1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2020 Hannes Reinecke, SUSE Linux
6 #include <linux/module.h>
7 #include <linux/crc32.h>
8 #include <linux/base64.h>
9 #include <linux/prandom.h>
10 #include <linux/scatterlist.h>
11 #include <linux/unaligned.h>
12 #include <crypto/hash.h>
13 #include <crypto/dh.h>
14 #include <linux/nvme.h>
15 #include <linux/nvme-auth.h>
17 static u32 nvme_dhchap_seqnum
;
18 static DEFINE_MUTEX(nvme_dhchap_mutex
);
20 u32
nvme_auth_get_seqnum(void)
24 mutex_lock(&nvme_dhchap_mutex
);
25 if (!nvme_dhchap_seqnum
)
26 nvme_dhchap_seqnum
= get_random_u32();
29 if (!nvme_dhchap_seqnum
)
32 seqnum
= nvme_dhchap_seqnum
;
33 mutex_unlock(&nvme_dhchap_mutex
);
36 EXPORT_SYMBOL_GPL(nvme_auth_get_seqnum
);
38 static struct nvme_auth_dhgroup_map
{
42 [NVME_AUTH_DHGROUP_NULL
] = {
43 .name
= "null", .kpp
= "null" },
44 [NVME_AUTH_DHGROUP_2048
] = {
45 .name
= "ffdhe2048", .kpp
= "ffdhe2048(dh)" },
46 [NVME_AUTH_DHGROUP_3072
] = {
47 .name
= "ffdhe3072", .kpp
= "ffdhe3072(dh)" },
48 [NVME_AUTH_DHGROUP_4096
] = {
49 .name
= "ffdhe4096", .kpp
= "ffdhe4096(dh)" },
50 [NVME_AUTH_DHGROUP_6144
] = {
51 .name
= "ffdhe6144", .kpp
= "ffdhe6144(dh)" },
52 [NVME_AUTH_DHGROUP_8192
] = {
53 .name
= "ffdhe8192", .kpp
= "ffdhe8192(dh)" },
56 const char *nvme_auth_dhgroup_name(u8 dhgroup_id
)
58 if (dhgroup_id
>= ARRAY_SIZE(dhgroup_map
))
60 return dhgroup_map
[dhgroup_id
].name
;
62 EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_name
);
64 const char *nvme_auth_dhgroup_kpp(u8 dhgroup_id
)
66 if (dhgroup_id
>= ARRAY_SIZE(dhgroup_map
))
68 return dhgroup_map
[dhgroup_id
].kpp
;
70 EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_kpp
);
72 u8
nvme_auth_dhgroup_id(const char *dhgroup_name
)
76 if (!dhgroup_name
|| !strlen(dhgroup_name
))
77 return NVME_AUTH_DHGROUP_INVALID
;
78 for (i
= 0; i
< ARRAY_SIZE(dhgroup_map
); i
++) {
79 if (!strlen(dhgroup_map
[i
].name
))
81 if (!strncmp(dhgroup_map
[i
].name
, dhgroup_name
,
82 strlen(dhgroup_map
[i
].name
)))
85 return NVME_AUTH_DHGROUP_INVALID
;
87 EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_id
);
89 static struct nvme_dhchap_hash_map
{
94 [NVME_AUTH_HASH_SHA256
] = {
96 .hmac
= "hmac(sha256)",
99 [NVME_AUTH_HASH_SHA384
] = {
101 .hmac
= "hmac(sha384)",
104 [NVME_AUTH_HASH_SHA512
] = {
106 .hmac
= "hmac(sha512)",
111 const char *nvme_auth_hmac_name(u8 hmac_id
)
113 if (hmac_id
>= ARRAY_SIZE(hash_map
))
115 return hash_map
[hmac_id
].hmac
;
117 EXPORT_SYMBOL_GPL(nvme_auth_hmac_name
);
119 const char *nvme_auth_digest_name(u8 hmac_id
)
121 if (hmac_id
>= ARRAY_SIZE(hash_map
))
123 return hash_map
[hmac_id
].digest
;
125 EXPORT_SYMBOL_GPL(nvme_auth_digest_name
);
127 u8
nvme_auth_hmac_id(const char *hmac_name
)
131 if (!hmac_name
|| !strlen(hmac_name
))
132 return NVME_AUTH_HASH_INVALID
;
134 for (i
= 0; i
< ARRAY_SIZE(hash_map
); i
++) {
135 if (!strlen(hash_map
[i
].hmac
))
137 if (!strncmp(hash_map
[i
].hmac
, hmac_name
,
138 strlen(hash_map
[i
].hmac
)))
141 return NVME_AUTH_HASH_INVALID
;
143 EXPORT_SYMBOL_GPL(nvme_auth_hmac_id
);
145 size_t nvme_auth_hmac_hash_len(u8 hmac_id
)
147 if (hmac_id
>= ARRAY_SIZE(hash_map
))
149 return hash_map
[hmac_id
].len
;
151 EXPORT_SYMBOL_GPL(nvme_auth_hmac_hash_len
);
153 u32
nvme_auth_key_struct_size(u32 key_len
)
155 struct nvme_dhchap_key key
;
157 return struct_size(&key
, key
, key_len
);
159 EXPORT_SYMBOL_GPL(nvme_auth_key_struct_size
);
161 struct nvme_dhchap_key
*nvme_auth_extract_key(unsigned char *secret
,
164 struct nvme_dhchap_key
*key
;
168 size_t allocated_len
= strlen(secret
);
170 /* Secret might be affixed with a ':' */
171 p
= strrchr(secret
, ':');
173 allocated_len
= p
- secret
;
174 key
= nvme_auth_alloc_key(allocated_len
, 0);
176 return ERR_PTR(-ENOMEM
);
178 key_len
= base64_decode(secret
, allocated_len
, key
->key
);
180 pr_debug("base64 key decoding error %d\n",
183 goto out_free_secret
;
186 if (key_len
!= 36 && key_len
!= 52 &&
188 pr_err("Invalid key len %d\n", key_len
);
190 goto out_free_secret
;
193 /* The last four bytes is the CRC in little-endian format */
196 * The linux implementation doesn't do pre- and post-increments,
197 * so we have to do it manually.
199 crc
= ~crc32(~0, key
->key
, key_len
);
201 if (get_unaligned_le32(key
->key
+ key_len
) != crc
) {
202 pr_err("key crc mismatch (key %08x, crc %08x)\n",
203 get_unaligned_le32(key
->key
+ key_len
), crc
);
205 goto out_free_secret
;
208 key
->hash
= key_hash
;
211 nvme_auth_free_key(key
);
214 EXPORT_SYMBOL_GPL(nvme_auth_extract_key
);
216 struct nvme_dhchap_key
*nvme_auth_alloc_key(u32 len
, u8 hash
)
218 u32 num_bytes
= nvme_auth_key_struct_size(len
);
219 struct nvme_dhchap_key
*key
= kzalloc(num_bytes
, GFP_KERNEL
);
227 EXPORT_SYMBOL_GPL(nvme_auth_alloc_key
);
229 void nvme_auth_free_key(struct nvme_dhchap_key
*key
)
233 kfree_sensitive(key
);
235 EXPORT_SYMBOL_GPL(nvme_auth_free_key
);
237 struct nvme_dhchap_key
*nvme_auth_transform_key(
238 struct nvme_dhchap_key
*key
, char *nqn
)
240 const char *hmac_name
;
241 struct crypto_shash
*key_tfm
;
242 struct shash_desc
*shash
;
243 struct nvme_dhchap_key
*transformed_key
;
247 pr_warn("No key specified\n");
248 return ERR_PTR(-ENOKEY
);
250 if (key
->hash
== 0) {
251 key_len
= nvme_auth_key_struct_size(key
->len
);
252 transformed_key
= kmemdup(key
, key_len
, GFP_KERNEL
);
253 if (!transformed_key
)
254 return ERR_PTR(-ENOMEM
);
255 return transformed_key
;
257 hmac_name
= nvme_auth_hmac_name(key
->hash
);
259 pr_warn("Invalid key hash id %d\n", key
->hash
);
260 return ERR_PTR(-EINVAL
);
263 key_tfm
= crypto_alloc_shash(hmac_name
, 0, 0);
265 return ERR_CAST(key_tfm
);
267 shash
= kmalloc(sizeof(struct shash_desc
) +
268 crypto_shash_descsize(key_tfm
),
275 key_len
= crypto_shash_digestsize(key_tfm
);
276 transformed_key
= nvme_auth_alloc_key(key_len
, key
->hash
);
277 if (!transformed_key
) {
282 shash
->tfm
= key_tfm
;
283 ret
= crypto_shash_setkey(key_tfm
, key
->key
, key
->len
);
285 goto out_free_transformed_key
;
286 ret
= crypto_shash_init(shash
);
288 goto out_free_transformed_key
;
289 ret
= crypto_shash_update(shash
, nqn
, strlen(nqn
));
291 goto out_free_transformed_key
;
292 ret
= crypto_shash_update(shash
, "NVMe-over-Fabrics", 17);
294 goto out_free_transformed_key
;
295 ret
= crypto_shash_final(shash
, transformed_key
->key
);
297 goto out_free_transformed_key
;
300 crypto_free_shash(key_tfm
);
302 return transformed_key
;
304 out_free_transformed_key
:
305 nvme_auth_free_key(transformed_key
);
309 crypto_free_shash(key_tfm
);
313 EXPORT_SYMBOL_GPL(nvme_auth_transform_key
);
315 static int nvme_auth_hash_skey(int hmac_id
, u8
*skey
, size_t skey_len
, u8
*hkey
)
317 const char *digest_name
;
318 struct crypto_shash
*tfm
;
321 digest_name
= nvme_auth_digest_name(hmac_id
);
323 pr_debug("%s: failed to get digest for %d\n", __func__
,
327 tfm
= crypto_alloc_shash(digest_name
, 0, 0);
331 ret
= crypto_shash_tfm_digest(tfm
, skey
, skey_len
, hkey
);
333 pr_debug("%s: Failed to hash digest len %zu\n", __func__
,
336 crypto_free_shash(tfm
);
340 int nvme_auth_augmented_challenge(u8 hmac_id
, u8
*skey
, size_t skey_len
,
341 u8
*challenge
, u8
*aug
, size_t hlen
)
343 struct crypto_shash
*tfm
;
345 const char *hmac_name
;
348 hashed_key
= kmalloc(hlen
, GFP_KERNEL
);
352 ret
= nvme_auth_hash_skey(hmac_id
, skey
,
353 skey_len
, hashed_key
);
357 hmac_name
= nvme_auth_hmac_name(hmac_id
);
359 pr_warn("%s: invalid hash algorithm %d\n",
365 tfm
= crypto_alloc_shash(hmac_name
, 0, 0);
371 ret
= crypto_shash_setkey(tfm
, hashed_key
, hlen
);
375 ret
= crypto_shash_tfm_digest(tfm
, challenge
, hlen
, aug
);
377 crypto_free_shash(tfm
);
379 kfree_sensitive(hashed_key
);
382 EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge
);
384 int nvme_auth_gen_privkey(struct crypto_kpp
*dh_tfm
, u8 dh_gid
)
388 ret
= crypto_kpp_set_secret(dh_tfm
, NULL
, 0);
390 pr_debug("failed to set private key, error %d\n", ret
);
394 EXPORT_SYMBOL_GPL(nvme_auth_gen_privkey
);
396 int nvme_auth_gen_pubkey(struct crypto_kpp
*dh_tfm
,
397 u8
*host_key
, size_t host_key_len
)
399 struct kpp_request
*req
;
400 struct crypto_wait wait
;
401 struct scatterlist dst
;
404 req
= kpp_request_alloc(dh_tfm
, GFP_KERNEL
);
408 crypto_init_wait(&wait
);
409 kpp_request_set_input(req
, NULL
, 0);
410 sg_init_one(&dst
, host_key
, host_key_len
);
411 kpp_request_set_output(req
, &dst
, host_key_len
);
412 kpp_request_set_callback(req
, CRYPTO_TFM_REQ_MAY_BACKLOG
,
413 crypto_req_done
, &wait
);
415 ret
= crypto_wait_req(crypto_kpp_generate_public_key(req
), &wait
);
416 kpp_request_free(req
);
419 EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey
);
421 int nvme_auth_gen_shared_secret(struct crypto_kpp
*dh_tfm
,
422 u8
*ctrl_key
, size_t ctrl_key_len
,
423 u8
*sess_key
, size_t sess_key_len
)
425 struct kpp_request
*req
;
426 struct crypto_wait wait
;
427 struct scatterlist src
, dst
;
430 req
= kpp_request_alloc(dh_tfm
, GFP_KERNEL
);
434 crypto_init_wait(&wait
);
435 sg_init_one(&src
, ctrl_key
, ctrl_key_len
);
436 kpp_request_set_input(req
, &src
, ctrl_key_len
);
437 sg_init_one(&dst
, sess_key
, sess_key_len
);
438 kpp_request_set_output(req
, &dst
, sess_key_len
);
439 kpp_request_set_callback(req
, CRYPTO_TFM_REQ_MAY_BACKLOG
,
440 crypto_req_done
, &wait
);
442 ret
= crypto_wait_req(crypto_kpp_compute_shared_secret(req
), &wait
);
444 kpp_request_free(req
);
447 EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret
);
449 int nvme_auth_generate_key(u8
*secret
, struct nvme_dhchap_key
**ret_key
)
451 struct nvme_dhchap_key
*key
;
459 if (sscanf(secret
, "DHHC-1:%hhd:%*s:", &key_hash
) != 1)
462 /* Pass in the secret without the 'DHHC-1:XX:' prefix */
463 key
= nvme_auth_extract_key(secret
+ 10, key_hash
);
472 EXPORT_SYMBOL_GPL(nvme_auth_generate_key
);
474 MODULE_DESCRIPTION("NVMe Authentication framework");
475 MODULE_LICENSE("GPL v2");