1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2024 Intel Corporation 3 */ 4 5 #include "spdk/nvme.h" 6 #include "spdk/json.h" 7 #include "spdk/log.h" 8 #include "spdk/stdinc.h" 9 #include "spdk/string.h" 10 #include "spdk/thread.h" 11 #include "spdk/util.h" 12 #include "spdk_internal/nvme.h" 13 14 #include <openssl/rand.h> 15 16 #include "nvmf_internal.h" 17 18 #define NVMF_AUTH_DEFAULT_KATO_US (120ull * 1000 * 1000) 19 #define NVMF_AUTH_DIGEST_MAX_SIZE 64 20 #define NVMF_AUTH_DH_KEY_MAX_SIZE 1024 21 22 #define AUTH_ERRLOG(q, fmt, ...) \ 23 SPDK_ERRLOG("[%s:%s:%u] " fmt, (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, \ 24 (q)->qid, ## __VA_ARGS__) 25 #define AUTH_DEBUGLOG(q, fmt, ...) \ 26 SPDK_DEBUGLOG(nvmf_auth, "[%s:%s:%u] " fmt, \ 27 (q)->ctrlr->subsys->subnqn, (q)->ctrlr->hostnqn, (q)->qid, ## __VA_ARGS__) 28 #define AUTH_LOGDUMP(msg, buf, len) \ 29 SPDK_LOGDUMP(nvmf_auth, msg, buf, len) 30 31 enum nvmf_qpair_auth_state { 32 NVMF_QPAIR_AUTH_NEGOTIATE, 33 NVMF_QPAIR_AUTH_CHALLENGE, 34 NVMF_QPAIR_AUTH_REPLY, 35 NVMF_QPAIR_AUTH_SUCCESS1, 36 NVMF_QPAIR_AUTH_FAILURE1, 37 NVMF_QPAIR_AUTH_COMPLETED, 38 NVMF_QPAIR_AUTH_ERROR, 39 }; 40 41 struct spdk_nvmf_qpair_auth { 42 enum nvmf_qpair_auth_state state; 43 struct spdk_poller *poller; 44 int fail_reason; 45 uint16_t tid; 46 int digest; 47 int dhgroup; 48 uint8_t cval[NVMF_AUTH_DIGEST_MAX_SIZE]; 49 uint32_t seqnum; 50 struct spdk_nvme_dhchap_dhkey *dhkey; 51 }; 52 53 struct nvmf_auth_common_header { 54 uint8_t auth_type; 55 uint8_t auth_id; 56 uint8_t reserved0[2]; 57 uint16_t t_id; 58 }; 59 60 static void 61 nvmf_auth_request_complete(struct spdk_nvmf_request *req, int sct, int sc, int dnr) 62 { 63 struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; 64 65 response->status.sct = sct; 66 response->status.sc = sc; 67 response->status.dnr = dnr; 68 69 spdk_nvmf_request_complete(req); 70 } 71 72 static const char * 73 nvmf_auth_get_state_name(enum nvmf_qpair_auth_state state) 74 { 75 static const char *state_names[] = { 76 [NVMF_QPAIR_AUTH_NEGOTIATE] = "negotiate", 77 [NVMF_QPAIR_AUTH_CHALLENGE] = "challenge", 78 [NVMF_QPAIR_AUTH_REPLY] = "reply", 79 [NVMF_QPAIR_AUTH_SUCCESS1] = "success1", 80 [NVMF_QPAIR_AUTH_FAILURE1] = "failure1", 81 [NVMF_QPAIR_AUTH_COMPLETED] = "completed", 82 [NVMF_QPAIR_AUTH_ERROR] = "error", 83 }; 84 85 return state_names[state]; 86 } 87 88 static void 89 nvmf_auth_set_state(struct spdk_nvmf_qpair *qpair, enum nvmf_qpair_auth_state state) 90 { 91 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 92 93 if (auth->state == state) { 94 return; 95 } 96 97 AUTH_DEBUGLOG(qpair, "auth state: %s\n", nvmf_auth_get_state_name(state)); 98 auth->state = state; 99 } 100 101 static void 102 nvmf_auth_disconnect_qpair(struct spdk_nvmf_qpair *qpair) 103 { 104 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_ERROR); 105 spdk_nvmf_qpair_disconnect(qpair); 106 } 107 108 static void 109 nvmf_auth_request_fail1(struct spdk_nvmf_request *req, int reason) 110 { 111 struct spdk_nvmf_qpair *qpair = req->qpair; 112 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 113 114 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1); 115 auth->fail_reason = reason; 116 117 /* The command itself is completed successfully, but a subsequent AUTHENTICATION_RECV 118 * command will be completed with an AUTH_failure1 message 119 */ 120 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0); 121 } 122 123 static int 124 nvmf_auth_timeout_poller(void *ctx) 125 { 126 struct spdk_nvmf_qpair *qpair = ctx; 127 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 128 129 AUTH_ERRLOG(qpair, "authentication timed out\n"); 130 131 spdk_poller_unregister(&auth->poller); 132 nvmf_auth_disconnect_qpair(qpair); 133 134 return SPDK_POLLER_BUSY; 135 } 136 137 static int 138 nvmf_auth_rearm_poller(struct spdk_nvmf_qpair *qpair) 139 { 140 struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr; 141 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 142 uint64_t timeout; 143 144 timeout = ctrlr->feat.keep_alive_timer.bits.kato > 0 ? 145 ctrlr->feat.keep_alive_timer.bits.kato * 1000 : 146 NVMF_AUTH_DEFAULT_KATO_US; 147 148 spdk_poller_unregister(&auth->poller); 149 auth->poller = SPDK_POLLER_REGISTER(nvmf_auth_timeout_poller, qpair, timeout); 150 if (auth->poller == NULL) { 151 return -ENOMEM; 152 } 153 154 return 0; 155 } 156 157 static void 158 nvmf_auth_qpair_cleanup(struct spdk_nvmf_qpair_auth *auth) 159 { 160 spdk_poller_unregister(&auth->poller); 161 spdk_nvme_dhchap_dhkey_free(&auth->dhkey); 162 } 163 164 static int 165 nvmf_auth_check_command(struct spdk_nvmf_request *req, uint8_t secp, 166 uint8_t spsp0, uint8_t spsp1, uint32_t len) 167 { 168 struct spdk_nvmf_qpair *qpair = req->qpair; 169 170 if (secp != SPDK_NVMF_AUTH_SECP_NVME) { 171 AUTH_ERRLOG(qpair, "invalid secp=%u\n", secp); 172 return -EINVAL; 173 } 174 if (spsp0 != 1 || spsp1 != 1) { 175 AUTH_ERRLOG(qpair, "invalid spsp0=%u, spsp1=%u\n", spsp0, spsp1); 176 return -EINVAL; 177 } 178 if (len != req->length) { 179 AUTH_ERRLOG(qpair, "invalid length: %"PRIu32" != %"PRIu32"\n", len, req->length); 180 return -EINVAL; 181 } 182 183 return 0; 184 } 185 186 static void * 187 nvmf_auth_get_message(struct spdk_nvmf_request *req, size_t size) 188 { 189 if (req->length > 0 && req->iovcnt == 1 && req->iov[0].iov_len >= size) { 190 return req->iov[0].iov_base; 191 } 192 193 return NULL; 194 } 195 196 static void 197 nvmf_auth_negotiate_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_auth_negotiate *msg) 198 { 199 struct spdk_nvmf_qpair *qpair = req->qpair; 200 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 201 struct spdk_nvmf_auth_descriptor *desc = NULL; 202 /* These arrays are sorted from the strongest hash/dhgroup to the weakest, so the strongest 203 * hash/dhgroup pair supported by the host is always selected 204 */ 205 enum spdk_nvmf_dhchap_hash digests[] = { 206 SPDK_NVMF_DHCHAP_HASH_SHA512, 207 SPDK_NVMF_DHCHAP_HASH_SHA384, 208 SPDK_NVMF_DHCHAP_HASH_SHA256 209 }; 210 enum spdk_nvmf_dhchap_dhgroup dhgroups[] = { 211 SPDK_NVMF_DHCHAP_DHGROUP_8192, 212 SPDK_NVMF_DHCHAP_DHGROUP_6144, 213 SPDK_NVMF_DHCHAP_DHGROUP_4096, 214 SPDK_NVMF_DHCHAP_DHGROUP_3072, 215 SPDK_NVMF_DHCHAP_DHGROUP_2048, 216 SPDK_NVMF_DHCHAP_DHGROUP_NULL, 217 }; 218 int digest = -1, dhgroup = -1; 219 size_t i, j; 220 221 if (auth->state != NVMF_QPAIR_AUTH_NEGOTIATE) { 222 AUTH_ERRLOG(qpair, "invalid state: %s\n", nvmf_auth_get_state_name(auth->state)); 223 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE); 224 return; 225 } 226 227 auth->tid = msg->t_id; 228 if (req->length < sizeof(*msg) || req->length != sizeof(*msg) + msg->napd * sizeof(*desc)) { 229 AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length); 230 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 231 return; 232 } 233 234 if (msg->sc_c != SPDK_NVMF_AUTH_SCC_DISABLED) { 235 AUTH_ERRLOG(qpair, "scc mismatch\n"); 236 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_SCC_MISMATCH); 237 return; 238 } 239 240 for (i = 0; i < msg->napd; ++i) { 241 if (msg->descriptors[i].auth_id == SPDK_NVMF_AUTH_TYPE_DHCHAP) { 242 desc = &msg->descriptors[i]; 243 break; 244 } 245 } 246 if (desc == NULL) { 247 AUTH_ERRLOG(qpair, "no usable protocol found\n"); 248 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_PROTOCOL_UNUSABLE); 249 return; 250 } 251 if (desc->halen > SPDK_COUNTOF(desc->hash_id_list) || 252 desc->dhlen > SPDK_COUNTOF(desc->dhg_id_list)) { 253 AUTH_ERRLOG(qpair, "invalid halen=%u, dhlen=%u\n", desc->halen, desc->dhlen); 254 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 255 return; 256 } 257 258 for (i = 0; i < SPDK_COUNTOF(digests); ++i) { 259 for (j = 0; j < desc->halen; ++j) { 260 if (digests[i] == desc->hash_id_list[j]) { 261 AUTH_DEBUGLOG(qpair, "selected digest: %s\n", 262 spdk_nvme_dhchap_get_digest_name(digests[i])); 263 digest = digests[i]; 264 break; 265 } 266 } 267 if (digest >= 0) { 268 break; 269 } 270 } 271 if (digest < 0) { 272 AUTH_ERRLOG(qpair, "no usable digests found\n"); 273 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_HASH_UNUSABLE); 274 return; 275 } 276 277 for (i = 0; i < SPDK_COUNTOF(dhgroups); ++i) { 278 for (j = 0; j < desc->dhlen; ++j) { 279 if (dhgroups[i] == desc->dhg_id_list[j]) { 280 AUTH_DEBUGLOG(qpair, "selected dhgroup: %s\n", 281 spdk_nvme_dhchap_get_dhgroup_name(dhgroups[i])); 282 dhgroup = dhgroups[i]; 283 break; 284 } 285 } 286 if (dhgroup >= 0) { 287 break; 288 } 289 } 290 if (dhgroup < 0) { 291 AUTH_ERRLOG(qpair, "no usable dhgroups found\n"); 292 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_DHGROUP_UNUSABLE); 293 return; 294 } 295 296 if (nvmf_auth_rearm_poller(qpair)) { 297 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 298 SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1); 299 nvmf_auth_disconnect_qpair(qpair); 300 return; 301 } 302 303 auth->digest = digest; 304 auth->dhgroup = dhgroup; 305 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_CHALLENGE); 306 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0); 307 } 308 309 static void 310 nvmf_auth_reply_exec(struct spdk_nvmf_request *req, struct spdk_nvmf_dhchap_reply *msg) 311 { 312 struct spdk_nvmf_qpair *qpair = req->qpair; 313 struct spdk_nvmf_ctrlr *ctrlr = qpair->ctrlr; 314 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 315 uint8_t response[NVMF_AUTH_DIGEST_MAX_SIZE]; 316 uint8_t dhsec[NVMF_AUTH_DH_KEY_MAX_SIZE]; 317 struct spdk_key *key = NULL; 318 size_t dhseclen = 0; 319 uint8_t hl; 320 int rc; 321 322 if (auth->state != NVMF_QPAIR_AUTH_REPLY) { 323 AUTH_ERRLOG(qpair, "invalid state=%s\n", nvmf_auth_get_state_name(auth->state)); 324 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE); 325 goto out; 326 } 327 if (req->length < sizeof(*msg)) { 328 AUTH_ERRLOG(qpair, "invalid message length=%"PRIu32"\n", req->length); 329 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 330 goto out; 331 } 332 333 hl = spdk_nvme_dhchap_get_digest_length(auth->digest); 334 if (hl == 0 || msg->hl != hl) { 335 AUTH_ERRLOG(qpair, "hash length mismatch: %u != %u\n", msg->hl, hl); 336 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 337 goto out; 338 } 339 if (req->length != sizeof(*msg) + 2 * hl + msg->dhvlen) { 340 AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32" != %zu\n", 341 req->length, sizeof(*msg) + 2 * hl); 342 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 343 goto out; 344 } 345 if (msg->t_id != auth->tid) { 346 AUTH_ERRLOG(qpair, "transaction id mismatch: %u != %u\n", msg->t_id, auth->tid); 347 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 348 goto out; 349 } 350 if (msg->cvalid) { 351 AUTH_ERRLOG(qpair, "bidirection authentication isn't supported yet\n"); 352 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 353 goto out; 354 } 355 356 key = nvmf_subsystem_get_dhchap_key(ctrlr->subsys, ctrlr->hostnqn, NVMF_AUTH_KEY_HOST); 357 if (key == NULL) { 358 AUTH_ERRLOG(qpair, "couldn't get DH-HMAC-CHAP key\n"); 359 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED); 360 goto out; 361 } 362 363 if (auth->dhgroup != SPDK_NVMF_DHCHAP_DHGROUP_NULL) { 364 AUTH_LOGDUMP("host pubkey:", &msg->rval[2 * hl], msg->dhvlen); 365 dhseclen = sizeof(dhsec); 366 rc = spdk_nvme_dhchap_dhkey_derive_secret(auth->dhkey, &msg->rval[2 * hl], 367 msg->dhvlen, dhsec, &dhseclen); 368 if (rc != 0) { 369 AUTH_ERRLOG(qpair, "couldn't derive DH secret\n"); 370 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED); 371 goto out; 372 } 373 374 AUTH_LOGDUMP("dh secret:", dhsec, dhseclen); 375 } 376 377 assert(hl <= sizeof(response) && hl <= sizeof(auth->cval)); 378 rc = spdk_nvme_dhchap_calculate(key, (enum spdk_nvmf_dhchap_hash)auth->digest, 379 "HostHost", auth->seqnum, auth->tid, 0, 380 ctrlr->hostnqn, ctrlr->subsys->subnqn, 381 dhseclen > 0 ? dhsec : NULL, dhseclen, 382 auth->cval, response); 383 if (rc != 0) { 384 AUTH_ERRLOG(qpair, "failed to calculate challenge response: %s\n", 385 spdk_strerror(-rc)); 386 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED); 387 goto out; 388 } 389 390 if (memcmp(msg->rval, response, hl) != 0) { 391 AUTH_ERRLOG(qpair, "challenge response mismatch\n"); 392 AUTH_LOGDUMP("response:", msg->rval, hl); 393 AUTH_LOGDUMP("expected:", response, hl); 394 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_FAILED); 395 goto out; 396 } 397 398 if (nvmf_auth_rearm_poller(qpair)) { 399 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 400 SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1); 401 nvmf_auth_disconnect_qpair(qpair); 402 goto out; 403 } 404 405 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_SUCCESS1); 406 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0); 407 out: 408 spdk_keyring_put_key(key); 409 } 410 411 static void 412 nvmf_auth_send_exec(struct spdk_nvmf_request *req) 413 { 414 struct spdk_nvmf_qpair *qpair = req->qpair; 415 struct spdk_nvmf_fabric_auth_send_cmd *cmd = &req->cmd->auth_send_cmd; 416 struct nvmf_auth_common_header *header; 417 int rc; 418 419 rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->tl); 420 if (rc != 0) { 421 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 422 SPDK_NVME_SC_INVALID_FIELD, 1); 423 return; 424 } 425 426 header = nvmf_auth_get_message(req, sizeof(*header)); 427 if (header == NULL) { 428 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PAYLOAD); 429 return; 430 } 431 432 switch (header->auth_type) { 433 case SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE: 434 switch (header->auth_id) { 435 case SPDK_NVMF_AUTH_ID_NEGOTIATE: 436 nvmf_auth_negotiate_exec(req, (void *)header); 437 break; 438 default: 439 AUTH_ERRLOG(qpair, "unexpected auth_id=%u\n", header->auth_id); 440 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE); 441 break; 442 } 443 break; 444 case SPDK_NVMF_AUTH_TYPE_DHCHAP: 445 switch (header->auth_id) { 446 case SPDK_NVMF_AUTH_ID_DHCHAP_REPLY: 447 nvmf_auth_reply_exec(req, (void *)header); 448 break; 449 default: 450 AUTH_ERRLOG(qpair, "unexpected auth_id=%u\n", header->auth_id); 451 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE); 452 break; 453 } 454 break; 455 default: 456 AUTH_ERRLOG(qpair, "unexpected auth_type=%u\n", header->auth_type); 457 nvmf_auth_request_fail1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE); 458 break; 459 } 460 } 461 462 static void 463 nvmf_auth_recv_complete(struct spdk_nvmf_request *req, uint32_t length) 464 { 465 assert(req->cmd->nvmf_cmd.fctype == SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV); 466 req->length = length; 467 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, SPDK_NVME_SC_SUCCESS, 0); 468 } 469 470 static void 471 nvmf_auth_recv_failure1(struct spdk_nvmf_request *req, int fail_reason) 472 { 473 struct spdk_nvmf_qpair *qpair = req->qpair; 474 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 475 struct spdk_nvmf_auth_failure *failure; 476 477 failure = nvmf_auth_get_message(req, sizeof(*failure)); 478 if (failure == NULL) { 479 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 480 SPDK_NVME_SC_INVALID_FIELD, 1); 481 nvmf_auth_disconnect_qpair(qpair); 482 return; 483 } 484 485 failure->auth_type = SPDK_NVMF_AUTH_TYPE_COMMON_MESSAGE; 486 failure->auth_id = SPDK_NVMF_AUTH_ID_FAILURE1; 487 failure->t_id = auth->tid; 488 failure->rc = SPDK_NVMF_AUTH_FAILURE; 489 failure->rce = fail_reason; 490 491 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_FAILURE1); 492 nvmf_auth_recv_complete(req, sizeof(*failure)); 493 nvmf_auth_disconnect_qpair(qpair); 494 } 495 496 static int 497 nvmf_auth_get_seqnum(struct spdk_nvmf_qpair *qpair) 498 { 499 struct spdk_nvmf_subsystem *subsys = qpair->ctrlr->subsys; 500 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 501 int rc; 502 503 pthread_mutex_lock(&subsys->mutex); 504 if (subsys->auth_seqnum == 0) { 505 rc = RAND_bytes((void *)&subsys->auth_seqnum, sizeof(subsys->auth_seqnum)); 506 if (rc != 1) { 507 pthread_mutex_unlock(&subsys->mutex); 508 return -EIO; 509 } 510 } 511 if (++subsys->auth_seqnum == 0) { 512 subsys->auth_seqnum = 1; 513 514 } 515 auth->seqnum = subsys->auth_seqnum; 516 pthread_mutex_unlock(&subsys->mutex); 517 518 return 0; 519 } 520 521 static int 522 nvmf_auth_recv_challenge(struct spdk_nvmf_request *req) 523 { 524 struct spdk_nvmf_qpair *qpair = req->qpair; 525 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 526 struct spdk_nvmf_dhchap_challenge *challenge; 527 uint8_t hl, dhv[NVMF_AUTH_DH_KEY_MAX_SIZE]; 528 size_t dhvlen = 0; 529 int rc; 530 531 hl = spdk_nvme_dhchap_get_digest_length(auth->digest); 532 assert(hl > 0 && hl <= sizeof(auth->cval)); 533 534 if (auth->dhgroup != SPDK_NVMF_DHCHAP_DHGROUP_NULL) { 535 auth->dhkey = spdk_nvme_dhchap_generate_dhkey(auth->dhgroup); 536 if (auth->dhkey == NULL) { 537 AUTH_ERRLOG(qpair, "failed to generate DH key\n"); 538 return SPDK_NVMF_AUTH_FAILED; 539 } 540 541 dhvlen = sizeof(dhv); 542 rc = spdk_nvme_dhchap_dhkey_get_pubkey(auth->dhkey, dhv, &dhvlen); 543 if (rc != 0) { 544 AUTH_ERRLOG(qpair, "failed to get DH public key\n"); 545 return SPDK_NVMF_AUTH_FAILED; 546 } 547 548 AUTH_LOGDUMP("ctrlr pubkey:", dhv, dhvlen); 549 } 550 551 challenge = nvmf_auth_get_message(req, sizeof(*challenge) + hl + dhvlen); 552 if (challenge == NULL) { 553 AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length); 554 return SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 555 } 556 rc = nvmf_auth_get_seqnum(qpair); 557 if (rc != 0) { 558 return SPDK_NVMF_AUTH_FAILED; 559 } 560 rc = RAND_bytes(auth->cval, hl); 561 if (rc != 1) { 562 return SPDK_NVMF_AUTH_FAILED; 563 } 564 if (nvmf_auth_rearm_poller(qpair)) { 565 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 566 SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 1); 567 nvmf_auth_disconnect_qpair(qpair); 568 return 0; 569 } 570 571 memcpy(challenge->cval, auth->cval, hl); 572 memcpy(&challenge->cval[hl], dhv, dhvlen); 573 challenge->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 574 challenge->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_CHALLENGE; 575 challenge->t_id = auth->tid; 576 challenge->hl = hl; 577 challenge->hash_id = (uint8_t)auth->digest; 578 challenge->dhg_id = (uint8_t)auth->dhgroup; 579 challenge->dhvlen = dhvlen; 580 challenge->seqnum = auth->seqnum; 581 582 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_REPLY); 583 nvmf_auth_recv_complete(req, sizeof(*challenge) + hl + dhvlen); 584 585 return 0; 586 } 587 588 static int 589 nvmf_auth_recv_success1(struct spdk_nvmf_request *req) 590 { 591 struct spdk_nvmf_qpair *qpair = req->qpair; 592 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 593 struct spdk_nvmf_dhchap_success1 *success; 594 595 success = nvmf_auth_get_message(req, sizeof(*success)); 596 if (success == NULL) { 597 AUTH_ERRLOG(qpair, "invalid message length: %"PRIu32"\n", req->length); 598 return SPDK_NVMF_AUTH_INCORRECT_PAYLOAD; 599 } 600 601 success->auth_type = SPDK_NVMF_AUTH_TYPE_DHCHAP; 602 success->auth_id = SPDK_NVMF_AUTH_ID_DHCHAP_SUCCESS1; 603 success->t_id = auth->tid; 604 /* Kernel initiator always expects hl to be set, regardless of rvalid */ 605 success->hl = spdk_nvme_dhchap_get_digest_length(auth->digest); 606 success->rvalid = 0; 607 608 AUTH_DEBUGLOG(qpair, "host authentication successful\n"); 609 nvmf_auth_recv_complete(req, sizeof(*success)); 610 nvmf_qpair_set_state(qpair, SPDK_NVMF_QPAIR_ENABLED); 611 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_COMPLETED); 612 nvmf_auth_qpair_cleanup(auth); 613 614 return 0; 615 } 616 617 static void 618 nvmf_auth_recv_exec(struct spdk_nvmf_request *req) 619 { 620 struct spdk_nvmf_qpair *qpair = req->qpair; 621 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 622 struct spdk_nvmf_fabric_auth_recv_cmd *cmd = &req->cmd->auth_recv_cmd; 623 int rc; 624 625 rc = nvmf_auth_check_command(req, cmd->secp, cmd->spsp0, cmd->spsp1, cmd->al); 626 if (rc != 0) { 627 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 628 SPDK_NVME_SC_INVALID_FIELD, 1); 629 return; 630 } 631 632 spdk_iov_memset(req->iov, req->iovcnt, 0); 633 switch (auth->state) { 634 case NVMF_QPAIR_AUTH_CHALLENGE: 635 rc = nvmf_auth_recv_challenge(req); 636 if (rc != 0) { 637 nvmf_auth_recv_failure1(req, rc); 638 } 639 break; 640 case NVMF_QPAIR_AUTH_SUCCESS1: 641 rc = nvmf_auth_recv_success1(req); 642 if (rc != 0) { 643 nvmf_auth_recv_failure1(req, rc); 644 } 645 break; 646 case NVMF_QPAIR_AUTH_FAILURE1: 647 nvmf_auth_recv_failure1(req, auth->fail_reason); 648 break; 649 default: 650 nvmf_auth_recv_failure1(req, SPDK_NVMF_AUTH_INCORRECT_PROTOCOL_MESSAGE); 651 break; 652 } 653 } 654 655 int 656 nvmf_auth_request_exec(struct spdk_nvmf_request *req) 657 { 658 struct spdk_nvmf_qpair *qpair = req->qpair; 659 union nvmf_h2c_msg *cmd = req->cmd; 660 661 /* We don't support reauthentication */ 662 if (qpair->state != SPDK_NVMF_QPAIR_AUTHENTICATING) { 663 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 664 SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR, 0); 665 return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; 666 } 667 668 assert(cmd->nvmf_cmd.opcode == SPDK_NVME_OPC_FABRIC); 669 switch (cmd->nvmf_cmd.fctype) { 670 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_SEND: 671 nvmf_auth_send_exec(req); 672 break; 673 case SPDK_NVMF_FABRIC_COMMAND_AUTHENTICATION_RECV: 674 nvmf_auth_recv_exec(req); 675 break; 676 default: 677 assert(0 && "invalid fctype"); 678 nvmf_auth_request_complete(req, SPDK_NVME_SCT_GENERIC, 679 SPDK_NVME_SC_INTERNAL_DEVICE_ERROR, 0); 680 break; 681 } 682 683 return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; 684 } 685 686 int 687 nvmf_qpair_auth_init(struct spdk_nvmf_qpair *qpair) 688 { 689 struct spdk_nvmf_qpair_auth *auth; 690 int rc; 691 692 assert(qpair->auth == NULL); 693 auth = calloc(1, sizeof(*qpair->auth)); 694 if (auth == NULL) { 695 return -ENOMEM; 696 } 697 698 auth->digest = -1; 699 qpair->auth = auth; 700 nvmf_auth_set_state(qpair, NVMF_QPAIR_AUTH_NEGOTIATE); 701 702 rc = nvmf_auth_rearm_poller(qpair); 703 if (rc != 0) { 704 AUTH_ERRLOG(qpair, "failed to arm timeout poller: %s\n", spdk_strerror(-rc)); 705 nvmf_qpair_auth_destroy(qpair); 706 return rc; 707 } 708 709 return 0; 710 } 711 712 void 713 nvmf_qpair_auth_destroy(struct spdk_nvmf_qpair *qpair) 714 { 715 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 716 717 if (auth != NULL) { 718 nvmf_auth_qpair_cleanup(auth); 719 free(qpair->auth); 720 qpair->auth = NULL; 721 } 722 } 723 724 void 725 nvmf_qpair_auth_dump(struct spdk_nvmf_qpair *qpair, struct spdk_json_write_ctx *w) 726 { 727 struct spdk_nvmf_qpair_auth *auth = qpair->auth; 728 const char *digest, *dhgroup; 729 730 if (auth == NULL) { 731 return; 732 } 733 734 spdk_json_write_named_object_begin(w, "auth"); 735 spdk_json_write_named_string(w, "state", nvmf_auth_get_state_name(auth->state)); 736 digest = spdk_nvme_dhchap_get_digest_name(auth->digest); 737 spdk_json_write_named_string(w, "digest", digest ? digest : "unknown"); 738 dhgroup = spdk_nvme_dhchap_get_dhgroup_name(auth->dhgroup); 739 spdk_json_write_named_string(w, "dhgroup", dhgroup ? dhgroup : "unknown"); 740 spdk_json_write_object_end(w); 741 } 742 743 bool 744 nvmf_auth_is_supported(void) 745 { 746 return true; 747 } 748 SPDK_LOG_REGISTER_COMPONENT(nvmf_auth) 749