]> Git Repo - linux.git/blob - drivers/nvme/target/auth.c
dma-mapping: don't return errors from dma_set_max_seg_size
[linux.git] / drivers / nvme / target / auth.c
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         down_write(&nvmet_config_sem);
48         if (set_ctrl) {
49                 kfree(host->dhchap_ctrl_secret);
50                 host->dhchap_ctrl_secret = strim(dhchap_secret);
51                 host->dhchap_ctrl_key_hash = key_hash;
52         } else {
53                 kfree(host->dhchap_secret);
54                 host->dhchap_secret = strim(dhchap_secret);
55                 host->dhchap_key_hash = key_hash;
56         }
57         up_write(&nvmet_config_sem);
58         return 0;
59 }
60
61 int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id)
62 {
63         const char *dhgroup_kpp;
64         int ret = 0;
65
66         pr_debug("%s: ctrl %d selecting dhgroup %d\n",
67                  __func__, ctrl->cntlid, dhgroup_id);
68
69         if (ctrl->dh_tfm) {
70                 if (ctrl->dh_gid == dhgroup_id) {
71                         pr_debug("%s: ctrl %d reuse existing DH group %d\n",
72                                  __func__, ctrl->cntlid, dhgroup_id);
73                         return 0;
74                 }
75                 crypto_free_kpp(ctrl->dh_tfm);
76                 ctrl->dh_tfm = NULL;
77                 ctrl->dh_gid = 0;
78         }
79
80         if (dhgroup_id == NVME_AUTH_DHGROUP_NULL)
81                 return 0;
82
83         dhgroup_kpp = nvme_auth_dhgroup_kpp(dhgroup_id);
84         if (!dhgroup_kpp) {
85                 pr_debug("%s: ctrl %d invalid DH group %d\n",
86                          __func__, ctrl->cntlid, dhgroup_id);
87                 return -EINVAL;
88         }
89         ctrl->dh_tfm = crypto_alloc_kpp(dhgroup_kpp, 0, 0);
90         if (IS_ERR(ctrl->dh_tfm)) {
91                 pr_debug("%s: ctrl %d failed to setup DH group %d, err %ld\n",
92                          __func__, ctrl->cntlid, dhgroup_id,
93                          PTR_ERR(ctrl->dh_tfm));
94                 ret = PTR_ERR(ctrl->dh_tfm);
95                 ctrl->dh_tfm = NULL;
96                 ctrl->dh_gid = 0;
97         } else {
98                 ctrl->dh_gid = dhgroup_id;
99                 pr_debug("%s: ctrl %d setup DH group %d\n",
100                          __func__, ctrl->cntlid, ctrl->dh_gid);
101                 ret = nvme_auth_gen_privkey(ctrl->dh_tfm, ctrl->dh_gid);
102                 if (ret < 0) {
103                         pr_debug("%s: ctrl %d failed to generate private key, err %d\n",
104                                  __func__, ctrl->cntlid, ret);
105                         kfree_sensitive(ctrl->dh_key);
106                         return ret;
107                 }
108                 ctrl->dh_keysize = crypto_kpp_maxsize(ctrl->dh_tfm);
109                 kfree_sensitive(ctrl->dh_key);
110                 ctrl->dh_key = kzalloc(ctrl->dh_keysize, GFP_KERNEL);
111                 if (!ctrl->dh_key) {
112                         pr_warn("ctrl %d failed to allocate public key\n",
113                                 ctrl->cntlid);
114                         return -ENOMEM;
115                 }
116                 ret = nvme_auth_gen_pubkey(ctrl->dh_tfm, ctrl->dh_key,
117                                            ctrl->dh_keysize);
118                 if (ret < 0) {
119                         pr_warn("ctrl %d failed to generate public key\n",
120                                 ctrl->cntlid);
121                         kfree(ctrl->dh_key);
122                         ctrl->dh_key = NULL;
123                 }
124         }
125
126         return ret;
127 }
128
129 u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl)
130 {
131         int ret = 0;
132         struct nvmet_host_link *p;
133         struct nvmet_host *host = NULL;
134
135         down_read(&nvmet_config_sem);
136         if (nvmet_is_disc_subsys(ctrl->subsys))
137                 goto out_unlock;
138
139         if (ctrl->subsys->allow_any_host)
140                 goto out_unlock;
141
142         list_for_each_entry(p, &ctrl->subsys->hosts, entry) {
143                 pr_debug("check %s\n", nvmet_host_name(p->host));
144                 if (strcmp(nvmet_host_name(p->host), ctrl->hostnqn))
145                         continue;
146                 host = p->host;
147                 break;
148         }
149         if (!host) {
150                 pr_debug("host %s not found\n", ctrl->hostnqn);
151                 ret = NVME_AUTH_DHCHAP_FAILURE_FAILED;
152                 goto out_unlock;
153         }
154
155         ret = nvmet_setup_dhgroup(ctrl, host->dhchap_dhgroup_id);
156         if (ret < 0) {
157                 pr_warn("Failed to setup DH group");
158                 ret = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE;
159                 goto out_unlock;
160         }
161
162         if (!host->dhchap_secret) {
163                 pr_debug("No authentication provided\n");
164                 goto out_unlock;
165         }
166
167         if (host->dhchap_hash_id == ctrl->shash_id) {
168                 pr_debug("Re-use existing hash ID %d\n",
169                          ctrl->shash_id);
170         } else {
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 = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE;
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 = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE;
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;
269         struct nvme_dhchap_key *transformed_key;
270         u8 buf[4];
271         int ret;
272
273         hash_name = nvme_auth_hmac_name(ctrl->shash_id);
274         if (!hash_name) {
275                 pr_warn("Hash ID %d invalid\n", ctrl->shash_id);
276                 return -EINVAL;
277         }
278
279         shash_tfm = crypto_alloc_shash(hash_name, 0, 0);
280         if (IS_ERR(shash_tfm)) {
281                 pr_err("failed to allocate shash %s\n", hash_name);
282                 return PTR_ERR(shash_tfm);
283         }
284
285         if (shash_len != crypto_shash_digestsize(shash_tfm)) {
286                 pr_err("%s: hash len mismatch (len %d digest %d)\n",
287                         __func__, shash_len,
288                         crypto_shash_digestsize(shash_tfm));
289                 ret = -EINVAL;
290                 goto out_free_tfm;
291         }
292
293         transformed_key = nvme_auth_transform_key(ctrl->host_key,
294                                                   ctrl->hostnqn);
295         if (IS_ERR(transformed_key)) {
296                 ret = PTR_ERR(transformed_key);
297                 goto out_free_tfm;
298         }
299
300         ret = crypto_shash_setkey(shash_tfm, transformed_key->key,
301                                   transformed_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_challenge;
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_challenge;
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         kfree(shash);
365 out_free_challenge:
366         if (challenge != req->sq->dhchap_c1)
367                 kfree(challenge);
368 out_free_response:
369         nvme_auth_free_key(transformed_key);
370 out_free_tfm:
371         crypto_free_shash(shash_tfm);
372         return ret;
373 }
374
375 int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response,
376                          unsigned int shash_len)
377 {
378         struct crypto_shash *shash_tfm;
379         struct shash_desc *shash;
380         struct nvmet_ctrl *ctrl = req->sq->ctrl;
381         const char *hash_name;
382         u8 *challenge = req->sq->dhchap_c2;
383         struct nvme_dhchap_key *transformed_key;
384         u8 buf[4];
385         int ret;
386
387         hash_name = nvme_auth_hmac_name(ctrl->shash_id);
388         if (!hash_name) {
389                 pr_warn("Hash ID %d invalid\n", ctrl->shash_id);
390                 return -EINVAL;
391         }
392
393         shash_tfm = crypto_alloc_shash(hash_name, 0, 0);
394         if (IS_ERR(shash_tfm)) {
395                 pr_err("failed to allocate shash %s\n", hash_name);
396                 return PTR_ERR(shash_tfm);
397         }
398
399         if (shash_len != crypto_shash_digestsize(shash_tfm)) {
400                 pr_debug("%s: hash len mismatch (len %d digest %d)\n",
401                          __func__, shash_len,
402                          crypto_shash_digestsize(shash_tfm));
403                 ret = -EINVAL;
404                 goto out_free_tfm;
405         }
406
407         transformed_key = nvme_auth_transform_key(ctrl->ctrl_key,
408                                                 ctrl->subsysnqn);
409         if (IS_ERR(transformed_key)) {
410                 ret = PTR_ERR(transformed_key);
411                 goto out_free_tfm;
412         }
413
414         ret = crypto_shash_setkey(shash_tfm, transformed_key->key,
415                                   transformed_key->len);
416         if (ret)
417                 goto out_free_response;
418
419         if (ctrl->dh_gid != NVME_AUTH_DHGROUP_NULL) {
420                 challenge = kmalloc(shash_len, GFP_KERNEL);
421                 if (!challenge) {
422                         ret = -ENOMEM;
423                         goto out_free_response;
424                 }
425                 ret = nvme_auth_augmented_challenge(ctrl->shash_id,
426                                                     req->sq->dhchap_skey,
427                                                     req->sq->dhchap_skey_len,
428                                                     req->sq->dhchap_c2,
429                                                     challenge, shash_len);
430                 if (ret)
431                         goto out_free_challenge;
432         }
433
434         shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(shash_tfm),
435                         GFP_KERNEL);
436         if (!shash) {
437                 ret = -ENOMEM;
438                 goto out_free_challenge;
439         }
440         shash->tfm = shash_tfm;
441
442         ret = crypto_shash_init(shash);
443         if (ret)
444                 goto out;
445         ret = crypto_shash_update(shash, challenge, shash_len);
446         if (ret)
447                 goto out;
448         put_unaligned_le32(req->sq->dhchap_s2, buf);
449         ret = crypto_shash_update(shash, buf, 4);
450         if (ret)
451                 goto out;
452         put_unaligned_le16(req->sq->dhchap_tid, buf);
453         ret = crypto_shash_update(shash, buf, 2);
454         if (ret)
455                 goto out;
456         memset(buf, 0, 4);
457         ret = crypto_shash_update(shash, buf, 1);
458         if (ret)
459                 goto out;
460         ret = crypto_shash_update(shash, "Controller", 10);
461         if (ret)
462                 goto out;
463         ret = crypto_shash_update(shash, ctrl->subsysnqn,
464                             strlen(ctrl->subsysnqn));
465         if (ret)
466                 goto out;
467         ret = crypto_shash_update(shash, buf, 1);
468         if (ret)
469                 goto out;
470         ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn));
471         if (ret)
472                 goto out;
473         ret = crypto_shash_final(shash, response);
474 out:
475         kfree(shash);
476 out_free_challenge:
477         if (challenge != req->sq->dhchap_c2)
478                 kfree(challenge);
479 out_free_response:
480         nvme_auth_free_key(transformed_key);
481 out_free_tfm:
482         crypto_free_shash(shash_tfm);
483         return ret;
484 }
485
486 int nvmet_auth_ctrl_exponential(struct nvmet_req *req,
487                                 u8 *buf, int buf_size)
488 {
489         struct nvmet_ctrl *ctrl = req->sq->ctrl;
490         int ret = 0;
491
492         if (!ctrl->dh_key) {
493                 pr_warn("ctrl %d no DH public key!\n", ctrl->cntlid);
494                 return -ENOKEY;
495         }
496         if (buf_size != ctrl->dh_keysize) {
497                 pr_warn("ctrl %d DH public key size mismatch, need %zu is %d\n",
498                         ctrl->cntlid, ctrl->dh_keysize, buf_size);
499                 ret = -EINVAL;
500         } else {
501                 memcpy(buf, ctrl->dh_key, buf_size);
502                 pr_debug("%s: ctrl %d public key %*ph\n", __func__,
503                          ctrl->cntlid, (int)buf_size, buf);
504         }
505
506         return ret;
507 }
508
509 int nvmet_auth_ctrl_sesskey(struct nvmet_req *req,
510                             u8 *pkey, int pkey_size)
511 {
512         struct nvmet_ctrl *ctrl = req->sq->ctrl;
513         int ret;
514
515         req->sq->dhchap_skey_len = ctrl->dh_keysize;
516         req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL);
517         if (!req->sq->dhchap_skey)
518                 return -ENOMEM;
519         ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm,
520                                           pkey, pkey_size,
521                                           req->sq->dhchap_skey,
522                                           req->sq->dhchap_skey_len);
523         if (ret)
524                 pr_debug("failed to compute shared secret, err %d\n", ret);
525         else
526                 pr_debug("%s: shared secret %*ph\n", __func__,
527                          (int)req->sq->dhchap_skey_len,
528                          req->sq->dhchap_skey);
529
530         return ret;
531 }
This page took 0.062294 seconds and 4 git commands to generate.