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_robust_mutex_lock(&ctrlr->ctrlr_lock); 196 if (ctrlr->auth_seqnum == 0) { 197 rc = RAND_bytes((void *)&ctrlr->auth_seqnum, sizeof(ctrlr->auth_seqnum)); 198 if (rc != 1) { 199 nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock); 200 return 0; 201 } 202 } 203 if (++ctrlr->auth_seqnum == 0) { 204 ctrlr->auth_seqnum = 1; 205 } 206 seqnum = ctrlr->auth_seqnum; 207 nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock); 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 532 if (EVP_PKEY_get_bn_param(key, "pub", &bn) != 1) { 533 rc = -EIO; 534 goto error; 535 } 536 if ((size_t)BN_num_bytes(bn) > *len) { 537 SPDK_ERRLOG("Insufficient key buffer size=%zu (needed=%d)", 538 *len, BN_num_bytes(bn)); 539 rc = -EINVAL; 540 goto error; 541 } 542 rc = BN_bn2bin(bn, pub); 543 if (rc <= 0) { 544 rc = -EIO; 545 goto error; 546 } 547 548 *len = (size_t)BN_num_bytes(bn); 549 rc = 0; 550 error: 551 BN_free(bn); 552 return rc; 553 } 554 555 static EVP_PKEY * 556 nvme_auth_get_peerkey(const void *peerkey, size_t len, const char *dhgroup) 557 { 558 EVP_PKEY_CTX *ctx = NULL; 559 EVP_PKEY *result = NULL, *key = NULL; 560 OSSL_PARAM_BLD *bld = NULL; 561 OSSL_PARAM *params = NULL; 562 BIGNUM *bn = NULL; 563 564 ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL); 565 if (ctx == NULL) { 566 goto error; 567 } 568 if (EVP_PKEY_fromdata_init(ctx) != 1) { 569 goto error; 570 } 571 572 bn = BN_bin2bn(peerkey, len, NULL); 573 if (bn == NULL) { 574 goto error; 575 } 576 577 bld = OSSL_PARAM_BLD_new(); 578 if (bld == NULL) { 579 goto error; 580 } 581 if (OSSL_PARAM_BLD_push_BN(bld, "pub", bn) != 1) { 582 goto error; 583 } 584 if (OSSL_PARAM_BLD_push_utf8_string(bld, "group", dhgroup, 0) != 1) { 585 goto error; 586 } 587 588 params = OSSL_PARAM_BLD_to_param(bld); 589 if (params == NULL) { 590 goto error; 591 } 592 if (EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) != 1) { 593 SPDK_ERRLOG("Failed to create dhkey peer key\n"); 594 goto error; 595 } 596 597 result = EVP_PKEY_dup(key); 598 error: 599 EVP_PKEY_free(key); 600 EVP_PKEY_CTX_free(ctx); 601 OSSL_PARAM_BLD_free(bld); 602 OSSL_PARAM_free(params); 603 BN_free(bn); 604 605 return result; 606 } 607 608 int 609 spdk_nvme_dhchap_dhkey_derive_secret(struct spdk_nvme_dhchap_dhkey *dhkey, 610 const void *peer, size_t peerlen, void *secret, size_t *seclen) 611 { 612 EVP_PKEY *key = (EVP_PKEY *)dhkey; 613 EVP_PKEY_CTX *ctx = NULL; 614 EVP_PKEY *peerkey = NULL; 615 char dhgroup[64] = {}; 616 int rc = 0; 617 618 if (EVP_PKEY_get_utf8_string_param(key, "group", dhgroup, 619 sizeof(dhgroup), NULL) != 1) { 620 return -EIO; 621 } 622 peerkey = nvme_auth_get_peerkey(peer, peerlen, dhgroup); 623 if (peerkey == NULL) { 624 return -EINVAL; 625 } 626 ctx = EVP_PKEY_CTX_new(key, NULL); 627 if (ctx == NULL) { 628 rc = -ENOMEM; 629 goto out; 630 } 631 if (EVP_PKEY_derive_init(ctx) != 1) { 632 rc = -EIO; 633 goto out; 634 } 635 if (EVP_PKEY_CTX_set_dh_pad(ctx, 1) <= 0) { 636 rc = -EIO; 637 goto out; 638 } 639 if (EVP_PKEY_derive_set_peer(ctx, peerkey) != 1) { 640 SPDK_ERRLOG("Failed to set dhsecret's peer key\n"); 641 rc = -EINVAL; 642 goto out; 643 } 644 if (EVP_PKEY_derive(ctx, secret, seclen) != 1) { 645 SPDK_ERRLOG("Failed to derive dhsecret\n"); 646 rc = -ENOBUFS; 647 goto out; 648 } 649 out: 650 EVP_PKEY_free(peerkey); 651 EVP_PKEY_CTX_free(ctx); 652 653 return rc; 654 } 655 656 static int 657 nvme_auth_submit_request(struct spdk_nvme_qpair *qpair, 658 enum spdk_nvmf_fabric_cmd_types type, uint32_t len) 659 { 660 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 661 struct nvme_request *req = qpair->reserved_req; 662 struct nvme_completion_poll_status *status = qpair->poll_status; 663 struct spdk_nvmf_fabric_auth_recv_cmd rcmd = {}; 664 struct spdk_nvmf_fabric_auth_send_cmd scmd = {}; 665 666 assert(len <= NVME_AUTH_DATA_SIZE); 667 memset(&status->cpl, 0, sizeof(status->cpl)); 668 status->timeout_tsc = ctrlr->opts.admin_timeout_ms * spdk_get_ticks_hz() / 1000 + 669 spdk_get_ticks(); 670 status->done = false; 671 NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, 672 NVME_PAYLOAD_CONTIG(status->dma_data, NULL), len, 0); 673 switch (type) { 674 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND: 675 scmd.opcode = SPDK_NVME_OPC_FABRIC; 676 scmd.fctype = type; 677 scmd.spsp0 = 1; 678 scmd.spsp1 = 1; 679 scmd.secp = SPDK_NVMF_AUTH_SECP_NVME; 680 scmd.tl = len; 681 memcpy(&req->cmd, &scmd, sizeof(scmd)); 682 break; 683 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV: 684 rcmd.opcode = SPDK_NVME_OPC_FABRIC; 685 rcmd.fctype = type; 686 rcmd.spsp0 = 1; 687 rcmd.spsp1 = 1; 688 rcmd.secp = SPDK_NVMF_AUTH_SECP_NVME; 689 rcmd.al = len; 690 memcpy(&req->cmd, &rcmd, sizeof(rcmd)); 691 break; 692 default: 693 assert(0 && "invalid command"); 694 return -EINVAL; 695 } 696 697 return nvme_qpair_submit_request(qpair, req); 698 } 699 700 static int 701 nvme_auth_recv_message(struct spdk_nvme_qpair *qpair) 702 { 703 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 704 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV, 705 NVME_AUTH_DATA_SIZE); 706 } 707 708 static bool 709 nvme_auth_send_failure2(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_failure_reason reason) 710 { 711 struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data; 712 struct nvme_auth *auth = &qpair->auth; 713 714 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 715 msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 716 msg->auth_id = SPDK_NVMF_AUTH_ID_FAILURE2; 717 msg->t_id = auth->tid; 718 msg->rc = SPDK_NVMF_AUTH_FAILURE; 719 msg->rce = reason; 720 721 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 722 sizeof(*msg)) == 0; 723 } 724 725 static int 726 nvme_auth_check_message(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_id auth_id) 727 { 728 struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data; 729 const char *reason = NULL; 730 const char *reasons[] = { 731 [SPDK_NVMF_AUTH_FAILED] = "authentication failed", 732 [SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE] = "protocol not usable", 733 [SPDK_NVMF_AUTH_SCC_MISMATCH] = "secure channel concatenation mismatch", 734 [SPDK_NVMF_AUTH_HASH_UNUSABLE] = "hash not usable", 735 [SPDK_NVMF_AUTH_DHGROUP_UNUSABLE] = "dhgroup not usable", 736 [SPDK_NVMF_AUTH_INCORRECT_PAYLOAD] = "incorrect payload", 737 [SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE] = "incorrect protocol message", 738 }; 739 740 switch (msg->auth_type) { 741 case SPDK_NVMF_AUTH_TYPE_DHCHAP: 742 if (msg->auth_id == auth_id) { 743 return 0; 744 } 745 AUTH_ERRLOG(qpair, "received unexpected DH-HMAC-CHAP message id: %u (expected: %u)\n", 746 msg->auth_id, auth_id); 747 break; 748 case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE: 749 /* The only common message that we can expect to receive is AUTH_failure1 */ 750 if (msg->auth_id != SPDK_NVMF_AUTH_ID_FAILURE1) { 751 AUTH_ERRLOG(qpair, "received unexpected common message id: %u\n", 752 msg->auth_id); 753 break; 754 } 755 if (msg->rc == SPDK_NVMF_AUTH_FAILURE && msg->rce < SPDK_COUNTOF(reasons)) { 756 reason = reasons[msg->rce]; 757 } 758 AUTH_ERRLOG(qpair, "received AUTH_failure1: rc=%d, rce=%d (%s)\n", 759 msg->rc, msg->rce, reason); 760 nvme_auth_set_failure(qpair, -EACCES, false); 761 return -EACCES; 762 default: 763 AUTH_ERRLOG(qpair, "received unknown message type: %u\n", msg->auth_type); 764 break; 765 } 766 767 nvme_auth_set_failure(qpair, -EACCES, 768 nvme_auth_send_failure2(qpair, 769 SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE)); 770 return -EACCES; 771 } 772 773 static int 774 nvme_auth_send_negotiate(struct spdk_nvme_qpair *qpair) 775 { 776 struct nvme_auth *auth = &qpair->auth; 777 struct spdk_nvmf_auth_negotiate *msg = qpair->poll_status->dma_data; 778 struct spdk_nvmf_auth_descriptor *desc = msg->descriptors; 779 size_t i; 780 781 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 782 desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP; 783 assert(SPDK_COUNTOF(g_digests) <= sizeof(desc->hash_id_list)); 784 assert(SPDK_COUNTOF(g_dhgroups) <= sizeof(desc->dhg_id_list)); 785 786 for (i = 0; i < SPDK_COUNTOF(g_digests); ++i) { 787 if (!nvme_auth_digest_allowed(qpair, g_digests[i].id)) { 788 continue; 789 } 790 AUTH_DEBUGLOG(qpair, "digest: %u (%s)\n", g_digests[i].id, 791 spdk_nvme_dhchap_get_digest_name(g_digests[i].id)); 792 desc->hash_id_list[desc->halen++] = g_digests[i].id; 793 } 794 for (i = 0; i < SPDK_COUNTOF(g_dhgroups); ++i) { 795 if (!nvme_auth_dhgroup_allowed(qpair, g_dhgroups[i].id)) { 796 continue; 797 } 798 AUTH_DEBUGLOG(qpair, "dhgroup: %u (%s)\n", g_dhgroups[i].id, 799 spdk_nvme_dhchap_get_dhgroup_name(g_dhgroups[i].id)); 800 desc->dhg_id_list[desc->dhlen++] = g_dhgroups[i].id; 801 } 802 803 msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 804 msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE; 805 msg->t_id = auth->tid; 806 msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED; 807 msg->napd = 1; 808 809 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 810 sizeof(*msg) + msg->napd * sizeof(*desc)); 811 } 812 813 static int 814 nvme_auth_check_challenge(struct spdk_nvme_qpair *qpair) 815 { 816 struct spdk_nvmf_dhchap_challenge *challenge = qpair->poll_status->dma_data; 817 struct nvme_auth *auth = &qpair->auth; 818 uint8_t hl; 819 int rc; 820 821 rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE); 822 if (rc != 0) { 823 return rc; 824 } 825 826 if (challenge->t_id != auth->tid) { 827 AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n", 828 challenge->t_id, auth->tid); 829 goto error; 830 } 831 832 if (challenge->seqnum == 0) { 833 AUTH_ERRLOG(qpair, "received challenge with seqnum=0\n"); 834 goto error; 835 } 836 837 hl = spdk_nvme_dhchap_get_digest_length(challenge->hash_id); 838 if (hl == 0) { 839 AUTH_ERRLOG(qpair, "unsupported hash function: 0x%x\n", challenge->hash_id); 840 goto error; 841 } 842 843 if (challenge->hl != hl) { 844 AUTH_ERRLOG(qpair, "unexpected hash length: received=%u, expected=%u\n", 845 challenge->hl, hl); 846 goto error; 847 } 848 849 switch (challenge->dhg_id) { 850 case SPDK_NVMF_DHCHAP_DHGROUP_NULL: 851 if (challenge->dhvlen != 0) { 852 AUTH_ERRLOG(qpair, "unexpected dhvlen=%u for dhgroup 0\n", 853 challenge->dhvlen); 854 goto error; 855 } 856 break; 857 case SPDK_NVMF_DHCHAP_DHGROUP_2048: 858 case SPDK_NVMF_DHCHAP_DHGROUP_3072: 859 case SPDK_NVMF_DHCHAP_DHGROUP_4096: 860 case SPDK_NVMF_DHCHAP_DHGROUP_6144: 861 case SPDK_NVMF_DHCHAP_DHGROUP_8192: 862 if (sizeof(*challenge) + hl + challenge->dhvlen > NVME_AUTH_DATA_SIZE || 863 challenge->dhvlen == 0) { 864 AUTH_ERRLOG(qpair, "invalid dhvlen=%u for dhgroup %u\n", 865 challenge->dhvlen, challenge->dhg_id); 866 goto error; 867 } 868 break; 869 default: 870 AUTH_ERRLOG(qpair, "unsupported dhgroup: 0x%x\n", challenge->dhg_id); 871 goto error; 872 } 873 874 if (!nvme_auth_digest_allowed(qpair, challenge->hash_id)) { 875 AUTH_ERRLOG(qpair, "received disallowed digest: %u (%s)\n", challenge->hash_id, 876 spdk_nvme_dhchap_get_digest_name(challenge->hash_id)); 877 goto error; 878 } 879 880 if (!nvme_auth_dhgroup_allowed(qpair, challenge->dhg_id)) { 881 AUTH_ERRLOG(qpair, "received disallowed dhgroup: %u (%s)\n", challenge->dhg_id, 882 spdk_nvme_dhchap_get_dhgroup_name(challenge->dhg_id)); 883 goto error; 884 } 885 886 return 0; 887 error: 888 nvme_auth_set_failure(qpair, -EACCES, 889 nvme_auth_send_failure2(qpair, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD)); 890 return -EACCES; 891 } 892 893 static int 894 nvme_auth_send_reply(struct spdk_nvme_qpair *qpair) 895 { 896 struct nvme_completion_poll_status *status = qpair->poll_status; 897 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 898 struct spdk_nvmf_dhchap_challenge *challenge = status->dma_data; 899 struct spdk_nvmf_dhchap_reply *reply = status->dma_data; 900 struct nvme_auth *auth = &qpair->auth; 901 struct spdk_nvme_dhchap_dhkey *dhkey; 902 uint8_t hl, response[NVME_AUTH_DATA_SIZE]; 903 uint8_t pubkey[NVME_AUTH_DH_KEY_MAX_SIZE]; 904 uint8_t dhsec[NVME_AUTH_DH_KEY_MAX_SIZE]; 905 uint8_t ctrlr_challenge[NVME_AUTH_DIGEST_MAX_SIZE] = {}; 906 size_t dhseclen = 0, publen = 0; 907 uint32_t seqnum = 0; 908 int rc; 909 910 auth->hash = challenge->hash_id; 911 hl = spdk_nvme_dhchap_get_digest_length(challenge->hash_id); 912 if (challenge->dhg_id != SPDK_NVMF_DHCHAP_DHGROUP_NULL) { 913 dhseclen = sizeof(dhsec); 914 publen = sizeof(pubkey); 915 AUTH_LOGDUMP("ctrlr pubkey:", &challenge->cval[hl], challenge->dhvlen); 916 dhkey = spdk_nvme_dhchap_generate_dhkey( 917 (enum spdk_nvmf_dhchap_dhgroup)challenge->dhg_id); 918 if (dhkey == NULL) { 919 return -EINVAL; 920 } 921 rc = spdk_nvme_dhchap_dhkey_get_pubkey(dhkey, pubkey, &publen); 922 if (rc != 0) { 923 spdk_nvme_dhchap_dhkey_free(&dhkey); 924 return rc; 925 } 926 AUTH_LOGDUMP("host pubkey:", pubkey, publen); 927 rc = spdk_nvme_dhchap_dhkey_derive_secret(dhkey, 928 &challenge->cval[hl], challenge->dhvlen, dhsec, &dhseclen); 929 spdk_nvme_dhchap_dhkey_free(&dhkey); 930 if (rc != 0) { 931 return rc; 932 } 933 934 AUTH_LOGDUMP("dh secret:", dhsec, dhseclen); 935 } 936 937 AUTH_DEBUGLOG(qpair, "key=%s, hash=%u, dhgroup=%u, seq=%u, tid=%u, subnqn=%s, hostnqn=%s, " 938 "len=%u\n", spdk_key_get_name(ctrlr->opts.dhchap_key), 939 challenge->hash_id, challenge->dhg_id, challenge->seqnum, auth->tid, 940 ctrlr->trid.subnqn, ctrlr->opts.hostnqn, hl); 941 rc = spdk_nvme_dhchap_calculate(ctrlr->opts.dhchap_key, 942 (enum spdk_nvmf_dhchap_hash)challenge->hash_id, 943 "HostHost", challenge->seqnum, auth->tid, 0, 944 ctrlr->opts.hostnqn, ctrlr->trid.subnqn, 945 dhseclen > 0 ? dhsec : NULL, dhseclen, 946 challenge->cval, response); 947 if (rc != 0) { 948 AUTH_ERRLOG(qpair, "failed to calculate response: %s\n", spdk_strerror(-rc)); 949 return rc; 950 } 951 952 if (ctrlr->opts.dhchap_ctrlr_key != NULL) { 953 seqnum = nvme_auth_get_seqnum(qpair); 954 if (seqnum == 0) { 955 return -EIO; 956 } 957 958 assert(sizeof(ctrlr_challenge) >= hl); 959 rc = RAND_bytes(ctrlr_challenge, hl); 960 if (rc != 1) { 961 return -EIO; 962 } 963 964 rc = spdk_nvme_dhchap_calculate(ctrlr->opts.dhchap_ctrlr_key, 965 (enum spdk_nvmf_dhchap_hash)challenge->hash_id, 966 "Controller", seqnum, auth->tid, 0, 967 ctrlr->trid.subnqn, ctrlr->opts.hostnqn, 968 dhseclen > 0 ? dhsec : NULL, dhseclen, 969 ctrlr_challenge, auth->challenge); 970 if (rc != 0) { 971 AUTH_ERRLOG(qpair, "failed to calculate controller's response: %s\n", 972 spdk_strerror(-rc)); 973 return rc; 974 } 975 } 976 977 /* Now that the response has been calculated, send the reply */ 978 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 979 assert(sizeof(*reply) + 2 * hl + publen <= NVME_AUTH_DATA_SIZE); 980 memcpy(reply->rval, response, hl); 981 memcpy(&reply->rval[1 * hl], ctrlr_challenge, hl); 982 memcpy(&reply->rval[2 * hl], pubkey, publen); 983 984 reply->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 985 reply->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_REPLY; 986 reply->t_id = auth->tid; 987 reply->hl = hl; 988 reply->cvalid = ctrlr->opts.dhchap_ctrlr_key != NULL; 989 reply->dhvlen = publen; 990 reply->seqnum = seqnum; 991 992 /* The 2 * reply->hl below is because the spec says that both rval[hl] and cval[hl] must 993 * always be part of the reply message, even cvalid is zero. 994 */ 995 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 996 sizeof(*reply) + 2 * reply->hl + publen); 997 } 998 999 static int 1000 nvme_auth_check_success1(struct spdk_nvme_qpair *qpair) 1001 { 1002 struct spdk_nvmf_dhchap_success1 *msg = qpair->poll_status->dma_data; 1003 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1004 struct nvme_auth *auth = &qpair->auth; 1005 uint8_t hl; 1006 int rc, status; 1007 1008 rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1); 1009 if (rc != 0) { 1010 return rc; 1011 } 1012 1013 if (msg->t_id != auth->tid) { 1014 AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n", 1015 msg->t_id, auth->tid); 1016 status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 1017 goto error; 1018 } 1019 1020 if (ctrlr->opts.dhchap_ctrlr_key != NULL) { 1021 if (!msg->rvalid) { 1022 AUTH_ERRLOG(qpair, "received rvalid=0, expected response\n"); 1023 status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 1024 goto error; 1025 } 1026 1027 hl = spdk_nvme_dhchap_get_digest_length(auth->hash); 1028 if (msg->hl != hl) { 1029 AUTH_ERRLOG(qpair, "received invalid hl=%u, expected=%u\n", msg->hl, hl); 1030 status = SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 1031 goto error; 1032 } 1033 1034 if (memcmp(msg->rval, auth->challenge, hl) != 0) { 1035 AUTH_ERRLOG(qpair, "controller challenge mismatch\n"); 1036 AUTH_LOGDUMP("received:", msg->rval, hl); 1037 AUTH_LOGDUMP("expected:", auth->challenge, hl); 1038 status = SPDK_NVMF_AUTH_FAILED; 1039 goto error; 1040 } 1041 } 1042 1043 return 0; 1044 error: 1045 nvme_auth_set_failure(qpair, -EACCES, nvme_auth_send_failure2(qpair, status)); 1046 1047 return -EACCES; 1048 } 1049 1050 static int 1051 nvme_auth_send_success2(struct spdk_nvme_qpair *qpair) 1052 { 1053 struct spdk_nvmf_dhchap_success2 *msg = qpair->poll_status->dma_data; 1054 struct nvme_auth *auth = &qpair->auth; 1055 1056 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 1057 msg->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 1058 msg->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS2; 1059 msg->t_id = auth->tid; 1060 1061 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 1062 sizeof(*msg)); 1063 } 1064 1065 int 1066 nvme_fabric_qpair_authenticate_poll(struct spdk_nvme_qpair *qpair) 1067 { 1068 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1069 struct nvme_auth *auth = &qpair->auth; 1070 struct nvme_completion_poll_status *status = qpair->poll_status; 1071 enum nvme_qpair_auth_state prev_state; 1072 int rc; 1073 1074 do { 1075 prev_state = auth->state; 1076 1077 switch (auth->state) { 1078 case NVME_QPAIR_AUTH_STATE_NEGOTIATE: 1079 rc = nvme_auth_send_negotiate(qpair); 1080 if (rc != 0) { 1081 nvme_auth_set_failure(qpair, rc, false); 1082 AUTH_ERRLOG(qpair, "failed to send AUTH_negotiate: %s\n", 1083 spdk_strerror(-rc)); 1084 break; 1085 } 1086 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE); 1087 break; 1088 case NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE: 1089 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1090 if (rc != 0) { 1091 if (rc != -EAGAIN) { 1092 nvme_auth_print_cpl(qpair, "AUTH_negotiate"); 1093 nvme_auth_set_failure(qpair, rc, false); 1094 } 1095 break; 1096 } 1097 /* Negotiate has been sent, try to receive the challenge */ 1098 rc = nvme_auth_recv_message(qpair); 1099 if (rc != 0) { 1100 nvme_auth_set_failure(qpair, rc, false); 1101 AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_challenge: %s\n", 1102 spdk_strerror(-rc)); 1103 break; 1104 } 1105 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE); 1106 break; 1107 case NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE: 1108 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1109 if (rc != 0) { 1110 if (rc != -EAGAIN) { 1111 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_challenge"); 1112 nvme_auth_set_failure(qpair, rc, false); 1113 } 1114 break; 1115 } 1116 rc = nvme_auth_check_challenge(qpair); 1117 if (rc != 0) { 1118 break; 1119 } 1120 rc = nvme_auth_send_reply(qpair); 1121 if (rc != 0) { 1122 nvme_auth_set_failure(qpair, rc, false); 1123 AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_reply: %s\n", 1124 spdk_strerror(-rc)); 1125 break; 1126 } 1127 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_REPLY); 1128 break; 1129 case NVME_QPAIR_AUTH_STATE_AWAIT_REPLY: 1130 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1131 if (rc != 0) { 1132 if (rc != -EAGAIN) { 1133 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_reply"); 1134 nvme_auth_set_failure(qpair, rc, false); 1135 } 1136 break; 1137 } 1138 /* Reply has been sent, try to receive response */ 1139 rc = nvme_auth_recv_message(qpair); 1140 if (rc != 0) { 1141 nvme_auth_set_failure(qpair, rc, false); 1142 AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_success1: %s\n", 1143 spdk_strerror(-rc)); 1144 break; 1145 } 1146 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1); 1147 break; 1148 case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1: 1149 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1150 if (rc != 0) { 1151 if (rc != -EAGAIN) { 1152 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_success1"); 1153 nvme_auth_set_failure(qpair, rc, false); 1154 } 1155 break; 1156 } 1157 rc = nvme_auth_check_success1(qpair); 1158 if (rc != 0) { 1159 break; 1160 } 1161 AUTH_DEBUGLOG(qpair, "authentication completed successfully\n"); 1162 if (ctrlr->opts.dhchap_ctrlr_key != NULL) { 1163 rc = nvme_auth_send_success2(qpair); 1164 if (rc != 0) { 1165 AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_success2: " 1166 "%s\n", spdk_strerror(rc)); 1167 nvme_auth_set_failure(qpair, rc, false); 1168 break; 1169 } 1170 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2); 1171 break; 1172 } 1173 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE); 1174 break; 1175 case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS2: 1176 case NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2: 1177 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 1178 if (rc == -EAGAIN) { 1179 break; 1180 } 1181 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE); 1182 break; 1183 case NVME_QPAIR_AUTH_STATE_DONE: 1184 if (qpair->poll_status != NULL && !status->timed_out) { 1185 qpair->poll_status = NULL; 1186 spdk_free(status->dma_data); 1187 free(status); 1188 } 1189 return auth->status; 1190 default: 1191 assert(0 && "invalid state"); 1192 return -EINVAL; 1193 } 1194 } while (auth->state != prev_state); 1195 1196 return -EAGAIN; 1197 } 1198 1199 int 1200 nvme_fabric_qpair_authenticate_async(struct spdk_nvme_qpair *qpair) 1201 { 1202 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 1203 struct nvme_completion_poll_status *status; 1204 struct nvme_auth *auth = &qpair->auth; 1205 int rc; 1206 1207 if (ctrlr->opts.dhchap_key == NULL) { 1208 AUTH_ERRLOG(qpair, "missing DH-HMAC-CHAP key\n"); 1209 return -ENOKEY; 1210 } 1211 1212 if (qpair->auth.flags & NVME_QPAIR_AUTH_FLAG_ASCR) { 1213 AUTH_ERRLOG(qpair, "secure channel concatentation is not supported\n"); 1214 return -EINVAL; 1215 } 1216 1217 status = calloc(1, sizeof(*qpair->poll_status)); 1218 if (!status) { 1219 AUTH_ERRLOG(qpair, "failed to allocate poll status\n"); 1220 return -ENOMEM; 1221 } 1222 1223 status->dma_data = spdk_zmalloc(NVME_AUTH_DATA_SIZE, 0, NULL, SPDK_ENV_LCORE_ID_ANY, 1224 SPDK_MALLOC_DMA); 1225 if (!status->dma_data) { 1226 AUTH_ERRLOG(qpair, "failed to allocate poll status\n"); 1227 free(status); 1228 return -ENOMEM; 1229 } 1230 1231 assert(qpair->poll_status == NULL); 1232 qpair->poll_status = status; 1233 1234 nvme_robust_mutex_lock(&ctrlr->ctrlr_lock); 1235 auth->tid = ctrlr->auth_tid++; 1236 nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock); 1237 1238 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_NEGOTIATE); 1239 1240 /* Do the initial poll to kick-start the state machine */ 1241 rc = nvme_fabric_qpair_authenticate_poll(qpair); 1242 return rc != -EAGAIN ? rc : 0; 1243 } 1244 #endif /* SPDK_CONFIG_EVP_MAC */ 1245 1246 SPDK_LOG_REGISTER_COMPONENT(nvme_auth) 1247