0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0008 #include <linux/module.h>
0009 #include <linux/init.h>
0010 #include <linux/slab.h>
0011 #include <linux/err.h>
0012 #include <crypto/hash.h>
0013 #include <linux/crc32.h>
0014 #include <linux/base64.h>
0015 #include <linux/ctype.h>
0016 #include <linux/random.h>
0017 #include <linux/nvme-auth.h>
0018 #include <asm/unaligned.h>
0019
0020 #include "nvmet.h"
0021
0022 int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
0023 bool set_ctrl)
0024 {
0025 unsigned char key_hash;
0026 char *dhchap_secret;
0027
0028 if (sscanf(secret, "DHHC-1:%hhd:%*s", &key_hash) != 1)
0029 return -EINVAL;
0030 if (key_hash > 3) {
0031 pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
0032 key_hash);
0033 return -EINVAL;
0034 }
0035 if (key_hash > 0) {
0036
0037 const char *hmac = nvme_auth_hmac_name(key_hash);
0038
0039 if (!crypto_has_shash(hmac, 0, 0)) {
0040 pr_err("DH-HMAC-CHAP hash %s unsupported\n", hmac);
0041 return -ENOTSUPP;
0042 }
0043 }
0044 dhchap_secret = kstrdup(secret, GFP_KERNEL);
0045 if (!dhchap_secret)
0046 return -ENOMEM;
0047 if (set_ctrl) {
0048 host->dhchap_ctrl_secret = strim(dhchap_secret);
0049 host->dhchap_ctrl_key_hash = key_hash;
0050 } else {
0051 host->dhchap_secret = strim(dhchap_secret);
0052 host->dhchap_key_hash = key_hash;
0053 }
0054 return 0;
0055 }
0056
0057 int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id)
0058 {
0059 const char *dhgroup_kpp;
0060 int ret = 0;
0061
0062 pr_debug("%s: ctrl %d selecting dhgroup %d\n",
0063 __func__, ctrl->cntlid, dhgroup_id);
0064
0065 if (ctrl->dh_tfm) {
0066 if (ctrl->dh_gid == dhgroup_id) {
0067 pr_debug("%s: ctrl %d reuse existing DH group %d\n",
0068 __func__, ctrl->cntlid, dhgroup_id);
0069 return 0;
0070 }
0071 crypto_free_kpp(ctrl->dh_tfm);
0072 ctrl->dh_tfm = NULL;
0073 ctrl->dh_gid = 0;
0074 }
0075
0076 if (dhgroup_id == NVME_AUTH_DHGROUP_NULL)
0077 return 0;
0078
0079 dhgroup_kpp = nvme_auth_dhgroup_kpp(dhgroup_id);
0080 if (!dhgroup_kpp) {
0081 pr_debug("%s: ctrl %d invalid DH group %d\n",
0082 __func__, ctrl->cntlid, dhgroup_id);
0083 return -EINVAL;
0084 }
0085 ctrl->dh_tfm = crypto_alloc_kpp(dhgroup_kpp, 0, 0);
0086 if (IS_ERR(ctrl->dh_tfm)) {
0087 pr_debug("%s: ctrl %d failed to setup DH group %d, err %ld\n",
0088 __func__, ctrl->cntlid, dhgroup_id,
0089 PTR_ERR(ctrl->dh_tfm));
0090 ret = PTR_ERR(ctrl->dh_tfm);
0091 ctrl->dh_tfm = NULL;
0092 ctrl->dh_gid = 0;
0093 } else {
0094 ctrl->dh_gid = dhgroup_id;
0095 pr_debug("%s: ctrl %d setup DH group %d\n",
0096 __func__, ctrl->cntlid, ctrl->dh_gid);
0097 ret = nvme_auth_gen_privkey(ctrl->dh_tfm, ctrl->dh_gid);
0098 if (ret < 0) {
0099 pr_debug("%s: ctrl %d failed to generate private key, err %d\n",
0100 __func__, ctrl->cntlid, ret);
0101 kfree_sensitive(ctrl->dh_key);
0102 return ret;
0103 }
0104 ctrl->dh_keysize = crypto_kpp_maxsize(ctrl->dh_tfm);
0105 kfree_sensitive(ctrl->dh_key);
0106 ctrl->dh_key = kzalloc(ctrl->dh_keysize, GFP_KERNEL);
0107 if (!ctrl->dh_key) {
0108 pr_warn("ctrl %d failed to allocate public key\n",
0109 ctrl->cntlid);
0110 return -ENOMEM;
0111 }
0112 ret = nvme_auth_gen_pubkey(ctrl->dh_tfm, ctrl->dh_key,
0113 ctrl->dh_keysize);
0114 if (ret < 0) {
0115 pr_warn("ctrl %d failed to generate public key\n",
0116 ctrl->cntlid);
0117 kfree(ctrl->dh_key);
0118 ctrl->dh_key = NULL;
0119 }
0120 }
0121
0122 return ret;
0123 }
0124
0125 int nvmet_setup_auth(struct nvmet_ctrl *ctrl)
0126 {
0127 int ret = 0;
0128 struct nvmet_host_link *p;
0129 struct nvmet_host *host = NULL;
0130 const char *hash_name;
0131
0132 down_read(&nvmet_config_sem);
0133 if (nvmet_is_disc_subsys(ctrl->subsys))
0134 goto out_unlock;
0135
0136 if (ctrl->subsys->allow_any_host)
0137 goto out_unlock;
0138
0139 list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
0140 pr_debug("check %s\n", nvmet_host_name(p->host));
0141 if (strcmp(nvmet_host_name(p->host), ctrl->hostnqn))
0142 continue;
0143 host = p->host;
0144 break;
0145 }
0146 if (!host) {
0147 pr_debug("host %s not found\n", ctrl->hostnqn);
0148 ret = -EPERM;
0149 goto out_unlock;
0150 }
0151
0152 ret = nvmet_setup_dhgroup(ctrl, host->dhchap_dhgroup_id);
0153 if (ret < 0)
0154 pr_warn("Failed to setup DH group");
0155
0156 if (!host->dhchap_secret) {
0157 pr_debug("No authentication provided\n");
0158 goto out_unlock;
0159 }
0160
0161 if (host->dhchap_hash_id == ctrl->shash_id) {
0162 pr_debug("Re-use existing hash ID %d\n",
0163 ctrl->shash_id);
0164 } else {
0165 hash_name = nvme_auth_hmac_name(host->dhchap_hash_id);
0166 if (!hash_name) {
0167 pr_warn("Hash ID %d invalid\n", host->dhchap_hash_id);
0168 ret = -EINVAL;
0169 goto out_unlock;
0170 }
0171 ctrl->shash_id = host->dhchap_hash_id;
0172 }
0173
0174
0175 nvme_auth_free_key(ctrl->host_key);
0176 ctrl->host_key = nvme_auth_extract_key(host->dhchap_secret + 10,
0177 host->dhchap_key_hash);
0178 if (IS_ERR(ctrl->host_key)) {
0179 ret = PTR_ERR(ctrl->host_key);
0180 ctrl->host_key = NULL;
0181 goto out_free_hash;
0182 }
0183 pr_debug("%s: using hash %s key %*ph\n", __func__,
0184 ctrl->host_key->hash > 0 ?
0185 nvme_auth_hmac_name(ctrl->host_key->hash) : "none",
0186 (int)ctrl->host_key->len, ctrl->host_key->key);
0187
0188 nvme_auth_free_key(ctrl->ctrl_key);
0189 if (!host->dhchap_ctrl_secret) {
0190 ctrl->ctrl_key = NULL;
0191 goto out_unlock;
0192 }
0193
0194 ctrl->ctrl_key = nvme_auth_extract_key(host->dhchap_ctrl_secret + 10,
0195 host->dhchap_ctrl_key_hash);
0196 if (IS_ERR(ctrl->ctrl_key)) {
0197 ret = PTR_ERR(ctrl->ctrl_key);
0198 ctrl->ctrl_key = NULL;
0199 goto out_free_hash;
0200 }
0201 pr_debug("%s: using ctrl hash %s key %*ph\n", __func__,
0202 ctrl->ctrl_key->hash > 0 ?
0203 nvme_auth_hmac_name(ctrl->ctrl_key->hash) : "none",
0204 (int)ctrl->ctrl_key->len, ctrl->ctrl_key->key);
0205
0206 out_free_hash:
0207 if (ret) {
0208 if (ctrl->host_key) {
0209 nvme_auth_free_key(ctrl->host_key);
0210 ctrl->host_key = NULL;
0211 }
0212 ctrl->shash_id = 0;
0213 }
0214 out_unlock:
0215 up_read(&nvmet_config_sem);
0216
0217 return ret;
0218 }
0219
0220 void nvmet_auth_sq_free(struct nvmet_sq *sq)
0221 {
0222 cancel_delayed_work(&sq->auth_expired_work);
0223 kfree(sq->dhchap_c1);
0224 sq->dhchap_c1 = NULL;
0225 kfree(sq->dhchap_c2);
0226 sq->dhchap_c2 = NULL;
0227 kfree(sq->dhchap_skey);
0228 sq->dhchap_skey = NULL;
0229 }
0230
0231 void nvmet_destroy_auth(struct nvmet_ctrl *ctrl)
0232 {
0233 ctrl->shash_id = 0;
0234
0235 if (ctrl->dh_tfm) {
0236 crypto_free_kpp(ctrl->dh_tfm);
0237 ctrl->dh_tfm = NULL;
0238 ctrl->dh_gid = 0;
0239 }
0240 kfree_sensitive(ctrl->dh_key);
0241 ctrl->dh_key = NULL;
0242
0243 if (ctrl->host_key) {
0244 nvme_auth_free_key(ctrl->host_key);
0245 ctrl->host_key = NULL;
0246 }
0247 if (ctrl->ctrl_key) {
0248 nvme_auth_free_key(ctrl->ctrl_key);
0249 ctrl->ctrl_key = NULL;
0250 }
0251 }
0252
0253 bool nvmet_check_auth_status(struct nvmet_req *req)
0254 {
0255 if (req->sq->ctrl->host_key &&
0256 !req->sq->authenticated)
0257 return false;
0258 return true;
0259 }
0260
0261 int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
0262 unsigned int shash_len)
0263 {
0264 struct crypto_shash *shash_tfm;
0265 struct shash_desc *shash;
0266 struct nvmet_ctrl *ctrl = req->sq->ctrl;
0267 const char *hash_name;
0268 u8 *challenge = req->sq->dhchap_c1, *host_response;
0269 u8 buf[4];
0270 int ret;
0271
0272 hash_name = nvme_auth_hmac_name(ctrl->shash_id);
0273 if (!hash_name) {
0274 pr_warn("Hash ID %d invalid\n", ctrl->shash_id);
0275 return -EINVAL;
0276 }
0277
0278 shash_tfm = crypto_alloc_shash(hash_name, 0, 0);
0279 if (IS_ERR(shash_tfm)) {
0280 pr_err("failed to allocate shash %s\n", hash_name);
0281 return PTR_ERR(shash_tfm);
0282 }
0283
0284 if (shash_len != crypto_shash_digestsize(shash_tfm)) {
0285 pr_debug("%s: hash len mismatch (len %d digest %d)\n",
0286 __func__, shash_len,
0287 crypto_shash_digestsize(shash_tfm));
0288 ret = -EINVAL;
0289 goto out_free_tfm;
0290 }
0291
0292 host_response = nvme_auth_transform_key(ctrl->host_key, ctrl->hostnqn);
0293 if (IS_ERR(host_response)) {
0294 ret = PTR_ERR(host_response);
0295 goto out_free_tfm;
0296 }
0297
0298 ret = crypto_shash_setkey(shash_tfm, host_response,
0299 ctrl->host_key->len);
0300 if (ret)
0301 goto out_free_response;
0302
0303 if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) {
0304 challenge = kmalloc(shash_len, GFP_KERNEL);
0305 if (!challenge) {
0306 ret = -ENOMEM;
0307 goto out_free_response;
0308 }
0309 ret = nvme_auth_augmented_challenge(ctrl->shash_id,
0310 req->sq->dhchap_skey,
0311 req->sq->dhchap_skey_len,
0312 req->sq->dhchap_c1,
0313 challenge, shash_len);
0314 if (ret)
0315 goto out_free_response;
0316 }
0317
0318 pr_debug("ctrl %d qid %d host response seq %u transaction %d\n",
0319 ctrl->cntlid, req->sq->qid, req->sq->dhchap_s1,
0320 req->sq->dhchap_tid);
0321
0322 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm),
0323 GFP_KERNEL);
0324 if (!shash) {
0325 ret = -ENOMEM;
0326 goto out_free_response;
0327 }
0328 shash->tfm = shash_tfm;
0329 ret = crypto_shash_init(shash);
0330 if (ret)
0331 goto out;
0332 ret = crypto_shash_update(shash, challenge, shash_len);
0333 if (ret)
0334 goto out;
0335 put_unaligned_le32(req->sq->dhchap_s1, buf);
0336 ret = crypto_shash_update(shash, buf, 4);
0337 if (ret)
0338 goto out;
0339 put_unaligned_le16(req->sq->dhchap_tid, buf);
0340 ret = crypto_shash_update(shash, buf, 2);
0341 if (ret)
0342 goto out;
0343 memset(buf, 0, 4);
0344 ret = crypto_shash_update(shash, buf, 1);
0345 if (ret)
0346 goto out;
0347 ret = crypto_shash_update(shash, "HostHost", 8);
0348 if (ret)
0349 goto out;
0350 ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn));
0351 if (ret)
0352 goto out;
0353 ret = crypto_shash_update(shash, buf, 1);
0354 if (ret)
0355 goto out;
0356 ret = crypto_shash_update(shash, ctrl->subsysnqn,
0357 strlen(ctrl->subsysnqn));
0358 if (ret)
0359 goto out;
0360 ret = crypto_shash_final(shash, response);
0361 out:
0362 if (challenge != req->sq->dhchap_c1)
0363 kfree(challenge);
0364 kfree(shash);
0365 out_free_response:
0366 kfree_sensitive(host_response);
0367 out_free_tfm:
0368 crypto_free_shash(shash_tfm);
0369 return 0;
0370 }
0371
0372 int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response,
0373 unsigned int shash_len)
0374 {
0375 struct crypto_shash *shash_tfm;
0376 struct shash_desc *shash;
0377 struct nvmet_ctrl *ctrl = req->sq->ctrl;
0378 const char *hash_name;
0379 u8 *challenge = req->sq->dhchap_c2, *ctrl_response;
0380 u8 buf[4];
0381 int ret;
0382
0383 hash_name = nvme_auth_hmac_name(ctrl->shash_id);
0384 if (!hash_name) {
0385 pr_warn("Hash ID %d invalid\n", ctrl->shash_id);
0386 return -EINVAL;
0387 }
0388
0389 shash_tfm = crypto_alloc_shash(hash_name, 0, 0);
0390 if (IS_ERR(shash_tfm)) {
0391 pr_err("failed to allocate shash %s\n", hash_name);
0392 return PTR_ERR(shash_tfm);
0393 }
0394
0395 if (shash_len != crypto_shash_digestsize(shash_tfm)) {
0396 pr_debug("%s: hash len mismatch (len %d digest %d)\n",
0397 __func__, shash_len,
0398 crypto_shash_digestsize(shash_tfm));
0399 ret = -EINVAL;
0400 goto out_free_tfm;
0401 }
0402
0403 ctrl_response = nvme_auth_transform_key(ctrl->ctrl_key,
0404 ctrl->subsysnqn);
0405 if (IS_ERR(ctrl_response)) {
0406 ret = PTR_ERR(ctrl_response);
0407 goto out_free_tfm;
0408 }
0409
0410 ret = crypto_shash_setkey(shash_tfm, ctrl_response,
0411 ctrl->ctrl_key->len);
0412 if (ret)
0413 goto out_free_response;
0414
0415 if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) {
0416 challenge = kmalloc(shash_len, GFP_KERNEL);
0417 if (!challenge) {
0418 ret = -ENOMEM;
0419 goto out_free_response;
0420 }
0421 ret = nvme_auth_augmented_challenge(ctrl->shash_id,
0422 req->sq->dhchap_skey,
0423 req->sq->dhchap_skey_len,
0424 req->sq->dhchap_c2,
0425 challenge, shash_len);
0426 if (ret)
0427 goto out_free_response;
0428 }
0429
0430 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm),
0431 GFP_KERNEL);
0432 if (!shash) {
0433 ret = -ENOMEM;
0434 goto out_free_response;
0435 }
0436 shash->tfm = shash_tfm;
0437
0438 ret = crypto_shash_init(shash);
0439 if (ret)
0440 goto out;
0441 ret = crypto_shash_update(shash, challenge, shash_len);
0442 if (ret)
0443 goto out;
0444 put_unaligned_le32(req->sq->dhchap_s2, buf);
0445 ret = crypto_shash_update(shash, buf, 4);
0446 if (ret)
0447 goto out;
0448 put_unaligned_le16(req->sq->dhchap_tid, buf);
0449 ret = crypto_shash_update(shash, buf, 2);
0450 if (ret)
0451 goto out;
0452 memset(buf, 0, 4);
0453 ret = crypto_shash_update(shash, buf, 1);
0454 if (ret)
0455 goto out;
0456 ret = crypto_shash_update(shash, "Controller", 10);
0457 if (ret)
0458 goto out;
0459 ret = crypto_shash_update(shash, ctrl->subsysnqn,
0460 strlen(ctrl->subsysnqn));
0461 if (ret)
0462 goto out;
0463 ret = crypto_shash_update(shash, buf, 1);
0464 if (ret)
0465 goto out;
0466 ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn));
0467 if (ret)
0468 goto out;
0469 ret = crypto_shash_final(shash, response);
0470 out:
0471 if (challenge != req->sq->dhchap_c2)
0472 kfree(challenge);
0473 kfree(shash);
0474 out_free_response:
0475 kfree_sensitive(ctrl_response);
0476 out_free_tfm:
0477 crypto_free_shash(shash_tfm);
0478 return 0;
0479 }
0480
0481 int nvmet_auth_ctrl_exponential(struct nvmet_req *req,
0482 u8 *buf, int buf_size)
0483 {
0484 struct nvmet_ctrl *ctrl = req->sq->ctrl;
0485 int ret = 0;
0486
0487 if (!ctrl->dh_key) {
0488 pr_warn("ctrl %d no DH public key!\n", ctrl->cntlid);
0489 return -ENOKEY;
0490 }
0491 if (buf_size != ctrl->dh_keysize) {
0492 pr_warn("ctrl %d DH public key size mismatch, need %zu is %d\n",
0493 ctrl->cntlid, ctrl->dh_keysize, buf_size);
0494 ret = -EINVAL;
0495 } else {
0496 memcpy(buf, ctrl->dh_key, buf_size);
0497 pr_debug("%s: ctrl %d public key %*ph\n", __func__,
0498 ctrl->cntlid, (int)buf_size, buf);
0499 }
0500
0501 return ret;
0502 }
0503
0504 int nvmet_auth_ctrl_sesskey(struct nvmet_req *req,
0505 u8 *pkey, int pkey_size)
0506 {
0507 struct nvmet_ctrl *ctrl = req->sq->ctrl;
0508 int ret;
0509
0510 req->sq->dhchap_skey_len = ctrl->dh_keysize;
0511 req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL);
0512 if (!req->sq->dhchap_skey)
0513 return -ENOMEM;
0514 ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm,
0515 pkey, pkey_size,
0516 req->sq->dhchap_skey,
0517 req->sq->dhchap_skey_len);
0518 if (ret)
0519 pr_debug("failed to compute shared secret, err %d\n", ret);
0520 else
0521 pr_debug("%s: shared secret %*ph\n", __func__,
0522 (int)req->sq->dhchap_skey_len,
0523 req->sq->dhchap_skey);
0524
0525 return ret;
0526 }