1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2024 Intel Corporation. All rights reserved. 3 */ 4 5 #include "spdk/base64.h" 6 #include "spdk/crc32.h" 7 #include "spdk/endian.h" 8 #include "spdk/log.h" 9 #include "spdk/string.h" 10 #include "spdk/util.h" 11 #include "spdk_internal/nvme.h" 12 #include "nvme_internal.h" 13 14 #ifdef SPDK_CONFIG_HAVE_EVP_MAC 15 #include <openssl/dh.h> 16 #include <openssl/evp.h> 17 #include <openssl/param_build.h> 18 #include <openssl/rand.h> 19 #endif 20 21 struct nvme_auth_digest { 22 uint8_t id; 23 const char *name; 24 uint8_t len; 25 }; 26 27 struct nvme_auth_dhgroup { 28 uint8_t id; 29 const char *name; 30 }; 31 32 #define NVME_AUTH_DATA_SIZE 4096 33 #define NVME_AUTH_DH_KEY_MAX_SIZE 1024 34 #define NVME_AUTH_CHAP_KEY_MAX_SIZE 256 35 36 #define AUTH_DEBUGLOG(q, fmt, ...) \ 37 SPDK_DEBUGLOG(nvme_auth, "[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, \ 38 (q)->ctrlr->opts.hostnqn, (q)->id, ## __VA_ARGS__) 39 #define AUTH_ERRLOG(q, fmt, ...) \ 40 SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, (q)->ctrlr->opts.hostnqn, \ 41 (q)->id, ## __VA_ARGS__) 42 #define AUTH_LOGDUMP(msg, buf, len) \ 43 SPDK_LOGDUMP(nvme_auth, msg, buf, len) 44 45 static const struct nvme_auth_digest g_digests[] = { 46 { SPDK_NVMF_DHCHAP_HASH_SHA256, "sha256", 32 }, 47 { SPDK_NVMF_DHCHAP_HASH_SHA384, "sha384", 48 }, 48 { SPDK_NVMF_DHCHAP_HASH_SHA512, "sha512", 64 }, 49 }; 50 51 static const struct nvme_auth_dhgroup g_dhgroups[] = { 52 { SPDK_NVMF_DHCHAP_DHGROUP_NULL, "null" }, 53 { SPDK_NVMF_DHCHAP_DHGROUP_2048, "ffdhe2048" }, 54 { SPDK_NVMF_DHCHAP_DHGROUP_3072, "ffdhe3072" }, 55 { SPDK_NVMF_DHCHAP_DHGROUP_4096, "ffdhe4096" }, 56 { SPDK_NVMF_DHCHAP_DHGROUP_6144, "ffdhe6144" }, 57 { SPDK_NVMF_DHCHAP_DHGROUP_8192, "ffdhe8192" }, 58 }; 59 60 static const struct nvme_auth_digest * 61 nvme_auth_get_digest(int id) 62 { 63 size_t i; 64 65 for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) { 66 if (g_digests[i].id == id) { 67 return &g_digests[i]; 68 } 69 } 70 71 return NULL; 72 } 73 74 int 75 spdk_nvme_dhchap_get_digest_id(const char *digest) 76 { 77 size_t i; 78 79 for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) { 80 if (strcmp(g_digests[i].name, digest) == 0) { 81 return g_digests[i].id; 82 } 83 } 84 85 return -EINVAL; 86 } 87 88 const char * 89 spdk_nvme_dhchap_get_digest_name(int id) 90 { 91 const struct nvme_auth_digest *digest = nvme_auth_get_digest(id); 92 93 return digest != NULL ? digest->name : NULL; 94 } 95 96 int 97 spdk_nvme_dhchap_get_dhgroup_id(const char *dhgroup) 98 { 99 size_t i; 100 101 for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) { 102 if (strcmp(g_dhgroups[i].name, dhgroup) == 0) { 103 return g_dhgroups[i].id; 104 } 105 } 106 107 return -EINVAL; 108 } 109 110 const char * 111 spdk_nvme_dhchap_get_dhgroup_name(int id) 112 { 113 size_t i; 114 115 for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) { 116 if (g_dhgroups[i].id == id) { 117 return g_dhgroups[i].name; 118 } 119 } 120 121 return NULL; 122 } 123 124 uint8_t 125 spdk_nvme_dhchap_get_digest_length(int id) 126 { 127 const struct nvme_auth_digest *digest = nvme_auth_get_digest(id); 128 129 return digest != NULL ? digest->len : 0; 130 } 131 132 #ifdef SPDK_CONFIG_HAVE_EVP_MAC 133 static bool 134 nvme_auth_digest_allowed(struct spdk_nvme_qpair *qpair, uint8_t digest) 135 { 136 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 137 138 return ctrlr->opts.dhchap_digests & SPDK_BIT(digest); 139 } 140 141 static bool 142 nvme_auth_dhgroup_allowed(struct spdk_nvme_qpair *qpair, uint8_t dhgroup) 143 { 144 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 145 146 return ctrlr->opts.dhchap_dhgroups & SPDK_BIT(dhgroup); 147 } 148 149 static void 150 nvme_auth_set_state(struct spdk_nvme_qpair *qpair, enum nvme_qpair_auth_state state) 151 { 152 static const char *state_names[] __attribute__((unused)) = { 153 [NVME_QPAIR_AUTH_STATE_NEGOTIATE] = "negotiate", 154 [NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE] = "await-negotiate", 155 [NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE] = "await-challenge", 156 [NVME_QPAIR_AUTH_STATE_AWAIT_REPLY] = "await-reply", 157 [NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1] = "await-success1", 158 [NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2] = "await-success2", 159 [NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2] = "await-failure2", 160 [NVME_QPAIR_AUTH_STATE_DONE] = "done", 161 }; 162 163 AUTH_DEBUGLOG(qpair, "auth state: %s\n", state_names[state]); 164 qpair->auth.state = state; 165 } 166 167 static void 168 nvme_auth_set_failure(struct spdk_nvme_qpair *qpair, int status, bool failure2) 169 { 170 if (qpair->auth.status == 0) { 171 qpair->auth.status = status; 172 } 173 174 nvme_auth_set_state(qpair, failure2 ? 175 NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2 : 176 NVME_QPAIR_AUTH_STATE_DONE); 177 } 178 179 static void 180 nvme_auth_print_cpl(struct spdk_nvme_qpair *qpair, const char *msg) 181 { 182 struct nvme_completion_poll_status *status = qpair->poll_status; 183 184 AUTH_ERRLOG(qpair, "%s failed: sc=%d, sct=%d (timed out: %s)\n", msg, status->cpl.status.sc, 185 status->cpl.status.sct, status->timed_out ? "true" : "false"); 186 } 187 188 static uint32_t 189 nvme_auth_get_seqnum(struct spdk_nvme_qpair *qpair) 190 { 191 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 192 uint32_t seqnum; 193 int rc; 194 195 nvme_ctrlr_lock(ctrlr); 196 if (ctrlr->auth_seqnum == 0) { 197 rc = RAND_bytes((void *)&ctrlr->auth_seqnum, sizeof(ctrlr->auth_seqnum)); 198 if (rc != 1) { 199 nvme_ctrlr_unlock(ctrlr); 200 return 0; 201 } 202 } 203 if (++ctrlr->auth_seqnum == 0) { 204 ctrlr->auth_seqnum = 1; 205 } 206 seqnum = ctrlr->auth_seqnum; 207 nvme_ctrlr_unlock(ctrlr); 208 209 return seqnum; 210 } 211 212 static int 213 nvme_auth_transform_key(struct spdk_key *key, int hash, const char *nqn, 214 const void *keyin, size_t keylen, void *out, size_t outlen) 215 { 216 EVP_MAC *hmac = NULL; 217 EVP_MAC_CTX *ctx = NULL; 218 OSSL_PARAM params[2]; 219 int rc; 220 221 switch (hash) { 222 case SPDK_NVMF_DHCHAP_HASH_NONE: 223 if (keylen > outlen) { 224 SPDK_ERRLOG("Key buffer too small: %zu < %zu (key=%s)\n", outlen, keylen, 225 spdk_key_get_name(key)); 226 return -ENOBUFS; 227 } 228 memcpy(out, keyin, keylen); 229 return keylen; 230 case SPDK_NVMF_DHCHAP_HASH_SHA256: 231 case SPDK_NVMF_DHCHAP_HASH_SHA384: 232 case SPDK_NVMF_DHCHAP_HASH_SHA512: 233 break; 234 default: 235 SPDK_ERRLOG("Unsupported key hash: 0x%x (key=%s)\n", hash, spdk_key_get_name(key)); 236 return -EINVAL; 237 } 238 239 hmac = EVP_MAC_fetch(NULL, "hmac", NULL); 240 if (hmac == NULL) { 241 return -EIO; 242 } 243 ctx = EVP_MAC_CTX_new(hmac); 244 if (ctx == NULL) { 245 rc = -EIO; 246 goto out; 247 } 248 params[0] = OSSL_PARAM_construct_utf8_string("digest", 249 (char *)spdk_nvme_dhchap_get_digest_name(hash), 0); 250 params[1] = OSSL_PARAM_construct_end(); 251 252 if (EVP_MAC_init(ctx, keyin, keylen, params) != 1) { 253 rc = -EIO; 254 goto out; 255 } 256 if (EVP_MAC_update(ctx, nqn, strlen(nqn)) != 1) { 257 rc = -EIO; 258 goto out; 259 } 260 if (EVP_MAC_update(ctx, "NVMe-over-Fabrics", strlen("NVMe-over-Fabrics")) != 1) { 261 rc = -EIO; 262 goto out; 263 } 264 if (EVP_MAC_final(ctx, out, &outlen, outlen) != 1) { 265 rc = -EIO; 266 goto out; 267 } 268 rc = (int)outlen; 269 out: 270 EVP_MAC_CTX_free(ctx); 271 EVP_MAC_free(hmac); 272 273 return rc; 274 } 275 276 static int 277 nvme_auth_get_key(struct spdk_key *key, const char *nqn, void *buf, size_t buflen) 278 { 279 char keystr[NVME_AUTH_CHAP_KEY_MAX_SIZE + 1] = {}; 280 char keyb64[NVME_AUTH_CHAP_KEY_MAX_SIZE] = {}; 281 char *tmp, *secret; 282 int rc, hash; 283 size_t keylen; 284 285 rc = spdk_key_get_key(key, keystr, NVME_AUTH_CHAP_KEY_MAX_SIZE); 286 if (rc < 0) { 287 SPDK_ERRLOG("Failed to load key=%s: %s\n", spdk_key_get_name(key), 288 spdk_strerror(-rc)); 289 goto out; 290 } 291 292 rc = sscanf(keystr, "DHHC-1:%02x:", &hash); 293 if (rc != 1) { 294 SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key)); 295 rc = -EINVAL; 296 goto out; 297 298 } 299 /* Start at the first character after second ":" and remove the trailing ":" */ 300 secret = &keystr[10]; 301 tmp = strstr(secret, ":"); 302 if (!tmp) { 303 SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key)); 304 rc = -EINVAL; 305 goto out; 306 } 307 308 *tmp = '\0'; 309 keylen = sizeof(keyb64); 310 rc = spdk_base64_decode(keyb64, &keylen, secret); 311 if (rc != 0) { 312 SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key)); 313 rc = -EINVAL; 314 goto out; 315 } 316 /* Only 32B, 48B, and 64B keys are supported (+ 4B, as they're followed by a crc32) */ 317 if (keylen != 36 && keylen != 52 && keylen != 68) { 318 SPDK_ERRLOG("Invalid key size=%zu (key=%s)\n", keylen, spdk_key_get_name(key)); 319 rc = -EINVAL; 320 goto out; 321 } 322 323 keylen -= 4; 324 if (~spdk_crc32_ieee_update(keyb64, keylen, ~0) != from_le32(&keyb64[keylen])) { 325 SPDK_ERRLOG("Invalid key checksum (key=%s)\n", spdk_key_get_name(key)); 326 rc = -EINVAL; 327 goto out; 328 } 329 330 rc = nvme_auth_transform_key(key, hash, nqn, keyb64, keylen, buf, buflen); 331 out: 332 spdk_memset_s(keystr, sizeof(keystr), 0, sizeof(keystr)); 333 spdk_memset_s(keyb64, sizeof(keyb64), 0, sizeof(keyb64)); 334 335 return rc; 336 } 337 338 static int 339 nvme_auth_augment_challenge(const void *cval, size_t clen, const void *key, size_t keylen, 340 void *caval, size_t *calen, enum spdk_nvmf_dhchap_hash hash) 341 { 342 EVP_MAC *hmac = NULL; 343 EVP_MAC_CTX *ctx = NULL; 344 EVP_MD *md = NULL; 345 OSSL_PARAM params[2]; 346 uint8_t keydgst[NVME_AUTH_DIGEST_MAX_SIZE]; 347 unsigned int dgstlen = sizeof(keydgst); 348 int rc = 0; 349 350 /* If there's no key, there's nothing to augment, cval == caval */ 351 if (key == NULL) { 352 assert(clen <= *calen); 353 memcpy(caval, cval, clen); 354 *calen = clen; 355 return 0; 356 } 357 358 md = EVP_MD_fetch(NULL, spdk_nvme_dhchap_get_digest_name(hash), NULL); 359 if (!md) { 360 SPDK_ERRLOG("Failed to fetch digest function: %d\n", hash); 361 return -EINVAL; 362 } 363 if (EVP_Digest(key, keylen, keydgst, &dgstlen, md, NULL) != 1) { 364 rc = -EIO; 365 goto out; 366 } 367 368 hmac = EVP_MAC_fetch(NULL, "hmac", NULL); 369 if (hmac == NULL) { 370 rc = -EIO; 371 goto out; 372 } 373 ctx = EVP_MAC_CTX_new(hmac); 374 if (ctx == NULL) { 375 rc = -EIO; 376 goto out; 377 } 378 params[0] = OSSL_PARAM_construct_utf8_string("digest", 379 (char *)spdk_nvme_dhchap_get_digest_name(hash), 0); 380 params[1] = OSSL_PARAM_construct_end(); 381 382 if (EVP_MAC_init(ctx, keydgst, dgstlen, params) != 1) { 383 rc = -EIO; 384 goto out; 385 } 386 if (EVP_MAC_update(ctx, cval, clen) != 1) { 387 rc = -EIO; 388 goto out; 389 } 390 if (EVP_MAC_final(ctx, caval, calen, *calen) != 1) { 391 rc = -EIO; 392 goto out; 393 } 394 out: 395 EVP_MD_free(md); 396 EVP_MAC_CTX_free(ctx); 397 EVP_MAC_free(hmac); 398 399 return rc; 400 } 401 402 int 403 spdk_nvme_dhchap_calculate(struct spdk_key *key, enum spdk_nvmf_dhchap_hash hash, 404 const char *type, uint32_t seq, uint16_t tid, uint8_t scc, 405 const char *nqn1, const char *nqn2, const void *dhkey, size_t dhlen, 406 const void *cval, void *rval) 407 { 408 EVP_MAC *hmac; 409 EVP_MAC_CTX *ctx; 410 OSSL_PARAM params[2]; 411 uint8_t keybuf[NVME_AUTH_CHAP_KEY_MAX_SIZE], term = 0; 412 uint8_t caval[NVME_AUTH_DATA_SIZE]; 413 size_t hlen, calen = sizeof(caval); 414 int rc, keylen; 415 416 hlen = spdk_nvme_dhchap_get_digest_length(hash); 417 rc = nvme_auth_augment_challenge(cval, hlen, dhkey, dhlen, caval, &calen, hash); 418 if (rc != 0) { 419 return rc; 420 } 421 422 hmac = EVP_MAC_fetch(NULL, "hmac", NULL); 423 if (hmac == NULL) { 424 return -EIO; 425 } 426 427 ctx = EVP_MAC_CTX_new(hmac); 428 if (ctx == NULL) { 429 rc = -EIO; 430 goto out; 431 } 432 433 keylen = nvme_auth_get_key(key, nqn1, keybuf, sizeof(keybuf)); 434 if (keylen < 0) { 435 rc = keylen; 436 goto out; 437 } 438 439 params[0] = OSSL_PARAM_construct_utf8_string("digest", 440 (char *)spdk_nvme_dhchap_get_digest_name(hash), 0); 441 params[1] = OSSL_PARAM_construct_end(); 442 443 rc = -EIO; 444 if (EVP_MAC_init(ctx, keybuf, (size_t)keylen, params) != 1) { 445 goto out; 446 } 447 if (EVP_MAC_update(ctx, caval, calen) != 1) { 448 goto out; 449 } 450 if (EVP_MAC_update(ctx, (void *)&seq, sizeof(seq)) != 1) { 451 goto out; 452 } 453 if (EVP_MAC_update(ctx, (void *)&tid, sizeof(tid)) != 1) { 454 goto out; 455 } 456 if (EVP_MAC_update(ctx, (void *)&scc, sizeof(scc)) != 1) { 457 goto out; 458 } 459 if (EVP_MAC_update(ctx, (void *)type, strlen(type)) != 1) { 460 goto out; 461 } 462 if (EVP_MAC_update(ctx, (void *)nqn1, strlen(nqn1)) != 1) { 463 goto out; 464 } 465 if (EVP_MAC_update(ctx, (void *)&term, sizeof(term)) != 1) { 466 goto out; 467 } 468 if (EVP_MAC_update(ctx, (void *)nqn2, strlen(nqn2)) != 1) { 469 goto out; 470 } 471 if (EVP_MAC_final(ctx, rval, &hlen, hlen) != 1) { 472 goto out; 473 } 474 rc = 0; 475 out: 476 spdk_memset_s(keybuf, sizeof(keybuf), 0, sizeof(keybuf)); 477 EVP_MAC_CTX_free(ctx); 478 EVP_MAC_free(hmac); 479 480 return rc; 481 } 482 483 struct spdk_nvme_dhchap_dhkey * 484 spdk_nvme_dhchap_generate_dhkey(enum spdk_nvmf_dhchap_dhgroup dhgroup) 485 { 486 EVP_PKEY_CTX *ctx = NULL; 487 EVP_PKEY *key = NULL; 488 OSSL_PARAM params[2]; 489 490 ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL); 491 if (ctx == NULL) { 492 goto error; 493 } 494 if (EVP_PKEY_keygen_init(ctx) != 1) { 495 goto error; 496 } 497 498 params[0] = OSSL_PARAM_construct_utf8_string("group", 499 (char *)spdk_nvme_dhchap_get_dhgroup_name(dhgroup), 0); 500 params[1] = OSSL_PARAM_construct_end(); 501 if (EVP_PKEY_CTX_set_params(ctx, params) != 1) { 502 SPDK_ERRLOG("Failed to set dhkey's dhgroup: %s\n", 503 spdk_nvme_dhchap_get_dhgroup_name(dhgroup)); 504 goto error; 505 } 506 if (EVP_PKEY_generate(ctx, &key) != 1) { 507 goto error; 508 } 509 error: 510 EVP_PKEY_CTX_free(ctx); 511 return (void *)key; 512 } 513 514 void 515 spdk_nvme_dhchap_dhkey_free(struct spdk_nvme_dhchap_dhkey **key) 516 { 517 if (key == NULL) { 518 return; 519 } 520 521 EVP_PKEY_free(*(EVP_PKEY **)key); 522 *key = NULL; 523 } 524 525 int 526 spdk_nvme_dhchap_dhkey_get_pubkey(struct spdk_nvme_dhchap_dhkey *dhkey, void *pub, size_t *len) 527 { 528 EVP_PKEY *key = (EVP_PKEY *)dhkey; 529 BIGNUM *bn = NULL; 530 int rc; 531 const size_t num_bytes = (size_t)spdk_divide_round_up(EVP_PKEY_get_bits(key), 8); 532 533 if (num_bytes == 0) { 534 SPDK_ERRLOG("Failed to get key size\n"); 535 return -EIO; 536 } 537 538 if (num_bytes > *len) { 539 SPDK_ERRLOG("Insufficient key buffer size=%zu (needed=%zu)", 540 *len, num_bytes); 541 return -EINVAL; 542 } 543 *len = num_bytes; 544 545 if (EVP_PKEY_get_bn_param(key, "pub", &bn) != 1) { 546 rc = -EIO; 547 goto error; 548 } 549 550 rc = BN_bn2binpad(bn, pub, *len); 551 if (rc <= 0) { 552 rc = -EIO; 553 goto error; 554 } 555 rc = 0; 556 error: 557 BN_free(bn); 558 return rc; 559 } 560 561 static EVP_PKEY * 562 nvme_auth_get_peerkey(const void *peerkey, size_t len, const char *dhgroup) 563 { 564 EVP_PKEY_CTX *ctx = NULL; 565 EVP_PKEY *result = NULL, *key = NULL; 566 OSSL_PARAM_BLD *bld = NULL; 567 OSSL_PARAM *params = NULL; 568 BIGNUM *bn = NULL; 569 570 ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL); 571 if (ctx == NULL) { 572 goto error; 573 } 574 if (EVP_PKEY_fromdata_init(ctx) != 1) { 575 goto error; 576 } 577 578 bn = BN_bin2bn(peerkey, len, NULL); 579 if (bn == NULL) { 580 goto error; 581 } 582 583 bld = OSSL_PARAM_BLD_new(); 584 if (bld == NULL) { 585 goto error; 586 } 587 if (OSSL_PARAM_BLD_push_BN(bld, "pub", bn) != 1) { 588 goto error; 589 } 590 if (OSSL_PARAM_BLD_push_utf8_string(bld, "group", dhgroup, 0) != 1) { 591 goto error; 592 } 593 594 params = OSSL_PARAM_BLD_to_param(bld); 595 if (params == NULL) { 596 goto error; 597 } 598 if (EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) != 1) { 599 SPDK_ERRLOG("Failed to create dhkey peer key\n"); 600 goto error; 601 } 602 603 result = EVP_PKEY_dup(key); 604 error: 605 EVP_PKEY_free(key); 606 EVP_PKEY_CTX_free(ctx); 607 OSSL_PARAM_BLD_free(bld); 608 OSSL_PARAM_free(params); 609 BN_free(bn); 610 611 return result; 612 } 613 614 int 615 spdk_nvme_dhchap_dhkey_derive_secret(struct spdk_nvme_dhchap_dhkey *dhkey, 616 const void *peer, size_t peerlen, void *secret, size_t *seclen) 617 { 618 EVP_PKEY *key = (EVP_PKEY *)dhkey; 619 EVP_PKEY_CTX *ctx = NULL; 620 EVP_PKEY *peerkey = NULL; 621 char dhgroup[64] = {}; 622 int rc = 0; 623 624 if (EVP_PKEY_get_utf8_string_param(key, "group", dhgroup, 625 sizeof(dhgroup), NULL) != 1) { 626 return -EIO; 627 } 628 peerkey = nvme_auth_get_peerkey(peer, peerlen, dhgroup); 629 if (peerkey == NULL) { 630 return -EINVAL; 631 } 632 ctx = EVP_PKEY_CTX_new(key, NULL); 633 if (ctx == NULL) { 634 rc = -ENOMEM; 635 goto out; 636 } 637 if (EVP_PKEY_derive_init(ctx) != 1) { 638 rc = -EIO; 639 goto out; 640 } 641 if (EVP_PKEY_CTX_set_dh_pad(ctx, 1) <= 0) { 642 rc = -EIO; 643 goto out; 644 } 645 if (EVP_PKEY_derive_set_peer(ctx, peerkey) != 1) { 646 SPDK_ERRLOG("Failed to set dhsecret's peer key\n"); 647 rc = -EINVAL; 648 goto out; 649 } 650 if (EVP_PKEY_derive(ctx, secret, seclen) != 1) { 651 SPDK_ERRLOG("Failed to derive dhsecret\n"); 652 rc = -ENOBUFS; 653 goto out; 654 } 655 out: 656 EVP_PKEY_free(peerkey); 657 EVP_PKEY_CTX_free(ctx); 658 659 return rc; 660 } 661 662 static int 663 nvme_auth_submit_request(struct spdk_nvme_qpair *qpair, 664 enum spdk_nvmf_fabric_cmd_types type, uint32_t len) 665 { 666 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 667 struct nvme_request *req = qpair->reserved_req; 668 struct nvme_completion_poll_status *status = qpair->poll_status; 669 struct spdk_nvmf_fabric_auth_recv_cmd rcmd = {}; 670 struct spdk_nvmf_fabric_auth_send_cmd scmd = {}; 671 672 assert(len <= NVME_AUTH_DATA_SIZE); 673 memset(&status->cpl, 0, sizeof(status->cpl)); 674 status->timeout_tsc = ctrlr->opts.admin_timeout_ms * spdk_get_ticks_hz() / 1000 + 675 spdk_get_ticks(); 676 status->done = false; 677 NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, 678 NVME_PAYLOAD_CONTIG(status->dma_data, NULL), len, 0); 679 switch (type) { 680 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND: 681 scmd.opcode = SPDK_NVME_OPC_FABRIC; 682 scmd.fctype = type; 683 scmd.spsp0 = 1; 684 scmd.spsp1 = 1; 685 scmd.secp = SPDK_NVMF_AUTH_SECP_NVME; 686 scmd.tl = len; 687 memcpy(&req->cmd, &scmd, sizeof(scmd)); 688 break; 689 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV: 690 rcmd.opcode = SPDK_NVME_OPC_FABRIC; 691 rcmd.fctype = type; 692 rcmd.spsp0 = 1; 693 rcmd.spsp1 = 1; 694 rcmd.secp = SPDK_NVMF_AUTH_SECP_NVME; 695 rcmd.al = len; 696 memcpy(&req->cmd, &rcmd, sizeof(rcmd)); 697 break; 698 default: 699 assert(0 && "invalid command"); 700 return -EINVAL; 701 } 702 703 return nvme_qpair_submit_request(qpair, req); 704 } 705 706 static int 707 nvme_auth_recv_message(struct spdk_nvme_qpair *qpair) 708 { 709 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 710 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV, 711 NVME_AUTH_DATA_SIZE); 712 } 713 714 static bool 715 nvme_auth_send_failure2(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_failure_reason reason) 716 { 717 struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data; 718 struct nvme_auth *auth = &qpair->auth; 719 720 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 721 msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 722 msg->auth_id = SPDK_NVMF_AUTH_ID_FAILURE2; 723 msg->t_id = auth->tid; 724 msg->rc = SPDK_NVMF_AUTH_FAILURE; 725 msg->rce = reason; 726 727 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 728 sizeof(*msg)) == 0; 729 } 730 731 static int 732 nvme_auth_check_message(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_id auth_id) 733 { 734 struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data; 735 const char *reason = NULL; 736 const char *reasons[] = { 737 [SPDK_NVMF_AUTH_FAILED] = "authentication failed", 738 [SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE] = "protocol not usable", 739 [SPDK_NVMF_AUTH_SCC_MISMATCH] = "secure channel concatenation mismatch", 740 [SPDK_NVMF_AUTH_HASH_UNUSABLE] = "hash not usable", 741 [SPDK_NVMF_AUTH_DHGROUP_UNUSABLE] = "dhgroup not usable", 742 [SPDK_NVMF_AUTH_INCORRECT_PAYLOAD] = "incorrect payload", 743 [SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE] = "incorrect protocol message", 744 }; 745 746 switch (msg->auth_type) { 747 case SPDK_NVMF_AUTH_TYPE_DHCHAP: 748 if (msg->auth_id == auth_id) { 749 return 0; 750 } 751 AUTH_ERRLOG(qpair, "received unexpected DH-HMAC-CHAP message id: %u (expected: %u)\n", 752 msg->auth_id, auth_id); 753 break; 754 case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE: 755 /* The only common message that we can expect to receive is AUTH_failure1 */ 756 if (msg->auth_id != SPDK_NVMF_AUTH_ID_FAILURE1) { 757 AUTH_ERRLOG(qpair, "received unexpected common message id: %u\n", 758 msg->auth_id); 759 break; 760 } 761 if (msg->rc == SPDK_NVMF_AUTH_FAILURE && msg->rce < SPDK_COUNTOF(reasons)) { 762 reason = reasons[msg->rce]; 763 } 764 AUTH_ERRLOG(qpair, "received AUTH_failure1: rc=%d, rce=%d (%s)\n", 765 msg->rc, msg->rce, reason); 766 nvme_auth_set_failure(qpair, -EACCES, false); 767 return -EACCES; 768 default: 769 AUTH_ERRLOG(qpair, "received unknown message type: %u\n", msg->auth_type); 770 break; 771 } 772 773 nvme_auth_set_failure(qpair, -EACCES, 774 nvme_auth_send_failure2(qpair, 775 SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE)); 776 return -EACCES; 777 } 778 779 static int 780 nvme_auth_send_negotiate(struct spdk_nvme_qpair *qpair) 781 { 782 struct nvme_auth *auth = &qpair->auth; 783 struct spdk_nvmf_auth_negotiate *msg = qpair->poll_status->dma_data; 784 struct spdk_nvmf_auth_descriptor *desc = msg->descriptors; 785 size_t i; 786 787 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 788 desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP; 789 assert(SPDK_COUNTOF(g_digests) <= sizeof(desc->hash_id_list)); 790 assert(SPDK_COUNTOF(g_dhgroups) <= sizeof(desc->dhg_id_list)); 791 792 for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) { 793 if (!nvme_auth_digest_allowed(qpair, g_digests[i].id)) { 794 continue; 795 } 796 AUTH_DEBUGLOG(qpair, "digest: %u (%s)\n", g_digests[i].id, 797 spdk_nvme_dhchap_get_digest_name(g_digests[i].id)); 798 desc->hash_id_list[desc->halen++] = g_digests[i].id; 799 } 800 for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) { 801 if (!nvme_auth_dhgroup_allowed(qpair, g_dhgroups[i].id)) { 802 continue; 803 } 804 AUTH_DEBUGLOG(qpair, "dhgroup: %u (%s)\n", g_dhgroups[i].id, 805 spdk_nvme_dhchap_get_dhgroup_name(g_dhgroups[i].id)); 806 desc->dhg_id_list[desc->dhlen++] = g_dhgroups[i].id; 807 } 808 809 msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 810 msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE; 811 msg->t_id = auth->tid; 812 msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED; 813 msg->napd = 1; 814 815 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 816 sizeof(*msg) + msg->napd * sizeof(*desc)); 817 } 818 819 static int 820 nvme_auth_check_challenge(struct spdk_nvme_qpair *qpair) 821 { 822 struct spdk_nvmf_dhchap_challenge *challenge = qpair->poll_status->dma_data; 823 struct nvme_auth *auth = &qpair->auth; 824 uint8_t hl; 825 int rc; 826 827 rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE); 828 if (rc != 0) { 829 return rc; 830 } 831 832 if (challenge->t_id != auth->tid) { 833 AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n", 834 challenge->t_id, auth->tid); 835 goto error; 836 } 837 838 if (challenge->seqnum == 0) { 839 AUTH_ERRLOG(qpair, "received challenge with seqnum=0\n"); 840 goto error; 841 } 842 843 hl = spdk_nvme_dhchap_get_digest_length(challenge->hash_id); 844 if (hl == 0) { 845 AUTH_ERRLOG(qpair, "unsupported hash function: 0x%x\n", challenge->hash_id); 846 goto error; 847 } 848 849 if (challenge->hl != hl) { 850 AUTH_ERRLOG(qpair, "unexpected hash length: received=%u, expected=%u\n", 851 challenge->hl, hl); 852 goto error; 853 } 854 855 switch (challenge->dhg_id) { 856 case SPDK_NVMF_DHCHAP_DHGROUP_NULL: 857 if (challenge->dhvlen != 0) { 858 AUTH_ERRLOG(qpair, "unexpected dhvlen=%u for dhgroup 0\n", 859 challenge->dhvlen); 860 goto error; 861 } 862 break; 863 case SPDK_NVMF_DHCHAP_DHGROUP_2048: 864 case SPDK_NVMF_DHCHAP_DHGROUP_3072: 865 case SPDK_NVMF_DHCHAP_DHGROUP_4096: 866 case SPDK_NVMF_DHCHAP_DHGROUP_6144: 867 case SPDK_NVMF_DHCHAP_DHGROUP_8192: 868 if (sizeof(*challenge) + hl + challenge->dhvlen > NVME_AUTH_DATA_SIZE || 869 challenge->dhvlen == 0) { 870 AUTH_ERRLOG(qpair, "invalid dhvlen=%u for dhgroup %u\n", 871 challenge->dhvlen, challenge->dhg_id); 872 goto error; 873 } 874 break; 875 default: 876 AUTH_ERRLOG(qpair, "unsupported dhgroup: 0x%x\n", challenge->dhg_id); 877 goto error; 878 } 879 880 if (!nvme_auth_digest_allowed(qpair, challenge->hash_id)) { 881 AUTH_ERRLOG(qpair, "received disallowed digest: %u (%s)\n", challenge->hash_id, 882 spdk_nvme_dhchap_get_digest_name(challenge->hash_id)); 883 goto error; 884 } 885 886 if (!nvme_auth_dhgroup_allowed(qpair, challenge->dhg_id)) { 887 AUTH_ERRLOG(qpair, "received disallowed dhgroup: %u (%s)\n", challenge->dhg_id, 888 spdk_nvme_dhchap_get_dhgroup_name(challenge->dhg_id)); 889 goto error; 890 } 891 892 return 0; 893 error: 894 nvme_auth_set_failure(qpair, -EACCES, 895 nvme_auth_send_failure2(qpair, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD)); 896 return -EACCES; 897 } 898 899 static int 900 nvme_auth_send_reply(struct spdk_nvme_qpair *qpair) 901 { 902 struct nvme_completion_poll_status *status = qpair->poll_status; 903 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 904 struct spdk_nvmf_dhchap_challenge *challenge = status->dma_data; 905 struct spdk_nvmf_dhchap_reply *reply = status->dma_data; 906 struct nvme_auth *auth = &qpair->auth; 907 struct spdk_nvme_dhchap_dhkey *dhkey; 908 struct spdk_key *key = NULL, *ckey = NULL; 909 uint8_t hl, response[NVME_AUTH_DATA_SIZE]; 910 uint8_t pubkey[NVME_AUTH_DH_KEY_MAX_SIZE]; 911 uint8_t dhsec[NVME_AUTH_DH_KEY_MAX_SIZE]; 912 uint8_t ctrlr_challenge[NVME_AUTH_DIGEST_MAX_SIZE] = {}; 913 size_t dhseclen = 0, publen = 0; 914 uint32_t seqnum = 0; 915 int rc; 916 917 auth->hash = challenge->hash_id; 918 hl = spdk_nvme_dhchap_get_digest_length(challenge->hash_id); 919 if (challenge->dhg_id != SPDK_NVMF_DHCHAP_DHGROUP_NULL) { 920 dhseclen = sizeof(dhsec); 921 publen = sizeof(pubkey); 922 AUTH_LOGDUMP("ctrlr pubkey:", &challenge->cval[hl], challenge->dhvlen); 923 dhkey = spdk_nvme_dhchap_generate_dhkey( 924 (enum spdk_nvmf_dhchap_dhgroup)challenge->dhg_id); 925 if (dhkey == NULL) { 926 rc = -EINVAL; 927 goto out; 928 } 929 rc = spdk_nvme_dhchap_dhkey_get_pubkey(dhkey, pubkey, &publen); 930 if (rc != 0) { 931 spdk_nvme_dhchap_dhkey_free(&dhkey); 932 goto out; 933 } 934 AUTH_LOGDUMP("host pubkey:", pubkey, publen); 935 rc = spdk_nvme_dhchap_dhkey_derive_secret(dhkey, 936 &challenge->cval[hl], challenge->dhvlen, dhsec, &dhseclen); 937 spdk_nvme_dhchap_dhkey_free(&dhkey); 938 if (rc != 0) { 939 goto out; 940 } 941 942 AUTH_LOGDUMP("dh secret:", dhsec, dhseclen); 943 } 944 945 nvme_ctrlr_lock(ctrlr); 946 key = ctrlr->opts.dhchap_key ? spdk_key_dup(ctrlr->opts.dhchap_key) : NULL; 947 ckey = ctrlr->opts.dhchap_ctrlr_key ? spdk_key_dup(ctrlr->opts.dhchap_ctrlr_key) : NULL; 948 nvme_ctrlr_unlock(ctrlr); 949 950 AUTH_DEBUGLOG(qpair, "key=%s, hash=%u, dhgroup=%u, seq=%u, tid=%u, subnqn=%s, hostnqn=%s, " 951 "len=%u\n", spdk_key_get_name(key), challenge->hash_id, challenge->dhg_id, 952 challenge->seqnum, auth->tid, ctrlr->trid.subnqn, ctrlr->opts.hostnqn, hl); 953 rc = spdk_nvme_dhchap_calculate(key, (enum spdk_nvmf_dhchap_hash)challenge->hash_id, 954 "HostHost", challenge->seqnum, auth->tid, 0, 955 ctrlr->opts.hostnqn, ctrlr->trid.subnqn, 956 dhseclen > 0 ? dhsec : NULL, dhseclen, 957 challenge->cval, response); 958 if (rc != 0) { 959 AUTH_ERRLOG(qpair, "failed to calculate response: %s\n", spdk_strerror(-rc)); 960 goto out; 961 } 962 963 if (ckey != NULL) { 964 seqnum = nvme_auth_get_seqnum(qpair); 965 if (seqnum == 0) { 966 rc = -EIO; 967 goto out; 968 } 969 970 assert(sizeof(ctrlr_challenge) >= hl); 971 rc = RAND_bytes(ctrlr_challenge, hl); 972 if (rc != 1) { 973 rc = -EIO; 974 goto out; 975 } 976 977 rc = spdk_nvme_dhchap_calculate(ckey, 978 (enum spdk_nvmf_dhchap_hash)challenge->hash_id, 979 "Controller", seqnum, auth->tid, 0, 980 ctrlr->trid.subnqn, ctrlr->opts.hostnqn, 981 dhseclen > 0 ? dhsec : NULL, dhseclen, 982 ctrlr_challenge, auth->challenge); 983 if (rc != 0) { 984 AUTH_ERRLOG(qpair, "failed to calculate controller's response: %s\n", 985 spdk_strerror(-rc)); 986 goto out; 987 } 988 } 989 990 /* Now that the response has been calculated, send the reply */ 991 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 992 assert(sizeof(*reply) + 2 * hl + publen <= NVME_AUTH_DATA_SIZE); 993 memcpy(reply->rval, response, hl); 994 memcpy(&reply->rval[1 * hl], ctrlr_challenge, hl); 995 memcpy(&reply->rval[2 * hl], pubkey, publen); 996 997 reply->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 998 reply->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_REPLY; 999 reply->t_id = auth->tid; 1000 reply->hl = hl; 1001 reply->cvalid = ckey != NULL; 1002 reply->dhvlen = publen; 1003 reply->seqnum = seqnum; 1004 1005 /* The 2 * reply->hl below is because the spec says that both rval[hl] and cval[hl] must 1006 * always be part of the reply message, even cvalid is zero. 1007 */ 1008 rc = nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 1009 sizeof(*reply) + 2 * reply->hl + publen); 1010 out: 1011 spdk_keyring_put_key(key); 1012 spdk_keyring_put_key(ckey); 1013 1014 return rc; 1015 } 1016 1017 static int 1018 nvme_auth_check_success1(struct spdk_nvme_qpair *qpair) 1019 { 1020 struct spdk_nvmf_dhchap_success1 *msg = qpair->poll_status->dma_data; 1021 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1022 struct nvme_auth *auth = &qpair->auth; 1023 uint8_t hl; 1024 int rc, status; 1025 1026 rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1); 1027 if (rc != 0) { 1028 return rc; 1029 } 1030 1031 if (msg->t_id != auth->tid) { 1032 AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n", 1033 msg->t_id, auth->tid); 1034 status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 1035 goto error; 1036 } 1037 1038 if (ctrlr->opts.dhchap_ctrlr_key != NULL) { 1039 if (!msg->rvalid) { 1040 AUTH_ERRLOG(qpair, "received rvalid=0, expected response\n"); 1041 status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 1042 goto error; 1043 } 1044 1045 hl = spdk_nvme_dhchap_get_digest_length(auth->hash); 1046 if (msg->hl != hl) { 1047 AUTH_ERRLOG(qpair, "received invalid hl=%u, expected=%u\n", msg->hl, hl); 1048 status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 1049 goto error; 1050 } 1051 1052 if (memcmp(msg->rval, auth->challenge, hl) != 0) { 1053 AUTH_ERRLOG(qpair, "controller challenge mismatch\n"); 1054 AUTH_LOGDUMP("received:", msg->rval, hl); 1055 AUTH_LOGDUMP("expected:", auth->challenge, hl); 1056 status = SPDK_NVMF_AUTH_FAILED; 1057 goto error; 1058 } 1059 } 1060 1061 return 0; 1062 error: 1063 nvme_auth_set_failure(qpair, -EACCES, nvme_auth_send_failure2(qpair, status)); 1064 1065 return -EACCES; 1066 } 1067 1068 static int 1069 nvme_auth_send_success2(struct spdk_nvme_qpair *qpair) 1070 { 1071 struct spdk_nvmf_dhchap_success2 *msg = qpair->poll_status->dma_data; 1072 struct nvme_auth *auth = &qpair->auth; 1073 1074 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 1075 msg->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 1076 msg->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS2; 1077 msg->t_id = auth->tid; 1078 1079 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 1080 sizeof(*msg)); 1081 } 1082 1083 int 1084 nvme_fabric_qpair_authenticate_poll(struct spdk_nvme_qpair *qpair) 1085 { 1086 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1087 struct nvme_auth *auth = &qpair->auth; 1088 struct nvme_completion_poll_status *status = qpair->poll_status; 1089 enum nvme_qpair_auth_state prev_state; 1090 int rc; 1091 1092 do { 1093 prev_state = auth->state; 1094 1095 switch (auth->state) { 1096 case NVME_QPAIR_AUTH_STATE_NEGOTIATE: 1097 rc = nvme_auth_send_negotiate(qpair); 1098 if (rc != 0) { 1099 nvme_auth_set_failure(qpair, rc, false); 1100 AUTH_ERRLOG(qpair, "failed to send AUTH_negotiate: %s\n", 1101 spdk_strerror(-rc)); 1102 break; 1103 } 1104 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE); 1105 break; 1106 case NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE: 1107 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1108 if (rc != 0) { 1109 if (rc != -EAGAIN) { 1110 nvme_auth_print_cpl(qpair, "AUTH_negotiate"); 1111 nvme_auth_set_failure(qpair, rc, false); 1112 } 1113 break; 1114 } 1115 /* Negotiate has been sent, try to receive the challenge */ 1116 rc = nvme_auth_recv_message(qpair); 1117 if (rc != 0) { 1118 nvme_auth_set_failure(qpair, rc, false); 1119 AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_challenge: %s\n", 1120 spdk_strerror(-rc)); 1121 break; 1122 } 1123 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE); 1124 break; 1125 case NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE: 1126 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1127 if (rc != 0) { 1128 if (rc != -EAGAIN) { 1129 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_challenge"); 1130 nvme_auth_set_failure(qpair, rc, false); 1131 } 1132 break; 1133 } 1134 rc = nvme_auth_check_challenge(qpair); 1135 if (rc != 0) { 1136 break; 1137 } 1138 rc = nvme_auth_send_reply(qpair); 1139 if (rc != 0) { 1140 nvme_auth_set_failure(qpair, rc, false); 1141 AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_reply: %s\n", 1142 spdk_strerror(-rc)); 1143 break; 1144 } 1145 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_REPLY); 1146 break; 1147 case NVME_QPAIR_AUTH_STATE_AWAIT_REPLY: 1148 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1149 if (rc != 0) { 1150 if (rc != -EAGAIN) { 1151 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_reply"); 1152 nvme_auth_set_failure(qpair, rc, false); 1153 } 1154 break; 1155 } 1156 /* Reply has been sent, try to receive response */ 1157 rc = nvme_auth_recv_message(qpair); 1158 if (rc != 0) { 1159 nvme_auth_set_failure(qpair, rc, false); 1160 AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_success1: %s\n", 1161 spdk_strerror(-rc)); 1162 break; 1163 } 1164 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1); 1165 break; 1166 case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1: 1167 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1168 if (rc != 0) { 1169 if (rc != -EAGAIN) { 1170 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_success1"); 1171 nvme_auth_set_failure(qpair, rc, false); 1172 } 1173 break; 1174 } 1175 rc = nvme_auth_check_success1(qpair); 1176 if (rc != 0) { 1177 break; 1178 } 1179 AUTH_DEBUGLOG(qpair, "authentication completed successfully\n"); 1180 if (ctrlr->opts.dhchap_ctrlr_key != NULL) { 1181 rc = nvme_auth_send_success2(qpair); 1182 if (rc != 0) { 1183 AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_success2: " 1184 "%s\n", spdk_strerror(rc)); 1185 nvme_auth_set_failure(qpair, rc, false); 1186 break; 1187 } 1188 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2); 1189 break; 1190 } 1191 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE); 1192 break; 1193 case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2: 1194 case NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2: 1195 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1196 if (rc == -EAGAIN) { 1197 break; 1198 } 1199 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE); 1200 break; 1201 case NVME_QPAIR_AUTH_STATE_DONE: 1202 if (qpair->poll_status != NULL && !status->timed_out) { 1203 qpair->poll_status = NULL; 1204 spdk_free(status->dma_data); 1205 free(status); 1206 } 1207 if (auth->cb_fn != NULL) { 1208 auth->cb_fn(auth->cb_ctx, auth->status); 1209 auth->cb_fn = NULL; 1210 } 1211 return auth->status; 1212 default: 1213 assert(0 && "invalid state"); 1214 return -EINVAL; 1215 } 1216 } while (auth->state != prev_state); 1217 1218 return -EAGAIN; 1219 } 1220 1221 int 1222 nvme_fabric_qpair_authenticate_async(struct spdk_nvme_qpair *qpair) 1223 { 1224 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1225 struct nvme_completion_poll_status *status; 1226 struct nvme_auth *auth = &qpair->auth; 1227 int rc; 1228 1229 if (ctrlr->opts.dhchap_key == NULL) { 1230 AUTH_ERRLOG(qpair, "missing DH-HMAC-CHAP key\n"); 1231 return -ENOKEY; 1232 } 1233 1234 if (qpair->auth.flags & NVME_QPAIR_AUTH_FLAG_ASCR) { 1235 AUTH_ERRLOG(qpair, "secure channel concatenation is not supported\n"); 1236 return -EINVAL; 1237 } 1238 1239 status = calloc(1, sizeof(*qpair->poll_status)); 1240 if (!status) { 1241 AUTH_ERRLOG(qpair, "failed to allocate poll status\n"); 1242 return -ENOMEM; 1243 } 1244 1245 status->dma_data = spdk_zmalloc(NVME_AUTH_DATA_SIZE, 0, NULL, SPDK_ENV_LCORE_ID_ANY, 1246 SPDK_MALLOC_DMA); 1247 if (!status->dma_data) { 1248 AUTH_ERRLOG(qpair, "failed to allocate poll status\n"); 1249 free(status); 1250 return -ENOMEM; 1251 } 1252 1253 assert(qpair->poll_status == NULL); 1254 qpair->poll_status = status; 1255 1256 nvme_ctrlr_lock(ctrlr); 1257 auth->tid = ctrlr->auth_tid++; 1258 nvme_ctrlr_unlock(ctrlr); 1259 1260 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_NEGOTIATE); 1261 1262 /* Do the initial poll to kick-start the state machine */ 1263 rc = nvme_fabric_qpair_authenticate_poll(qpair); 1264 return rc != -EAGAIN ? rc : 0; 1265 } 1266 1267 int 1268 spdk_nvme_qpair_authenticate(struct spdk_nvme_qpair *qpair, 1269 spdk_nvme_authenticate_cb cb_fn, void *cb_ctx) 1270 { 1271 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1272 int rc; 1273 1274 if (qpair->auth.cb_fn != NULL) { 1275 SPDK_ERRLOG("authentication already in-progress\n"); 1276 return -EALREADY; 1277 } 1278 1279 if (ctrlr->opts.dhchap_key == NULL) { 1280 SPDK_ERRLOG("missing DH-HMAC-CHAP key\n"); 1281 return -ENOKEY; 1282 } 1283 1284 rc = nvme_transport_qpair_authenticate(qpair); 1285 if (rc == 0) { 1286 qpair->auth.cb_fn = cb_fn; 1287 qpair->auth.cb_ctx = cb_ctx; 1288 } 1289 1290 return rc; 1291 } 1292 #endif /* SPDK_CONFIG_EVP_MAC */ 1293 1294 SPDK_LOG_REGISTER_COMPONENT(nvme_auth) 1295