1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * NVMe over Fabrics DH-HMAC-CHAP authentication. 4 * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions. 5 * All rights reserved. 6 */ 7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 #include <linux/module.h> 9 #include <linux/init.h> 10 #include <linux/slab.h> 11 #include <linux/err.h> 12 #include <crypto/hash.h> 13 #include <linux/crc32.h> 14 #include <linux/base64.h> 15 #include <linux/ctype.h> 16 #include <linux/random.h> 17 #include <linux/nvme-auth.h> 18 #include <linux/unaligned.h> 19 20 #include "nvmet.h" 21 22 int nvmet_auth_set_key(struct nvmet_host *host, const char *secret, 23 bool set_ctrl) 24 { 25 unsigned char key_hash; 26 char *dhchap_secret; 27 28 if (!strlen(secret)) { 29 if (set_ctrl) { 30 kfree(host->dhchap_ctrl_secret); 31 host->dhchap_ctrl_secret = NULL; 32 host->dhchap_ctrl_key_hash = 0; 33 } else { 34 kfree(host->dhchap_secret); 35 host->dhchap_secret = NULL; 36 host->dhchap_key_hash = 0; 37 } 38 return 0; 39 } 40 if (sscanf(secret, "DHHC-1:%hhd:%*s", &key_hash) != 1) 41 return -EINVAL; 42 if (key_hash > 3) { 43 pr_warn("Invalid DH-HMAC-CHAP hash id %d\n", 44 key_hash); 45 return -EINVAL; 46 } 47 if (key_hash > 0) { 48 /* Validate selected hash algorithm */ 49 const char *hmac = nvme_auth_hmac_name(key_hash); 50 51 if (!crypto_has_shash(hmac, 0, 0)) { 52 pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac); 53 return -ENOTSUPP; 54 } 55 } 56 dhchap_secret = kstrdup(secret, GFP_KERNEL); 57 if (!dhchap_secret) 58 return -ENOMEM; 59 down_write(&nvmet_config_sem); 60 if (set_ctrl) { 61 kfree(host->dhchap_ctrl_secret); 62 host->dhchap_ctrl_secret = strim(dhchap_secret); 63 host->dhchap_ctrl_key_hash = key_hash; 64 } else { 65 kfree(host->dhchap_secret); 66 host->dhchap_secret = strim(dhchap_secret); 67 host->dhchap_key_hash = key_hash; 68 } 69 up_write(&nvmet_config_sem); 70 return 0; 71 } 72 73 int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id) 74 { 75 const char *dhgroup_kpp; 76 int ret = 0; 77 78 pr_debug("%s: ctrl %d selecting dhgroup %d\n", 79 __func__, ctrl->cntlid, dhgroup_id); 80 81 if (ctrl->dh_tfm) { 82 if (ctrl->dh_gid == dhgroup_id) { 83 pr_debug("%s: ctrl %d reuse existing DH group %d\n", 84 __func__, ctrl->cntlid, dhgroup_id); 85 return 0; 86 } 87 crypto_free_kpp(ctrl->dh_tfm); 88 ctrl->dh_tfm = NULL; 89 ctrl->dh_gid = 0; 90 } 91 92 if (dhgroup_id == NVME_AUTH_DHGROUP_NULL) 93 return 0; 94 95 dhgroup_kpp = nvme_auth_dhgroup_kpp(dhgroup_id); 96 if (!dhgroup_kpp) { 97 pr_debug("%s: ctrl %d invalid DH group %d\n", 98 __func__, ctrl->cntlid, dhgroup_id); 99 return -EINVAL; 100 } 101 ctrl->dh_tfm = crypto_alloc_kpp(dhgroup_kpp, 0, 0); 102 if (IS_ERR(ctrl->dh_tfm)) { 103 pr_debug("%s: ctrl %d failed to setup DH group %d, err %ld\n", 104 __func__, ctrl->cntlid, dhgroup_id, 105 PTR_ERR(ctrl->dh_tfm)); 106 ret = PTR_ERR(ctrl->dh_tfm); 107 ctrl->dh_tfm = NULL; 108 ctrl->dh_gid = 0; 109 } else { 110 ctrl->dh_gid = dhgroup_id; 111 pr_debug("%s: ctrl %d setup DH group %d\n", 112 __func__, ctrl->cntlid, ctrl->dh_gid); 113 ret = nvme_auth_gen_privkey(ctrl->dh_tfm, ctrl->dh_gid); 114 if (ret < 0) { 115 pr_debug("%s: ctrl %d failed to generate private key, err %d\n", 116 __func__, ctrl->cntlid, ret); 117 kfree_sensitive(ctrl->dh_key); 118 return ret; 119 } 120 ctrl->dh_keysize = crypto_kpp_maxsize(ctrl->dh_tfm); 121 kfree_sensitive(ctrl->dh_key); 122 ctrl->dh_key = kzalloc(ctrl->dh_keysize, GFP_KERNEL); 123 if (!ctrl->dh_key) { 124 pr_warn("ctrl %d failed to allocate public key\n", 125 ctrl->cntlid); 126 return -ENOMEM; 127 } 128 ret = nvme_auth_gen_pubkey(ctrl->dh_tfm, ctrl->dh_key, 129 ctrl->dh_keysize); 130 if (ret < 0) { 131 pr_warn("ctrl %d failed to generate public key\n", 132 ctrl->cntlid); 133 kfree(ctrl->dh_key); 134 ctrl->dh_key = NULL; 135 } 136 } 137 138 return ret; 139 } 140 141 u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl) 142 { 143 int ret = 0; 144 struct nvmet_host_link *p; 145 struct nvmet_host *host = NULL; 146 147 down_read(&nvmet_config_sem); 148 if (nvmet_is_disc_subsys(ctrl->subsys)) 149 goto out_unlock; 150 151 if (ctrl->subsys->allow_any_host) 152 goto out_unlock; 153 154 list_for_each_entry(p, &ctrl->subsys->hosts, entry) { 155 pr_debug("check %s\n", nvmet_host_name(p->host)); 156 if (strcmp(nvmet_host_name(p->host), ctrl->hostnqn)) 157 continue; 158 host = p->host; 159 break; 160 } 161 if (!host) { 162 pr_debug("host %s not found\n", ctrl->hostnqn); 163 ret = NVME_AUTH_DHCHAP_FAILURE_FAILED; 164 goto out_unlock; 165 } 166 167 ret = nvmet_setup_dhgroup(ctrl, host->dhchap_dhgroup_id); 168 if (ret < 0) { 169 pr_warn("Failed to setup DH group"); 170 ret = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; 171 goto out_unlock; 172 } 173 174 if (!host->dhchap_secret) { 175 pr_debug("No authentication provided\n"); 176 goto out_unlock; 177 } 178 179 if (host->dhchap_hash_id == ctrl->shash_id) { 180 pr_debug("Re-use existing hash ID %d\n", 181 ctrl->shash_id); 182 } else { 183 ctrl->shash_id = host->dhchap_hash_id; 184 } 185 186 /* Skip the 'DHHC-1:XX:' prefix */ 187 nvme_auth_free_key(ctrl->host_key); 188 ctrl->host_key = nvme_auth_extract_key(host->dhchap_secret + 10, 189 host->dhchap_key_hash); 190 if (IS_ERR(ctrl->host_key)) { 191 ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE; 192 ctrl->host_key = NULL; 193 goto out_free_hash; 194 } 195 pr_debug("%s: using hash %s key %*ph\n", __func__, 196 ctrl->host_key->hash > 0 ? 197 nvme_auth_hmac_name(ctrl->host_key->hash) : "none", 198 (int)ctrl->host_key->len, ctrl->host_key->key); 199 200 nvme_auth_free_key(ctrl->ctrl_key); 201 if (!host->dhchap_ctrl_secret) { 202 ctrl->ctrl_key = NULL; 203 goto out_unlock; 204 } 205 206 ctrl->ctrl_key = nvme_auth_extract_key(host->dhchap_ctrl_secret + 10, 207 host->dhchap_ctrl_key_hash); 208 if (IS_ERR(ctrl->ctrl_key)) { 209 ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE; 210 ctrl->ctrl_key = NULL; 211 goto out_free_hash; 212 } 213 pr_debug("%s: using ctrl hash %s key %*ph\n", __func__, 214 ctrl->ctrl_key->hash > 0 ? 215 nvme_auth_hmac_name(ctrl->ctrl_key->hash) : "none", 216 (int)ctrl->ctrl_key->len, ctrl->ctrl_key->key); 217 218 out_free_hash: 219 if (ret) { 220 if (ctrl->host_key) { 221 nvme_auth_free_key(ctrl->host_key); 222 ctrl->host_key = NULL; 223 } 224 ctrl->shash_id = 0; 225 } 226 out_unlock: 227 up_read(&nvmet_config_sem); 228 229 return ret; 230 } 231 232 void nvmet_auth_sq_free(struct nvmet_sq *sq) 233 { 234 cancel_delayed_work(&sq->auth_expired_work); 235 kfree(sq->dhchap_c1); 236 sq->dhchap_c1 = NULL; 237 kfree(sq->dhchap_c2); 238 sq->dhchap_c2 = NULL; 239 kfree(sq->dhchap_skey); 240 sq->dhchap_skey = NULL; 241 } 242 243 void nvmet_destroy_auth(struct nvmet_ctrl *ctrl) 244 { 245 ctrl->shash_id = 0; 246 247 if (ctrl->dh_tfm) { 248 crypto_free_kpp(ctrl->dh_tfm); 249 ctrl->dh_tfm = NULL; 250 ctrl->dh_gid = 0; 251 } 252 kfree_sensitive(ctrl->dh_key); 253 ctrl->dh_key = NULL; 254 255 if (ctrl->host_key) { 256 nvme_auth_free_key(ctrl->host_key); 257 ctrl->host_key = NULL; 258 } 259 if (ctrl->ctrl_key) { 260 nvme_auth_free_key(ctrl->ctrl_key); 261 ctrl->ctrl_key = NULL; 262 } 263 } 264 265 bool nvmet_check_auth_status(struct nvmet_req *req) 266 { 267 if (req->sq->ctrl->host_key && 268 !req->sq->authenticated) 269 return false; 270 return true; 271 } 272 273 int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, 274 unsigned int shash_len) 275 { 276 struct crypto_shash *shash_tfm; 277 struct shash_desc *shash; 278 struct nvmet_ctrl *ctrl = req->sq->ctrl; 279 const char *hash_name; 280 u8 *challenge = req->sq->dhchap_c1; 281 struct nvme_dhchap_key *transformed_key; 282 u8 buf[4]; 283 int ret; 284 285 hash_name = nvme_auth_hmac_name(ctrl->shash_id); 286 if (!hash_name) { 287 pr_warn("Hash ID %d invalid\n", ctrl->shash_id); 288 return -EINVAL; 289 } 290 291 shash_tfm = crypto_alloc_shash(hash_name, 0, 0); 292 if (IS_ERR(shash_tfm)) { 293 pr_err("failed to allocate shash %s\n", hash_name); 294 return PTR_ERR(shash_tfm); 295 } 296 297 if (shash_len != crypto_shash_digestsize(shash_tfm)) { 298 pr_err("%s: hash len mismatch (len %d digest %d)\n", 299 __func__, shash_len, 300 crypto_shash_digestsize(shash_tfm)); 301 ret = -EINVAL; 302 goto out_free_tfm; 303 } 304 305 transformed_key = nvme_auth_transform_key(ctrl->host_key, 306 ctrl->hostnqn); 307 if (IS_ERR(transformed_key)) { 308 ret = PTR_ERR(transformed_key); 309 goto out_free_tfm; 310 } 311 312 ret = crypto_shash_setkey(shash_tfm, transformed_key->key, 313 transformed_key->len); 314 if (ret) 315 goto out_free_response; 316 317 if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) { 318 challenge = kmalloc(shash_len, GFP_KERNEL); 319 if (!challenge) { 320 ret = -ENOMEM; 321 goto out_free_response; 322 } 323 ret = nvme_auth_augmented_challenge(ctrl->shash_id, 324 req->sq->dhchap_skey, 325 req->sq->dhchap_skey_len, 326 req->sq->dhchap_c1, 327 challenge, shash_len); 328 if (ret) 329 goto out_free_challenge; 330 } 331 332 pr_debug("ctrl %d qid %d host response seq %u transaction %d\n", 333 ctrl->cntlid, req->sq->qid, req->sq->dhchap_s1, 334 req->sq->dhchap_tid); 335 336 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm), 337 GFP_KERNEL); 338 if (!shash) { 339 ret = -ENOMEM; 340 goto out_free_challenge; 341 } 342 shash->tfm = shash_tfm; 343 ret = crypto_shash_init(shash); 344 if (ret) 345 goto out; 346 ret = crypto_shash_update(shash, challenge, shash_len); 347 if (ret) 348 goto out; 349 put_unaligned_le32(req->sq->dhchap_s1, buf); 350 ret = crypto_shash_update(shash, buf, 4); 351 if (ret) 352 goto out; 353 put_unaligned_le16(req->sq->dhchap_tid, buf); 354 ret = crypto_shash_update(shash, buf, 2); 355 if (ret) 356 goto out; 357 memset(buf, 0, 4); 358 ret = crypto_shash_update(shash, buf, 1); 359 if (ret) 360 goto out; 361 ret = crypto_shash_update(shash, "HostHost", 8); 362 if (ret) 363 goto out; 364 ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn)); 365 if (ret) 366 goto out; 367 ret = crypto_shash_update(shash, buf, 1); 368 if (ret) 369 goto out; 370 ret = crypto_shash_update(shash, ctrl->subsysnqn, 371 strlen(ctrl->subsysnqn)); 372 if (ret) 373 goto out; 374 ret = crypto_shash_final(shash, response); 375 out: 376 kfree(shash); 377 out_free_challenge: 378 if (challenge != req->sq->dhchap_c1) 379 kfree(challenge); 380 out_free_response: 381 nvme_auth_free_key(transformed_key); 382 out_free_tfm: 383 crypto_free_shash(shash_tfm); 384 return ret; 385 } 386 387 int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, 388 unsigned int shash_len) 389 { 390 struct crypto_shash *shash_tfm; 391 struct shash_desc *shash; 392 struct nvmet_ctrl *ctrl = req->sq->ctrl; 393 const char *hash_name; 394 u8 *challenge = req->sq->dhchap_c2; 395 struct nvme_dhchap_key *transformed_key; 396 u8 buf[4]; 397 int ret; 398 399 hash_name = nvme_auth_hmac_name(ctrl->shash_id); 400 if (!hash_name) { 401 pr_warn("Hash ID %d invalid\n", ctrl->shash_id); 402 return -EINVAL; 403 } 404 405 shash_tfm = crypto_alloc_shash(hash_name, 0, 0); 406 if (IS_ERR(shash_tfm)) { 407 pr_err("failed to allocate shash %s\n", hash_name); 408 return PTR_ERR(shash_tfm); 409 } 410 411 if (shash_len != crypto_shash_digestsize(shash_tfm)) { 412 pr_debug("%s: hash len mismatch (len %d digest %d)\n", 413 __func__, shash_len, 414 crypto_shash_digestsize(shash_tfm)); 415 ret = -EINVAL; 416 goto out_free_tfm; 417 } 418 419 transformed_key = nvme_auth_transform_key(ctrl->ctrl_key, 420 ctrl->subsysnqn); 421 if (IS_ERR(transformed_key)) { 422 ret = PTR_ERR(transformed_key); 423 goto out_free_tfm; 424 } 425 426 ret = crypto_shash_setkey(shash_tfm, transformed_key->key, 427 transformed_key->len); 428 if (ret) 429 goto out_free_response; 430 431 if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) { 432 challenge = kmalloc(shash_len, GFP_KERNEL); 433 if (!challenge) { 434 ret = -ENOMEM; 435 goto out_free_response; 436 } 437 ret = nvme_auth_augmented_challenge(ctrl->shash_id, 438 req->sq->dhchap_skey, 439 req->sq->dhchap_skey_len, 440 req->sq->dhchap_c2, 441 challenge, shash_len); 442 if (ret) 443 goto out_free_challenge; 444 } 445 446 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm), 447 GFP_KERNEL); 448 if (!shash) { 449 ret = -ENOMEM; 450 goto out_free_challenge; 451 } 452 shash->tfm = shash_tfm; 453 454 ret = crypto_shash_init(shash); 455 if (ret) 456 goto out; 457 ret = crypto_shash_update(shash, challenge, shash_len); 458 if (ret) 459 goto out; 460 put_unaligned_le32(req->sq->dhchap_s2, buf); 461 ret = crypto_shash_update(shash, buf, 4); 462 if (ret) 463 goto out; 464 put_unaligned_le16(req->sq->dhchap_tid, buf); 465 ret = crypto_shash_update(shash, buf, 2); 466 if (ret) 467 goto out; 468 memset(buf, 0, 4); 469 ret = crypto_shash_update(shash, buf, 1); 470 if (ret) 471 goto out; 472 ret = crypto_shash_update(shash, "Controller", 10); 473 if (ret) 474 goto out; 475 ret = crypto_shash_update(shash, ctrl->subsysnqn, 476 strlen(ctrl->subsysnqn)); 477 if (ret) 478 goto out; 479 ret = crypto_shash_update(shash, buf, 1); 480 if (ret) 481 goto out; 482 ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn)); 483 if (ret) 484 goto out; 485 ret = crypto_shash_final(shash, response); 486 out: 487 kfree(shash); 488 out_free_challenge: 489 if (challenge != req->sq->dhchap_c2) 490 kfree(challenge); 491 out_free_response: 492 nvme_auth_free_key(transformed_key); 493 out_free_tfm: 494 crypto_free_shash(shash_tfm); 495 return ret; 496 } 497 498 int nvmet_auth_ctrl_exponential(struct nvmet_req *req, 499 u8 *buf, int buf_size) 500 { 501 struct nvmet_ctrl *ctrl = req->sq->ctrl; 502 int ret = 0; 503 504 if (!ctrl->dh_key) { 505 pr_warn("ctrl %d no DH public key!\n", ctrl->cntlid); 506 return -ENOKEY; 507 } 508 if (buf_size != ctrl->dh_keysize) { 509 pr_warn("ctrl %d DH public key size mismatch, need %zu is %d\n", 510 ctrl->cntlid, ctrl->dh_keysize, buf_size); 511 ret = -EINVAL; 512 } else { 513 memcpy(buf, ctrl->dh_key, buf_size); 514 pr_debug("%s: ctrl %d public key %*ph\n", __func__, 515 ctrl->cntlid, (int)buf_size, buf); 516 } 517 518 return ret; 519 } 520 521 int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, 522 u8 *pkey, int pkey_size) 523 { 524 struct nvmet_ctrl *ctrl = req->sq->ctrl; 525 int ret; 526 527 req->sq->dhchap_skey_len = ctrl->dh_keysize; 528 req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL); 529 if (!req->sq->dhchap_skey) 530 return -ENOMEM; 531 ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm, 532 pkey, pkey_size, 533 req->sq->dhchap_skey, 534 req->sq->dhchap_skey_len); 535 if (ret) 536 pr_debug("failed to compute shared secret, err %d\n", ret); 537 else 538 pr_debug("%s: shared secret %*ph\n", __func__, 539 (int)req->sq->dhchap_skey_len, 540 req->sq->dhchap_skey); 541 542 return ret; 543 } 544