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
nvmet_auth_set_key(struct nvmet_host * host,const char * secret,bool set_ctrl)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
nvmet_setup_dhgroup(struct nvmet_ctrl * ctrl,u8 dhgroup_id)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
nvmet_setup_auth(struct nvmet_ctrl * ctrl)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
nvmet_auth_sq_free(struct nvmet_sq * sq)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
nvmet_destroy_auth(struct nvmet_ctrl * ctrl)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
nvmet_check_auth_status(struct nvmet_req * req)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
nvmet_auth_host_hash(struct nvmet_req * req,u8 * response,unsigned int shash_len)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
nvmet_auth_ctrl_hash(struct nvmet_req * req,u8 * response,unsigned int shash_len)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
nvmet_auth_ctrl_exponential(struct nvmet_req * req,u8 * buf,int buf_size)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
nvmet_auth_ctrl_sesskey(struct nvmet_req * req,u8 * pkey,int pkey_size)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