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