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