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 "nvme_internal.h" 12 #include <openssl/evp.h> 13 14 #define NVME_AUTH_DATA_SIZE 4096 15 #define NVME_AUTH_CHAP_KEY_MAX_SIZE 256 16 17 #define AUTH_DEBUGLOG(q, fmt, ...) \ 18 SPDK_DEBUGLOG(nvme_auth, "[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, \ 19 (q)->ctrlr->opts.hostnqn, (q)->id, ## __VA_ARGS__) 20 #define AUTH_ERRLOG(q, fmt, ...) \ 21 SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->trid.subnqn, (q)->ctrlr->opts.hostnqn, \ 22 (q)->id, ## __VA_ARGS__) 23 24 static const char * 25 nvme_auth_get_digest_name(uint8_t id) 26 { 27 const char *names[] = { 28 [SPDK_NVMF_DHCHAP_HASH_SHA256] = "sha256", 29 [SPDK_NVMF_DHCHAP_HASH_SHA384] = "sha384", 30 [SPDK_NVMF_DHCHAP_HASH_SHA512] = "sha512", 31 }; 32 33 if (id >= SPDK_COUNTOF(names)) { 34 return NULL; 35 } 36 37 return names[id]; 38 } 39 40 static uint8_t 41 nvme_auth_get_digest_len(uint8_t id) 42 { 43 uint8_t hlen[] = { 44 [SPDK_NVMF_DHCHAP_HASH_SHA256] = 32, 45 [SPDK_NVMF_DHCHAP_HASH_SHA384] = 48, 46 [SPDK_NVMF_DHCHAP_HASH_SHA512] = 64, 47 }; 48 49 if (id >= SPDK_COUNTOF(hlen)) { 50 return 0; 51 } 52 53 return hlen[id]; 54 } 55 56 static void 57 nvme_auth_set_state(struct spdk_nvme_qpair *qpair, enum nvme_qpair_auth_state state) 58 { 59 static const char *state_names[] __attribute__((unused)) = { 60 [NVME_QPAIR_AUTH_STATE_NEGOTIATE] = "negotiate", 61 [NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE] = "await-negotiate", 62 [NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE] = "await-challenge", 63 [NVME_QPAIR_AUTH_STATE_AWAIT_REPLY] = "await-reply", 64 [NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1] = "await-success1", 65 [NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2] = "await-failure2", 66 [NVME_QPAIR_AUTH_STATE_DONE] = "done", 67 }; 68 69 AUTH_DEBUGLOG(qpair, "auth state: %s\n", state_names[state]); 70 qpair->auth.state = state; 71 } 72 73 static void 74 nvme_auth_set_failure(struct spdk_nvme_qpair *qpair, int status, bool failure2) 75 { 76 if (qpair->auth.status == 0) { 77 qpair->auth.status = status; 78 } 79 80 nvme_auth_set_state(qpair, failure2 ? 81 NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2 : 82 NVME_QPAIR_AUTH_STATE_DONE); 83 } 84 85 static void 86 nvme_auth_print_cpl(struct spdk_nvme_qpair *qpair, const char *msg) 87 { 88 struct nvme_completion_poll_status *status = qpair->poll_status; 89 90 AUTH_ERRLOG(qpair, "%s failed: sc=%d, sct=%d (timed out: %s)\n", msg, status->cpl.status.sc, 91 status->cpl.status.sct, status->timed_out ? "true" : "false"); 92 } 93 94 static int 95 nvme_auth_transform_key(struct spdk_key *key, int hash, const void *keyin, size_t keylen, 96 void *out, size_t outlen) 97 { 98 switch (hash) { 99 case SPDK_NVMF_DHCHAP_HASH_NONE: 100 if (keylen > outlen) { 101 SPDK_ERRLOG("Key buffer too small: %zu < %zu (key=%s)\n", outlen, keylen, 102 spdk_key_get_name(key)); 103 return -ENOBUFS; 104 } 105 memcpy(out, keyin, keylen); 106 return keylen; 107 case SPDK_NVMF_DHCHAP_HASH_SHA256: 108 case SPDK_NVMF_DHCHAP_HASH_SHA384: 109 case SPDK_NVMF_DHCHAP_HASH_SHA512: 110 SPDK_ERRLOG("Key transformation is not supported\n"); 111 return -EINVAL; 112 default: 113 SPDK_ERRLOG("Unsupported key hash: 0x%x (key=%s)\n", hash, spdk_key_get_name(key)); 114 return -EINVAL; 115 } 116 } 117 118 static int 119 nvme_auth_get_key(struct spdk_key *key, void *buf, size_t buflen) 120 { 121 char keystr[NVME_AUTH_CHAP_KEY_MAX_SIZE + 1] = {}; 122 char keyb64[NVME_AUTH_CHAP_KEY_MAX_SIZE] = {}; 123 char *tmp, *secret; 124 int rc, hash; 125 size_t keylen; 126 127 rc = spdk_key_get_key(key, keystr, NVME_AUTH_CHAP_KEY_MAX_SIZE); 128 if (rc < 0) { 129 SPDK_ERRLOG("Failed to load key=%s: %s\n", spdk_key_get_name(key), 130 spdk_strerror(-rc)); 131 goto out; 132 } 133 134 rc = sscanf(keystr, "DHHC-1:%02x:", &hash); 135 if (rc != 1) { 136 SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key)); 137 rc = -EINVAL; 138 goto out; 139 140 } 141 /* Start at the first character after second ":" and remove the trailing ":" */ 142 secret = &keystr[10]; 143 tmp = strstr(secret, ":"); 144 if (!tmp) { 145 SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key)); 146 rc = -EINVAL; 147 goto out; 148 } 149 150 *tmp = '\0'; 151 keylen = sizeof(keyb64); 152 rc = spdk_base64_decode(keyb64, &keylen, secret); 153 if (rc != 0) { 154 SPDK_ERRLOG("Invalid key format (key=%s)\n", spdk_key_get_name(key)); 155 rc = -EINVAL; 156 goto out; 157 } 158 /* Only 32B, 48B, and 64B keys are supported (+ 4B, as they're followed by a crc32) */ 159 if (keylen != 36 && keylen != 52 && keylen != 68) { 160 SPDK_ERRLOG("Invalid key size=%zu (key=%s)\n", keylen, spdk_key_get_name(key)); 161 rc = -EINVAL; 162 goto out; 163 } 164 165 keylen -= 4; 166 if (~spdk_crc32_ieee_update(keyb64, keylen, ~0) != from_le32(&keyb64[keylen])) { 167 SPDK_ERRLOG("Invalid key checksum (key=%s)\n", spdk_key_get_name(key)); 168 rc = -EINVAL; 169 goto out; 170 } 171 172 rc = nvme_auth_transform_key(key, hash, keyb64, keylen, buf, buflen); 173 out: 174 spdk_memset_s(keystr, sizeof(keystr), 0, sizeof(keystr)); 175 spdk_memset_s(keyb64, sizeof(keyb64), 0, sizeof(keyb64)); 176 177 return rc; 178 } 179 180 static int 181 nvme_auth_calc_response(struct spdk_key *key, enum spdk_nvmf_dhchap_hash hash, 182 const char *type, uint32_t seq, uint16_t tid, uint8_t scc, 183 const char *nqn1, const char *nqn2, const void *dhkey, size_t dhlen, 184 const void *cval, void *rval) 185 { 186 EVP_MAC *hmac; 187 EVP_MAC_CTX *ctx; 188 OSSL_PARAM params[2]; 189 uint8_t keybuf[NVME_AUTH_CHAP_KEY_MAX_SIZE], term = 0; 190 size_t hlen; 191 int rc, keylen; 192 193 assert(dhkey == NULL && dhlen == 0); 194 hmac = EVP_MAC_fetch(NULL, "hmac", NULL); 195 if (hmac == NULL) { 196 return -EIO; 197 } 198 199 ctx = EVP_MAC_CTX_new(hmac); 200 if (ctx == NULL) { 201 rc = -EIO; 202 goto out; 203 } 204 205 keylen = nvme_auth_get_key(key, keybuf, sizeof(keybuf)); 206 if (keylen < 0) { 207 rc = keylen; 208 goto out; 209 } 210 211 hlen = nvme_auth_get_digest_len(hash); 212 params[0] = OSSL_PARAM_construct_utf8_string("digest", 213 (char *)nvme_auth_get_digest_name(hash), 0); 214 params[1] = OSSL_PARAM_construct_end(); 215 216 rc = -EIO; 217 if (EVP_MAC_init(ctx, keybuf, (size_t)keylen, params) != 1) { 218 goto out; 219 } 220 if (EVP_MAC_update(ctx, cval, hlen) != 1) { 221 goto out; 222 } 223 if (EVP_MAC_update(ctx, (void *)&seq, sizeof(seq)) != 1) { 224 goto out; 225 } 226 if (EVP_MAC_update(ctx, (void *)&tid, sizeof(tid)) != 1) { 227 goto out; 228 } 229 if (EVP_MAC_update(ctx, (void *)&scc, sizeof(scc)) != 1) { 230 goto out; 231 } 232 if (EVP_MAC_update(ctx, (void *)type, strlen(type)) != 1) { 233 goto out; 234 } 235 if (EVP_MAC_update(ctx, (void *)nqn1, strlen(nqn1)) != 1) { 236 goto out; 237 } 238 if (EVP_MAC_update(ctx, (void *)&term, sizeof(term)) != 1) { 239 goto out; 240 } 241 if (EVP_MAC_update(ctx, (void *)nqn2, strlen(nqn2)) != 1) { 242 goto out; 243 } 244 if (EVP_MAC_final(ctx, rval, &hlen, hlen) != 1) { 245 goto out; 246 } 247 rc = 0; 248 out: 249 spdk_memset_s(keybuf, sizeof(keybuf), 0, sizeof(keybuf)); 250 EVP_MAC_CTX_free(ctx); 251 EVP_MAC_free(hmac); 252 253 return rc; 254 } 255 256 static int 257 nvme_auth_submit_request(struct spdk_nvme_qpair *qpair, 258 enum spdk_nvmf_fabric_cmd_types type, uint32_t len) 259 { 260 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 261 struct nvme_request *req = qpair->reserved_req; 262 struct nvme_completion_poll_status *status = qpair->poll_status; 263 struct spdk_nvmf_fabric_auth_recv_cmd rcmd = {}; 264 struct spdk_nvmf_fabric_auth_send_cmd scmd = {}; 265 266 assert(len <= NVME_AUTH_DATA_SIZE); 267 memset(&status->cpl, 0, sizeof(status->cpl)); 268 status->timeout_tsc = ctrlr->opts.admin_timeout_ms * spdk_get_ticks_hz() / 1000 + 269 spdk_get_ticks(); 270 status->done = false; 271 NVME_INIT_REQUEST(req, nvme_completion_poll_cb, status, 272 NVME_PAYLOAD_CONTIG(status->dma_data, NULL), len, 0); 273 switch (type) { 274 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND: 275 scmd.opcode = SPDK_NVME_OPC_FABRIC; 276 scmd.fctype = type; 277 scmd.spsp0 = 1; 278 scmd.spsp1 = 1; 279 scmd.secp = SPDK_NVMF_AUTH_SECP_NVME; 280 scmd.tl = len; 281 memcpy(&req->cmd, &scmd, sizeof(scmd)); 282 break; 283 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV: 284 rcmd.opcode = SPDK_NVME_OPC_FABRIC; 285 rcmd.fctype = type; 286 rcmd.spsp0 = 1; 287 rcmd.spsp1 = 1; 288 rcmd.secp = SPDK_NVMF_AUTH_SECP_NVME; 289 rcmd.al = len; 290 memcpy(&req->cmd, &rcmd, sizeof(rcmd)); 291 break; 292 default: 293 assert(0 && "invalid command"); 294 return -EINVAL; 295 } 296 297 return nvme_qpair_submit_request(qpair, req); 298 } 299 300 static int 301 nvme_auth_recv_message(struct spdk_nvme_qpair *qpair) 302 { 303 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 304 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV, 305 NVME_AUTH_DATA_SIZE); 306 } 307 308 static bool 309 nvme_auth_send_failure2(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_failure_reason reason) 310 { 311 struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data; 312 struct nvme_auth *auth = &qpair->auth; 313 314 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 315 msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 316 msg->auth_id = SPDK_NVMF_AUTH_ID_FAILURE2; 317 msg->t_id = auth->tid; 318 msg->rc = SPDK_NVMF_AUTH_FAILURE; 319 msg->rce = reason; 320 321 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 322 sizeof(*msg)) == 0; 323 } 324 325 static int 326 nvme_auth_check_message(struct spdk_nvme_qpair *qpair, enum spdk_nvmf_auth_id auth_id) 327 { 328 struct spdk_nvmf_auth_failure *msg = qpair->poll_status->dma_data; 329 const char *reason = NULL; 330 const char *reasons[] = { 331 [SPDK_NVMF_AUTH_FAILED] = "authentication failed", 332 [SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE] = "protocol not usable", 333 [SPDK_NVMF_AUTH_SCC_MISMATCH] = "secure channel concatenation mismatch", 334 [SPDK_NVMF_AUTH_HASH_UNUSABLE] = "hash not usable", 335 [SPDK_NVMF_AUTH_DHGROUP_UNUSABLE] = "dhgroup not usable", 336 [SPDK_NVMF_AUTH_INCORRECT_PAYLOAD] = "incorrect payload", 337 [SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE] = "incorrect protocol message", 338 }; 339 340 switch (msg->auth_type) { 341 case SPDK_NVMF_AUTH_TYPE_DHCHAP: 342 if (msg->auth_id == auth_id) { 343 return 0; 344 } 345 AUTH_ERRLOG(qpair, "received unexpected DH-HMAC-CHAP message id: %u (expected: %u)\n", 346 msg->auth_id, auth_id); 347 break; 348 case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE: 349 /* The only common message that we can expect to receive is AUTH_failure1 */ 350 if (msg->auth_id != SPDK_NVMF_AUTH_ID_FAILURE1) { 351 AUTH_ERRLOG(qpair, "received unexpected common message id: %u\n", 352 msg->auth_id); 353 break; 354 } 355 if (msg->rc == SPDK_NVMF_AUTH_FAILURE && msg->rce < SPDK_COUNTOF(reasons)) { 356 reason = reasons[msg->rce]; 357 } 358 AUTH_ERRLOG(qpair, "received AUTH_failure1: rc=%d, rce=%d (%s)\n", 359 msg->rc, msg->rce, reason); 360 nvme_auth_set_failure(qpair, -EACCES, false); 361 return -EACCES; 362 default: 363 AUTH_ERRLOG(qpair, "received unknown message type: %u\n", msg->auth_type); 364 break; 365 } 366 367 nvme_auth_set_failure(qpair, -EACCES, 368 nvme_auth_send_failure2(qpair, 369 SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE)); 370 return -EACCES; 371 } 372 373 static int 374 nvme_auth_send_negotiate(struct spdk_nvme_qpair *qpair) 375 { 376 struct nvme_auth *auth = &qpair->auth; 377 struct spdk_nvmf_auth_negotiate *msg = qpair->poll_status->dma_data; 378 struct spdk_nvmf_auth_descriptor *desc = msg->descriptors; 379 uint8_t hashids[] = { 380 SPDK_NVMF_DHCHAP_HASH_SHA256, 381 SPDK_NVMF_DHCHAP_HASH_SHA384, 382 SPDK_NVMF_DHCHAP_HASH_SHA512, 383 }; 384 uint8_t dhgids[] = { 385 SPDK_NVMF_DHCHAP_DHGROUP_NULL, 386 }; 387 388 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 389 desc->auth_id = SPDK_NVMF_AUTH_TYPE_DHCHAP; 390 desc->halen = SPDK_COUNTOF(hashids); 391 desc->dhlen = SPDK_COUNTOF(dhgids); 392 393 assert(desc->halen <= sizeof(desc->hash_id_list)); 394 assert(desc->dhlen <= sizeof(desc->dhg_id_list)); 395 memcpy(desc->hash_id_list, hashids, desc->halen); 396 memcpy(desc->dhg_id_list, dhgids, desc->dhlen); 397 398 msg->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 399 msg->auth_id = SPDK_NVMF_AUTH_ID_NEGOTIATE; 400 msg->t_id = auth->tid; 401 msg->sc_c = SPDK_NVMF_AUTH_SCC_DISABLED; 402 msg->napd = 1; 403 404 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 405 sizeof(*msg) + msg->napd * sizeof(*desc)); 406 } 407 408 static int 409 nvme_auth_check_challenge(struct spdk_nvme_qpair *qpair) 410 { 411 struct spdk_nvmf_dhchap_challenge *challenge = qpair->poll_status->dma_data; 412 struct nvme_auth *auth = &qpair->auth; 413 uint8_t hl; 414 int rc; 415 416 rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE); 417 if (rc != 0) { 418 return rc; 419 } 420 421 if (challenge->t_id != auth->tid) { 422 AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n", 423 challenge->t_id, auth->tid); 424 goto error; 425 } 426 427 if (challenge->seqnum == 0) { 428 AUTH_ERRLOG(qpair, "received challenge with seqnum=0\n"); 429 goto error; 430 } 431 432 hl = nvme_auth_get_digest_len(challenge->hash_id); 433 if (hl == 0) { 434 AUTH_ERRLOG(qpair, "unsupported hash function: 0x%x\n", challenge->hash_id); 435 goto error; 436 } 437 438 if (challenge->hl != hl) { 439 AUTH_ERRLOG(qpair, "unexpected hash length: received=%u, expected=%u\n", 440 challenge->hl, hl); 441 goto error; 442 } 443 444 if (challenge->dhg_id != SPDK_NVMF_DHCHAP_DHGROUP_NULL) { 445 AUTH_ERRLOG(qpair, "unsupported dhgroup: 0x%x\n", challenge->dhg_id); 446 goto error; 447 } 448 449 return 0; 450 error: 451 nvme_auth_set_failure(qpair, -EACCES, 452 nvme_auth_send_failure2(qpair, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD)); 453 return -EACCES; 454 } 455 456 static int 457 nvme_auth_send_reply(struct spdk_nvme_qpair *qpair) 458 { 459 struct nvme_completion_poll_status *status = qpair->poll_status; 460 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 461 struct spdk_nvmf_dhchap_challenge *challenge = status->dma_data; 462 struct spdk_nvmf_dhchap_reply *reply = status->dma_data; 463 struct nvme_auth *auth = &qpair->auth; 464 uint8_t hl, response[NVME_AUTH_DATA_SIZE]; 465 int rc; 466 467 hl = nvme_auth_get_digest_len(challenge->hash_id); 468 AUTH_DEBUGLOG(qpair, "key=%s, hash=%u, dhgroup=%u, seq=%u, tid=%u, subnqn=%s, hostnqn=%s, " 469 "len=%u\n", spdk_key_get_name(ctrlr->opts.dhchap_key), 470 challenge->hash_id, challenge->dhg_id, challenge->seqnum, auth->tid, 471 ctrlr->trid.subnqn, ctrlr->opts.hostnqn, hl); 472 rc = nvme_auth_calc_response(ctrlr->opts.dhchap_key, 473 (enum spdk_nvmf_dhchap_hash)challenge->hash_id, 474 "HostHost", challenge->seqnum, auth->tid, 0, 475 ctrlr->opts.hostnqn, ctrlr->trid.subnqn, NULL, 0, 476 challenge->cval, response); 477 if (rc != 0) { 478 AUTH_ERRLOG(qpair, "failed to calculate response: %s\n", spdk_strerror(-rc)); 479 return rc; 480 } 481 482 /* Now that the response has been calculated, send the reply */ 483 memset(qpair->poll_status->dma_data, 0, NVME_AUTH_DATA_SIZE); 484 memcpy(reply->rval, response, hl); 485 486 reply->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 487 reply->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_REPLY; 488 reply->t_id = auth->tid; 489 reply->hl = hl; 490 reply->cvalid = 0; 491 reply->dhvlen = 0; 492 reply->seqnum = 0; 493 494 /* The 2 * reply->hl below is because the spec says that both rval[hl] and cval[hl] must 495 * always be part of the reply message, even cvalid is zero. 496 */ 497 return nvme_auth_submit_request(qpair, SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND, 498 sizeof(*reply) + 2 * reply->hl); 499 } 500 501 static int 502 nvme_auth_check_success1(struct spdk_nvme_qpair *qpair) 503 { 504 struct spdk_nvmf_dhchap_success1 *msg = qpair->poll_status->dma_data; 505 struct nvme_auth *auth = &qpair->auth; 506 int rc; 507 508 rc = nvme_auth_check_message(qpair, SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1); 509 if (rc != 0) { 510 return rc; 511 } 512 513 if (msg->t_id != auth->tid) { 514 AUTH_ERRLOG(qpair, "unexpected tid: received=%u, expected=%u\n", 515 msg->t_id, auth->tid); 516 goto error; 517 } 518 519 return 0; 520 error: 521 nvme_auth_set_failure(qpair, -EACCES, 522 nvme_auth_send_failure2(qpair, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD)); 523 return -EACCES; 524 } 525 526 int 527 nvme_fabric_qpair_authenticate_poll(struct spdk_nvme_qpair *qpair) 528 { 529 struct nvme_auth *auth = &qpair->auth; 530 struct nvme_completion_poll_status *status = qpair->poll_status; 531 enum nvme_qpair_auth_state prev_state; 532 int rc; 533 534 do { 535 prev_state = auth->state; 536 537 switch (auth->state) { 538 case NVME_QPAIR_AUTH_STATE_NEGOTIATE: 539 rc = nvme_auth_send_negotiate(qpair); 540 if (rc != 0) { 541 nvme_auth_set_failure(qpair, rc, false); 542 AUTH_ERRLOG(qpair, "failed to send AUTH_negotiate: %s\n", 543 spdk_strerror(-rc)); 544 break; 545 } 546 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE); 547 break; 548 case NVME_QPAIR_AUTH_STATE_AWAIT_NEGOTIATE: 549 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 550 if (rc != 0) { 551 if (rc != -EAGAIN) { 552 nvme_auth_print_cpl(qpair, "AUTH_negotiate"); 553 nvme_auth_set_failure(qpair, rc, false); 554 } 555 break; 556 } 557 /* Negotiate has been sent, try to receive the challenge */ 558 rc = nvme_auth_recv_message(qpair); 559 if (rc != 0) { 560 nvme_auth_set_failure(qpair, rc, false); 561 AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_challenge: %s\n", 562 spdk_strerror(-rc)); 563 break; 564 } 565 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE); 566 break; 567 case NVME_QPAIR_AUTH_STATE_AWAIT_CHALLENGE: 568 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 569 if (rc != 0) { 570 if (rc != -EAGAIN) { 571 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_challenge"); 572 nvme_auth_set_failure(qpair, rc, false); 573 } 574 break; 575 } 576 rc = nvme_auth_check_challenge(qpair); 577 if (rc != 0) { 578 break; 579 } 580 rc = nvme_auth_send_reply(qpair); 581 if (rc != 0) { 582 nvme_auth_set_failure(qpair, rc, false); 583 AUTH_ERRLOG(qpair, "failed to send DH-HMAC-CHAP_reply: %s\n", 584 spdk_strerror(-rc)); 585 break; 586 } 587 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_REPLY); 588 break; 589 case NVME_QPAIR_AUTH_STATE_AWAIT_REPLY: 590 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 591 if (rc != 0) { 592 if (rc != -EAGAIN) { 593 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_reply"); 594 nvme_auth_set_failure(qpair, rc, false); 595 } 596 break; 597 } 598 /* Reply has been sent, try to receive response */ 599 rc = nvme_auth_recv_message(qpair); 600 if (rc != 0) { 601 nvme_auth_set_failure(qpair, rc, false); 602 AUTH_ERRLOG(qpair, "failed to recv DH-HMAC-CHAP_success1: %s\n", 603 spdk_strerror(-rc)); 604 break; 605 } 606 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1); 607 break; 608 case NVME_QPAIR_AUTH_STATE_AWAIT_SUCCESS1: 609 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 610 if (rc != 0) { 611 if (rc != -EAGAIN) { 612 nvme_auth_print_cpl(qpair, "DH-HMAC-CHAP_success1"); 613 nvme_auth_set_failure(qpair, rc, false); 614 } 615 break; 616 } 617 rc = nvme_auth_check_success1(qpair); 618 if (rc != 0) { 619 break; 620 } 621 AUTH_DEBUGLOG(qpair, "authentication completed successfully\n"); 622 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE); 623 break; 624 case NVME_QPAIR_AUTH_STATE_AWAIT_FAILURE2: 625 rc = nvme_wait_for_completion_robust_lock_timeout_poll(qpair, status, NULL); 626 if (rc == -EAGAIN) { 627 break; 628 } 629 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_DONE); 630 break; 631 case NVME_QPAIR_AUTH_STATE_DONE: 632 if (qpair->poll_status != NULL && !status->timed_out) { 633 qpair->poll_status = NULL; 634 spdk_free(status->dma_data); 635 free(status); 636 } 637 return auth->status; 638 default: 639 assert(0 && "invalid state"); 640 return -EINVAL; 641 } 642 } while (auth->state != prev_state); 643 644 return -EAGAIN; 645 } 646 647 int 648 nvme_fabric_qpair_authenticate_async(struct spdk_nvme_qpair *qpair) 649 { 650 struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; 651 struct nvme_completion_poll_status *status; 652 struct nvme_auth *auth = &qpair->auth; 653 int rc; 654 655 if (ctrlr->opts.dhchap_key == NULL) { 656 AUTH_ERRLOG(qpair, "missing DH-HMAC-CHAP key\n"); 657 return -ENOKEY; 658 } 659 660 if (qpair->auth.flags & NVME_QPAIR_AUTH_FLAG_ASCR) { 661 AUTH_ERRLOG(qpair, "secure channel concatentation is not supported\n"); 662 return -EINVAL; 663 } 664 665 status = calloc(1, sizeof(*qpair->poll_status)); 666 if (!status) { 667 AUTH_ERRLOG(qpair, "failed to allocate poll status\n"); 668 return -ENOMEM; 669 } 670 671 status->dma_data = spdk_zmalloc(NVME_AUTH_DATA_SIZE, 0, NULL, SPDK_ENV_LCORE_ID_ANY, 672 SPDK_MALLOC_DMA); 673 if (!status->dma_data) { 674 AUTH_ERRLOG(qpair, "failed to allocate poll status\n"); 675 free(status); 676 return -ENOMEM; 677 } 678 679 assert(qpair->poll_status == NULL); 680 qpair->poll_status = status; 681 682 nvme_robust_mutex_lock(&ctrlr->ctrlr_lock); 683 auth->tid = ctrlr->auth_tid++; 684 nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock); 685 686 nvme_auth_set_state(qpair, NVME_QPAIR_AUTH_STATE_NEGOTIATE); 687 688 /* Do the initial poll to kick-start the state machine */ 689 rc = nvme_fabric_qpair_authenticate_poll(qpair); 690 return rc != -EAGAIN ? rc : 0; 691 } 692 SPDK_LOG_REGISTER_COMPONENT(nvme_auth) 693