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 ctrl->dh_key = NULL; 119 return ret; 120 } 121 ctrl->dh_keysize = crypto_kpp_maxsize(ctrl->dh_tfm); 122 kfree_sensitive(ctrl->dh_key); 123 ctrl->dh_key = kzalloc(ctrl->dh_keysize, GFP_KERNEL); 124 if (!ctrl->dh_key) { 125 pr_warn("ctrl %d failed to allocate public key\n", 126 ctrl->cntlid); 127 return -ENOMEM; 128 } 129 ret = nvme_auth_gen_pubkey(ctrl->dh_tfm, ctrl->dh_key, 130 ctrl->dh_keysize); 131 if (ret < 0) { 132 pr_warn("ctrl %d failed to generate public key\n", 133 ctrl->cntlid); 134 kfree(ctrl->dh_key); 135 ctrl->dh_key = NULL; 136 } 137 } 138 139 return ret; 140 } 141 142 u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl) 143 { 144 int ret = 0; 145 struct nvmet_host_link *p; 146 struct nvmet_host *host = NULL; 147 148 down_read(&nvmet_config_sem); 149 if (nvmet_is_disc_subsys(ctrl->subsys)) 150 goto out_unlock; 151 152 if (ctrl->subsys->allow_any_host) 153 goto out_unlock; 154 155 list_for_each_entry(p, &ctrl->subsys->hosts, entry) { 156 pr_debug("check %s\n", nvmet_host_name(p->host)); 157 if (strcmp(nvmet_host_name(p->host), ctrl->hostnqn)) 158 continue; 159 host = p->host; 160 break; 161 } 162 if (!host) { 163 pr_debug("host %s not found\n", ctrl->hostnqn); 164 ret = NVME_AUTH_DHCHAP_FAILURE_FAILED; 165 goto out_unlock; 166 } 167 168 ret = nvmet_setup_dhgroup(ctrl, host->dhchap_dhgroup_id); 169 if (ret < 0) { 170 pr_warn("Failed to setup DH group"); 171 ret = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; 172 goto out_unlock; 173 } 174 175 if (!host->dhchap_secret) { 176 pr_debug("No authentication provided\n"); 177 goto out_unlock; 178 } 179 180 if (host->dhchap_hash_id == ctrl->shash_id) { 181 pr_debug("Re-use existing hash ID %d\n", 182 ctrl->shash_id); 183 } else { 184 ctrl->shash_id = host->dhchap_hash_id; 185 } 186 187 /* Skip the 'DHHC-1:XX:' prefix */ 188 nvme_auth_free_key(ctrl->host_key); 189 ctrl->host_key = nvme_auth_extract_key(host->dhchap_secret + 10, 190 host->dhchap_key_hash); 191 if (IS_ERR(ctrl->host_key)) { 192 ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE; 193 ctrl->host_key = NULL; 194 goto out_free_hash; 195 } 196 pr_debug("%s: using hash %s key %*ph\n", __func__, 197 ctrl->host_key->hash > 0 ? 198 nvme_auth_hmac_name(ctrl->host_key->hash) : "none", 199 (int)ctrl->host_key->len, ctrl->host_key->key); 200 201 nvme_auth_free_key(ctrl->ctrl_key); 202 if (!host->dhchap_ctrl_secret) { 203 ctrl->ctrl_key = NULL; 204 goto out_unlock; 205 } 206 207 ctrl->ctrl_key = nvme_auth_extract_key(host->dhchap_ctrl_secret + 10, 208 host->dhchap_ctrl_key_hash); 209 if (IS_ERR(ctrl->ctrl_key)) { 210 ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE; 211 ctrl->ctrl_key = NULL; 212 goto out_free_hash; 213 } 214 pr_debug("%s: using ctrl hash %s key %*ph\n", __func__, 215 ctrl->ctrl_key->hash > 0 ? 216 nvme_auth_hmac_name(ctrl->ctrl_key->hash) : "none", 217 (int)ctrl->ctrl_key->len, ctrl->ctrl_key->key); 218 219 out_free_hash: 220 if (ret) { 221 if (ctrl->host_key) { 222 nvme_auth_free_key(ctrl->host_key); 223 ctrl->host_key = NULL; 224 } 225 ctrl->shash_id = 0; 226 } 227 out_unlock: 228 up_read(&nvmet_config_sem); 229 230 return ret; 231 } 232 233 void nvmet_auth_sq_free(struct nvmet_sq *sq) 234 { 235 cancel_delayed_work(&sq->auth_expired_work); 236 kfree(sq->dhchap_c1); 237 sq->dhchap_c1 = NULL; 238 kfree(sq->dhchap_c2); 239 sq->dhchap_c2 = NULL; 240 kfree(sq->dhchap_skey); 241 sq->dhchap_skey = NULL; 242 } 243 244 void nvmet_destroy_auth(struct nvmet_ctrl *ctrl) 245 { 246 ctrl->shash_id = 0; 247 248 if (ctrl->dh_tfm) { 249 crypto_free_kpp(ctrl->dh_tfm); 250 ctrl->dh_tfm = NULL; 251 ctrl->dh_gid = 0; 252 } 253 kfree_sensitive(ctrl->dh_key); 254 ctrl->dh_key = NULL; 255 256 if (ctrl->host_key) { 257 nvme_auth_free_key(ctrl->host_key); 258 ctrl->host_key = NULL; 259 } 260 if (ctrl->ctrl_key) { 261 nvme_auth_free_key(ctrl->ctrl_key); 262 ctrl->ctrl_key = NULL; 263 } 264 } 265 266 bool nvmet_check_auth_status(struct nvmet_req *req) 267 { 268 if (req->sq->ctrl->host_key && 269 !req->sq->authenticated) 270 return false; 271 return true; 272 } 273 274 int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, 275 unsigned int shash_len) 276 { 277 struct crypto_shash *shash_tfm; 278 struct shash_desc *shash; 279 struct nvmet_ctrl *ctrl = req->sq->ctrl; 280 const char *hash_name; 281 u8 *challenge = req->sq->dhchap_c1; 282 struct nvme_dhchap_key *transformed_key; 283 u8 buf[4]; 284 int ret; 285 286 hash_name = nvme_auth_hmac_name(ctrl->shash_id); 287 if (!hash_name) { 288 pr_warn("Hash ID %d invalid\n", ctrl->shash_id); 289 return -EINVAL; 290 } 291 292 shash_tfm = crypto_alloc_shash(hash_name, 0, 0); 293 if (IS_ERR(shash_tfm)) { 294 pr_err("failed to allocate shash %s\n", hash_name); 295 return PTR_ERR(shash_tfm); 296 } 297 298 if (shash_len != crypto_shash_digestsize(shash_tfm)) { 299 pr_err("%s: hash len mismatch (len %d digest %d)\n", 300 __func__, shash_len, 301 crypto_shash_digestsize(shash_tfm)); 302 ret = -EINVAL; 303 goto out_free_tfm; 304 } 305 306 transformed_key = nvme_auth_transform_key(ctrl->host_key, 307 ctrl->hostnqn); 308 if (IS_ERR(transformed_key)) { 309 ret = PTR_ERR(transformed_key); 310 goto out_free_tfm; 311 } 312 313 ret = crypto_shash_setkey(shash_tfm, transformed_key->key, 314 transformed_key->len); 315 if (ret) 316 goto out_free_response; 317 318 if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) { 319 challenge = kmalloc(shash_len, GFP_KERNEL); 320 if (!challenge) { 321 ret = -ENOMEM; 322 goto out_free_response; 323 } 324 ret = nvme_auth_augmented_challenge(ctrl->shash_id, 325 req->sq->dhchap_skey, 326 req->sq->dhchap_skey_len, 327 req->sq->dhchap_c1, 328 challenge, shash_len); 329 if (ret) 330 goto out_free_challenge; 331 } 332 333 pr_debug("ctrl %d qid %d host response seq %u transaction %d\n", 334 ctrl->cntlid, req->sq->qid, req->sq->dhchap_s1, 335 req->sq->dhchap_tid); 336 337 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm), 338 GFP_KERNEL); 339 if (!shash) { 340 ret = -ENOMEM; 341 goto out_free_challenge; 342 } 343 shash->tfm = shash_tfm; 344 ret = crypto_shash_init(shash); 345 if (ret) 346 goto out; 347 ret = crypto_shash_update(shash, challenge, shash_len); 348 if (ret) 349 goto out; 350 put_unaligned_le32(req->sq->dhchap_s1, buf); 351 ret = crypto_shash_update(shash, buf, 4); 352 if (ret) 353 goto out; 354 put_unaligned_le16(req->sq->dhchap_tid, buf); 355 ret = crypto_shash_update(shash, buf, 2); 356 if (ret) 357 goto out; 358 memset(buf, 0, 4); 359 ret = crypto_shash_update(shash, buf, 1); 360 if (ret) 361 goto out; 362 ret = crypto_shash_update(shash, "HostHost", 8); 363 if (ret) 364 goto out; 365 ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn)); 366 if (ret) 367 goto out; 368 ret = crypto_shash_update(shash, buf, 1); 369 if (ret) 370 goto out; 371 ret = crypto_shash_update(shash, ctrl->subsysnqn, 372 strlen(ctrl->subsysnqn)); 373 if (ret) 374 goto out; 375 ret = crypto_shash_final(shash, response); 376 out: 377 kfree(shash); 378 out_free_challenge: 379 if (challenge != req->sq->dhchap_c1) 380 kfree(challenge); 381 out_free_response: 382 nvme_auth_free_key(transformed_key); 383 out_free_tfm: 384 crypto_free_shash(shash_tfm); 385 return ret; 386 } 387 388 int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, 389 unsigned int shash_len) 390 { 391 struct crypto_shash *shash_tfm; 392 struct shash_desc *shash; 393 struct nvmet_ctrl *ctrl = req->sq->ctrl; 394 const char *hash_name; 395 u8 *challenge = req->sq->dhchap_c2; 396 struct nvme_dhchap_key *transformed_key; 397 u8 buf[4]; 398 int ret; 399 400 hash_name = nvme_auth_hmac_name(ctrl->shash_id); 401 if (!hash_name) { 402 pr_warn("Hash ID %d invalid\n", ctrl->shash_id); 403 return -EINVAL; 404 } 405 406 shash_tfm = crypto_alloc_shash(hash_name, 0, 0); 407 if (IS_ERR(shash_tfm)) { 408 pr_err("failed to allocate shash %s\n", hash_name); 409 return PTR_ERR(shash_tfm); 410 } 411 412 if (shash_len != crypto_shash_digestsize(shash_tfm)) { 413 pr_debug("%s: hash len mismatch (len %d digest %d)\n", 414 __func__, shash_len, 415 crypto_shash_digestsize(shash_tfm)); 416 ret = -EINVAL; 417 goto out_free_tfm; 418 } 419 420 transformed_key = nvme_auth_transform_key(ctrl->ctrl_key, 421 ctrl->subsysnqn); 422 if (IS_ERR(transformed_key)) { 423 ret = PTR_ERR(transformed_key); 424 goto out_free_tfm; 425 } 426 427 ret = crypto_shash_setkey(shash_tfm, transformed_key->key, 428 transformed_key->len); 429 if (ret) 430 goto out_free_response; 431 432 if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) { 433 challenge = kmalloc(shash_len, GFP_KERNEL); 434 if (!challenge) { 435 ret = -ENOMEM; 436 goto out_free_response; 437 } 438 ret = nvme_auth_augmented_challenge(ctrl->shash_id, 439 req->sq->dhchap_skey, 440 req->sq->dhchap_skey_len, 441 req->sq->dhchap_c2, 442 challenge, shash_len); 443 if (ret) 444 goto out_free_challenge; 445 } 446 447 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm), 448 GFP_KERNEL); 449 if (!shash) { 450 ret = -ENOMEM; 451 goto out_free_challenge; 452 } 453 shash->tfm = shash_tfm; 454 455 ret = crypto_shash_init(shash); 456 if (ret) 457 goto out; 458 ret = crypto_shash_update(shash, challenge, shash_len); 459 if (ret) 460 goto out; 461 put_unaligned_le32(req->sq->dhchap_s2, buf); 462 ret = crypto_shash_update(shash, buf, 4); 463 if (ret) 464 goto out; 465 put_unaligned_le16(req->sq->dhchap_tid, buf); 466 ret = crypto_shash_update(shash, buf, 2); 467 if (ret) 468 goto out; 469 memset(buf, 0, 4); 470 ret = crypto_shash_update(shash, buf, 1); 471 if (ret) 472 goto out; 473 ret = crypto_shash_update(shash, "Controller", 10); 474 if (ret) 475 goto out; 476 ret = crypto_shash_update(shash, ctrl->subsysnqn, 477 strlen(ctrl->subsysnqn)); 478 if (ret) 479 goto out; 480 ret = crypto_shash_update(shash, buf, 1); 481 if (ret) 482 goto out; 483 ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn)); 484 if (ret) 485 goto out; 486 ret = crypto_shash_final(shash, response); 487 out: 488 kfree(shash); 489 out_free_challenge: 490 if (challenge != req->sq->dhchap_c2) 491 kfree(challenge); 492 out_free_response: 493 nvme_auth_free_key(transformed_key); 494 out_free_tfm: 495 crypto_free_shash(shash_tfm); 496 return ret; 497 } 498 499 int nvmet_auth_ctrl_exponential(struct nvmet_req *req, 500 u8 *buf, int buf_size) 501 { 502 struct nvmet_ctrl *ctrl = req->sq->ctrl; 503 int ret = 0; 504 505 if (!ctrl->dh_key) { 506 pr_warn("ctrl %d no DH public key!\n", ctrl->cntlid); 507 return -ENOKEY; 508 } 509 if (buf_size != ctrl->dh_keysize) { 510 pr_warn("ctrl %d DH public key size mismatch, need %zu is %d\n", 511 ctrl->cntlid, ctrl->dh_keysize, buf_size); 512 ret = -EINVAL; 513 } else { 514 memcpy(buf, ctrl->dh_key, buf_size); 515 pr_debug("%s: ctrl %d public key %*ph\n", __func__, 516 ctrl->cntlid, (int)buf_size, buf); 517 } 518 519 return ret; 520 } 521 522 int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, 523 u8 *pkey, int pkey_size) 524 { 525 struct nvmet_ctrl *ctrl = req->sq->ctrl; 526 int ret; 527 528 req->sq->dhchap_skey_len = ctrl->dh_keysize; 529 req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL); 530 if (!req->sq->dhchap_skey) 531 return -ENOMEM; 532 ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm, 533 pkey, pkey_size, 534 req->sq->dhchap_skey, 535 req->sq->dhchap_skey_len); 536 if (ret) 537 pr_debug("failed to compute shared secret, err %d\n", ret); 538 else 539 pr_debug("%s: shared secret %*ph\n", __func__, 540 (int)req->sq->dhchap_skey_len, 541 req->sq->dhchap_skey); 542 543 return ret; 544 } 545