1f50fff73SHannes Reinecke // SPDX-License-Identifier: GPL-2.0
2f50fff73SHannes Reinecke /*
3f50fff73SHannes Reinecke * Copyright (c) 2020 Hannes Reinecke, SUSE Linux
4f50fff73SHannes Reinecke */
5f50fff73SHannes Reinecke
6f50fff73SHannes Reinecke #include <linux/module.h>
7f50fff73SHannes Reinecke #include <linux/crc32.h>
8f50fff73SHannes Reinecke #include <linux/base64.h>
9f50fff73SHannes Reinecke #include <linux/prandom.h>
10f50fff73SHannes Reinecke #include <linux/scatterlist.h>
11f50fff73SHannes Reinecke #include <asm/unaligned.h>
12f50fff73SHannes Reinecke #include <crypto/hash.h>
13f50fff73SHannes Reinecke #include <crypto/dh.h>
14f50fff73SHannes Reinecke #include <linux/nvme.h>
15f50fff73SHannes Reinecke #include <linux/nvme-auth.h>
16f50fff73SHannes Reinecke
17f50fff73SHannes Reinecke static u32 nvme_dhchap_seqnum;
18f50fff73SHannes Reinecke static DEFINE_MUTEX(nvme_dhchap_mutex);
19f50fff73SHannes Reinecke
nvme_auth_get_seqnum(void)20f50fff73SHannes Reinecke u32 nvme_auth_get_seqnum(void)
21f50fff73SHannes Reinecke {
22f50fff73SHannes Reinecke u32 seqnum;
23f50fff73SHannes Reinecke
24f50fff73SHannes Reinecke mutex_lock(&nvme_dhchap_mutex);
25f50fff73SHannes Reinecke if (!nvme_dhchap_seqnum)
26*a251c17aSJason A. Donenfeld nvme_dhchap_seqnum = get_random_u32();
27f50fff73SHannes Reinecke else {
28f50fff73SHannes Reinecke nvme_dhchap_seqnum++;
29f50fff73SHannes Reinecke if (!nvme_dhchap_seqnum)
30f50fff73SHannes Reinecke nvme_dhchap_seqnum++;
31f50fff73SHannes Reinecke }
32f50fff73SHannes Reinecke seqnum = nvme_dhchap_seqnum;
33f50fff73SHannes Reinecke mutex_unlock(&nvme_dhchap_mutex);
34f50fff73SHannes Reinecke return seqnum;
35f50fff73SHannes Reinecke }
36f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_get_seqnum);
37f50fff73SHannes Reinecke
38f50fff73SHannes Reinecke static struct nvme_auth_dhgroup_map {
39f50fff73SHannes Reinecke const char name[16];
40f50fff73SHannes Reinecke const char kpp[16];
41f50fff73SHannes Reinecke } dhgroup_map[] = {
42f50fff73SHannes Reinecke [NVME_AUTH_DHGROUP_NULL] = {
43f50fff73SHannes Reinecke .name = "null", .kpp = "null" },
44f50fff73SHannes Reinecke [NVME_AUTH_DHGROUP_2048] = {
45f50fff73SHannes Reinecke .name = "ffdhe2048", .kpp = "ffdhe2048(dh)" },
46f50fff73SHannes Reinecke [NVME_AUTH_DHGROUP_3072] = {
47f50fff73SHannes Reinecke .name = "ffdhe3072", .kpp = "ffdhe3072(dh)" },
48f50fff73SHannes Reinecke [NVME_AUTH_DHGROUP_4096] = {
49f50fff73SHannes Reinecke .name = "ffdhe4096", .kpp = "ffdhe4096(dh)" },
50f50fff73SHannes Reinecke [NVME_AUTH_DHGROUP_6144] = {
51f50fff73SHannes Reinecke .name = "ffdhe6144", .kpp = "ffdhe6144(dh)" },
52f50fff73SHannes Reinecke [NVME_AUTH_DHGROUP_8192] = {
53f50fff73SHannes Reinecke .name = "ffdhe8192", .kpp = "ffdhe8192(dh)" },
54f50fff73SHannes Reinecke };
55f50fff73SHannes Reinecke
nvme_auth_dhgroup_name(u8 dhgroup_id)56f50fff73SHannes Reinecke const char *nvme_auth_dhgroup_name(u8 dhgroup_id)
57f50fff73SHannes Reinecke {
584daf7fa0SDan Carpenter if (dhgroup_id >= ARRAY_SIZE(dhgroup_map))
59f50fff73SHannes Reinecke return NULL;
60f50fff73SHannes Reinecke return dhgroup_map[dhgroup_id].name;
61f50fff73SHannes Reinecke }
62f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_name);
63f50fff73SHannes Reinecke
nvme_auth_dhgroup_kpp(u8 dhgroup_id)64f50fff73SHannes Reinecke const char *nvme_auth_dhgroup_kpp(u8 dhgroup_id)
65f50fff73SHannes Reinecke {
664daf7fa0SDan Carpenter if (dhgroup_id >= ARRAY_SIZE(dhgroup_map))
67f50fff73SHannes Reinecke return NULL;
68f50fff73SHannes Reinecke return dhgroup_map[dhgroup_id].kpp;
69f50fff73SHannes Reinecke }
70f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_kpp);
71f50fff73SHannes Reinecke
nvme_auth_dhgroup_id(const char * dhgroup_name)72f50fff73SHannes Reinecke u8 nvme_auth_dhgroup_id(const char *dhgroup_name)
73f50fff73SHannes Reinecke {
74f50fff73SHannes Reinecke int i;
75f50fff73SHannes Reinecke
76f50fff73SHannes Reinecke if (!dhgroup_name || !strlen(dhgroup_name))
77f50fff73SHannes Reinecke return NVME_AUTH_DHGROUP_INVALID;
78f50fff73SHannes Reinecke for (i = 0; i < ARRAY_SIZE(dhgroup_map); i++) {
79f50fff73SHannes Reinecke if (!strlen(dhgroup_map[i].name))
80f50fff73SHannes Reinecke continue;
81f50fff73SHannes Reinecke if (!strncmp(dhgroup_map[i].name, dhgroup_name,
82f50fff73SHannes Reinecke strlen(dhgroup_map[i].name)))
83f50fff73SHannes Reinecke return i;
84f50fff73SHannes Reinecke }
85f50fff73SHannes Reinecke return NVME_AUTH_DHGROUP_INVALID;
86f50fff73SHannes Reinecke }
87f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_dhgroup_id);
88f50fff73SHannes Reinecke
89f50fff73SHannes Reinecke static struct nvme_dhchap_hash_map {
90f50fff73SHannes Reinecke int len;
91f50fff73SHannes Reinecke const char hmac[15];
92f50fff73SHannes Reinecke const char digest[8];
93f50fff73SHannes Reinecke } hash_map[] = {
94f50fff73SHannes Reinecke [NVME_AUTH_HASH_SHA256] = {
95f50fff73SHannes Reinecke .len = 32,
96f50fff73SHannes Reinecke .hmac = "hmac(sha256)",
97f50fff73SHannes Reinecke .digest = "sha256",
98f50fff73SHannes Reinecke },
99f50fff73SHannes Reinecke [NVME_AUTH_HASH_SHA384] = {
100f50fff73SHannes Reinecke .len = 48,
101f50fff73SHannes Reinecke .hmac = "hmac(sha384)",
102f50fff73SHannes Reinecke .digest = "sha384",
103f50fff73SHannes Reinecke },
104f50fff73SHannes Reinecke [NVME_AUTH_HASH_SHA512] = {
105f50fff73SHannes Reinecke .len = 64,
106f50fff73SHannes Reinecke .hmac = "hmac(sha512)",
107f50fff73SHannes Reinecke .digest = "sha512",
108f50fff73SHannes Reinecke },
109f50fff73SHannes Reinecke };
110f50fff73SHannes Reinecke
nvme_auth_hmac_name(u8 hmac_id)111f50fff73SHannes Reinecke const char *nvme_auth_hmac_name(u8 hmac_id)
112f50fff73SHannes Reinecke {
1134daf7fa0SDan Carpenter if (hmac_id >= ARRAY_SIZE(hash_map))
114f50fff73SHannes Reinecke return NULL;
115f50fff73SHannes Reinecke return hash_map[hmac_id].hmac;
116f50fff73SHannes Reinecke }
117f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_hmac_name);
118f50fff73SHannes Reinecke
nvme_auth_digest_name(u8 hmac_id)119f50fff73SHannes Reinecke const char *nvme_auth_digest_name(u8 hmac_id)
120f50fff73SHannes Reinecke {
1214daf7fa0SDan Carpenter if (hmac_id >= ARRAY_SIZE(hash_map))
122f50fff73SHannes Reinecke return NULL;
123f50fff73SHannes Reinecke return hash_map[hmac_id].digest;
124f50fff73SHannes Reinecke }
125f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_digest_name);
126f50fff73SHannes Reinecke
nvme_auth_hmac_id(const char * hmac_name)127f50fff73SHannes Reinecke u8 nvme_auth_hmac_id(const char *hmac_name)
128f50fff73SHannes Reinecke {
129f50fff73SHannes Reinecke int i;
130f50fff73SHannes Reinecke
131f50fff73SHannes Reinecke if (!hmac_name || !strlen(hmac_name))
132f50fff73SHannes Reinecke return NVME_AUTH_HASH_INVALID;
133f50fff73SHannes Reinecke
134f50fff73SHannes Reinecke for (i = 0; i < ARRAY_SIZE(hash_map); i++) {
135f50fff73SHannes Reinecke if (!strlen(hash_map[i].hmac))
136f50fff73SHannes Reinecke continue;
137f50fff73SHannes Reinecke if (!strncmp(hash_map[i].hmac, hmac_name,
138f50fff73SHannes Reinecke strlen(hash_map[i].hmac)))
139f50fff73SHannes Reinecke return i;
140f50fff73SHannes Reinecke }
141f50fff73SHannes Reinecke return NVME_AUTH_HASH_INVALID;
142f50fff73SHannes Reinecke }
143f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_hmac_id);
144f50fff73SHannes Reinecke
nvme_auth_hmac_hash_len(u8 hmac_id)145f50fff73SHannes Reinecke size_t nvme_auth_hmac_hash_len(u8 hmac_id)
146f50fff73SHannes Reinecke {
1474daf7fa0SDan Carpenter if (hmac_id >= ARRAY_SIZE(hash_map))
148f50fff73SHannes Reinecke return 0;
149f50fff73SHannes Reinecke return hash_map[hmac_id].len;
150f50fff73SHannes Reinecke }
151f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_hmac_hash_len);
152f50fff73SHannes Reinecke
nvme_auth_extract_key(unsigned char * secret,u8 key_hash)153f50fff73SHannes Reinecke struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
154f50fff73SHannes Reinecke u8 key_hash)
155f50fff73SHannes Reinecke {
156f50fff73SHannes Reinecke struct nvme_dhchap_key *key;
157f50fff73SHannes Reinecke unsigned char *p;
158f50fff73SHannes Reinecke u32 crc;
159f50fff73SHannes Reinecke int ret, key_len;
160f50fff73SHannes Reinecke size_t allocated_len = strlen(secret);
161f50fff73SHannes Reinecke
162f50fff73SHannes Reinecke /* Secret might be affixed with a ':' */
163f50fff73SHannes Reinecke p = strrchr(secret, ':');
164f50fff73SHannes Reinecke if (p)
165f50fff73SHannes Reinecke allocated_len = p - secret;
166f50fff73SHannes Reinecke key = kzalloc(sizeof(*key), GFP_KERNEL);
167f50fff73SHannes Reinecke if (!key)
168f50fff73SHannes Reinecke return ERR_PTR(-ENOMEM);
169f50fff73SHannes Reinecke key->key = kzalloc(allocated_len, GFP_KERNEL);
170f50fff73SHannes Reinecke if (!key->key) {
171f50fff73SHannes Reinecke ret = -ENOMEM;
172f50fff73SHannes Reinecke goto out_free_key;
173f50fff73SHannes Reinecke }
174f50fff73SHannes Reinecke
175f50fff73SHannes Reinecke key_len = base64_decode(secret, allocated_len, key->key);
176f50fff73SHannes Reinecke if (key_len < 0) {
177f50fff73SHannes Reinecke pr_debug("base64 key decoding error %d\n",
178f50fff73SHannes Reinecke key_len);
179f50fff73SHannes Reinecke ret = key_len;
180f50fff73SHannes Reinecke goto out_free_secret;
181f50fff73SHannes Reinecke }
182f50fff73SHannes Reinecke
183f50fff73SHannes Reinecke if (key_len != 36 && key_len != 52 &&
184f50fff73SHannes Reinecke key_len != 68) {
185f50fff73SHannes Reinecke pr_err("Invalid key len %d\n", key_len);
186f50fff73SHannes Reinecke ret = -EINVAL;
187f50fff73SHannes Reinecke goto out_free_secret;
188f50fff73SHannes Reinecke }
189f50fff73SHannes Reinecke
190f50fff73SHannes Reinecke if (key_hash > 0 &&
191f50fff73SHannes Reinecke (key_len - 4) != nvme_auth_hmac_hash_len(key_hash)) {
192f50fff73SHannes Reinecke pr_err("Mismatched key len %d for %s\n", key_len,
193f50fff73SHannes Reinecke nvme_auth_hmac_name(key_hash));
194f50fff73SHannes Reinecke ret = -EINVAL;
195f50fff73SHannes Reinecke goto out_free_secret;
196f50fff73SHannes Reinecke }
197f50fff73SHannes Reinecke
198f50fff73SHannes Reinecke /* The last four bytes is the CRC in little-endian format */
199f50fff73SHannes Reinecke key_len -= 4;
200f50fff73SHannes Reinecke /*
201f50fff73SHannes Reinecke * The linux implementation doesn't do pre- and post-increments,
202f50fff73SHannes Reinecke * so we have to do it manually.
203f50fff73SHannes Reinecke */
204f50fff73SHannes Reinecke crc = ~crc32(~0, key->key, key_len);
205f50fff73SHannes Reinecke
206f50fff73SHannes Reinecke if (get_unaligned_le32(key->key + key_len) != crc) {
207f50fff73SHannes Reinecke pr_err("key crc mismatch (key %08x, crc %08x)\n",
208f50fff73SHannes Reinecke get_unaligned_le32(key->key + key_len), crc);
209f50fff73SHannes Reinecke ret = -EKEYREJECTED;
210f50fff73SHannes Reinecke goto out_free_secret;
211f50fff73SHannes Reinecke }
212f50fff73SHannes Reinecke key->len = key_len;
213f50fff73SHannes Reinecke key->hash = key_hash;
214f50fff73SHannes Reinecke return key;
215f50fff73SHannes Reinecke out_free_secret:
216f50fff73SHannes Reinecke kfree_sensitive(key->key);
217f50fff73SHannes Reinecke out_free_key:
218f50fff73SHannes Reinecke kfree(key);
219f50fff73SHannes Reinecke return ERR_PTR(ret);
220f50fff73SHannes Reinecke }
221f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_extract_key);
222f50fff73SHannes Reinecke
nvme_auth_free_key(struct nvme_dhchap_key * key)223f50fff73SHannes Reinecke void nvme_auth_free_key(struct nvme_dhchap_key *key)
224f50fff73SHannes Reinecke {
225f50fff73SHannes Reinecke if (!key)
226f50fff73SHannes Reinecke return;
227f50fff73SHannes Reinecke kfree_sensitive(key->key);
228f50fff73SHannes Reinecke kfree(key);
229f50fff73SHannes Reinecke }
230f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_free_key);
231f50fff73SHannes Reinecke
nvme_auth_transform_key(struct nvme_dhchap_key * key,char * nqn)232f50fff73SHannes Reinecke u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
233f50fff73SHannes Reinecke {
234f50fff73SHannes Reinecke const char *hmac_name;
235f50fff73SHannes Reinecke struct crypto_shash *key_tfm;
236f50fff73SHannes Reinecke struct shash_desc *shash;
237f50fff73SHannes Reinecke u8 *transformed_key;
238f50fff73SHannes Reinecke int ret;
239f50fff73SHannes Reinecke
240f50fff73SHannes Reinecke if (!key || !key->key) {
241f50fff73SHannes Reinecke pr_warn("No key specified\n");
242f50fff73SHannes Reinecke return ERR_PTR(-ENOKEY);
243f50fff73SHannes Reinecke }
244f50fff73SHannes Reinecke if (key->hash == 0) {
245f50fff73SHannes Reinecke transformed_key = kmemdup(key->key, key->len, GFP_KERNEL);
246f50fff73SHannes Reinecke return transformed_key ? transformed_key : ERR_PTR(-ENOMEM);
247f50fff73SHannes Reinecke }
248f50fff73SHannes Reinecke hmac_name = nvme_auth_hmac_name(key->hash);
249f50fff73SHannes Reinecke if (!hmac_name) {
250f50fff73SHannes Reinecke pr_warn("Invalid key hash id %d\n", key->hash);
251f50fff73SHannes Reinecke return ERR_PTR(-EINVAL);
252f50fff73SHannes Reinecke }
253f50fff73SHannes Reinecke
254f50fff73SHannes Reinecke key_tfm = crypto_alloc_shash(hmac_name, 0, 0);
255f50fff73SHannes Reinecke if (IS_ERR(key_tfm))
256f50fff73SHannes Reinecke return (u8 *)key_tfm;
257f50fff73SHannes Reinecke
258f50fff73SHannes Reinecke shash = kmalloc(sizeof(struct shash_desc) +
259f50fff73SHannes Reinecke crypto_shash_descsize(key_tfm),
260f50fff73SHannes Reinecke GFP_KERNEL);
261f50fff73SHannes Reinecke if (!shash) {
262f50fff73SHannes Reinecke ret = -ENOMEM;
263f50fff73SHannes Reinecke goto out_free_key;
264f50fff73SHannes Reinecke }
265f50fff73SHannes Reinecke
266f50fff73SHannes Reinecke transformed_key = kzalloc(crypto_shash_digestsize(key_tfm), GFP_KERNEL);
267f50fff73SHannes Reinecke if (!transformed_key) {
268f50fff73SHannes Reinecke ret = -ENOMEM;
269f50fff73SHannes Reinecke goto out_free_shash;
270f50fff73SHannes Reinecke }
271f50fff73SHannes Reinecke
272f50fff73SHannes Reinecke shash->tfm = key_tfm;
273f50fff73SHannes Reinecke ret = crypto_shash_setkey(key_tfm, key->key, key->len);
274f50fff73SHannes Reinecke if (ret < 0)
27580e27684SDan Carpenter goto out_free_transformed_key;
276f50fff73SHannes Reinecke ret = crypto_shash_init(shash);
277f50fff73SHannes Reinecke if (ret < 0)
27880e27684SDan Carpenter goto out_free_transformed_key;
279f50fff73SHannes Reinecke ret = crypto_shash_update(shash, nqn, strlen(nqn));
280f50fff73SHannes Reinecke if (ret < 0)
28180e27684SDan Carpenter goto out_free_transformed_key;
282f50fff73SHannes Reinecke ret = crypto_shash_update(shash, "NVMe-over-Fabrics", 17);
283f50fff73SHannes Reinecke if (ret < 0)
28480e27684SDan Carpenter goto out_free_transformed_key;
285f50fff73SHannes Reinecke ret = crypto_shash_final(shash, transformed_key);
28680e27684SDan Carpenter if (ret < 0)
28780e27684SDan Carpenter goto out_free_transformed_key;
28880e27684SDan Carpenter
28980e27684SDan Carpenter kfree(shash);
29080e27684SDan Carpenter crypto_free_shash(key_tfm);
29180e27684SDan Carpenter
29280e27684SDan Carpenter return transformed_key;
29380e27684SDan Carpenter
29480e27684SDan Carpenter out_free_transformed_key:
29580e27684SDan Carpenter kfree_sensitive(transformed_key);
296f50fff73SHannes Reinecke out_free_shash:
297f50fff73SHannes Reinecke kfree(shash);
298f50fff73SHannes Reinecke out_free_key:
299f50fff73SHannes Reinecke crypto_free_shash(key_tfm);
30080e27684SDan Carpenter
301f50fff73SHannes Reinecke return ERR_PTR(ret);
302f50fff73SHannes Reinecke }
303f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_transform_key);
304f50fff73SHannes Reinecke
nvme_auth_hash_skey(int hmac_id,u8 * skey,size_t skey_len,u8 * hkey)305b61775d1SHannes Reinecke static int nvme_auth_hash_skey(int hmac_id, u8 *skey, size_t skey_len, u8 *hkey)
306b61775d1SHannes Reinecke {
307b61775d1SHannes Reinecke const char *digest_name;
308b61775d1SHannes Reinecke struct crypto_shash *tfm;
309b61775d1SHannes Reinecke int ret;
310b61775d1SHannes Reinecke
311b61775d1SHannes Reinecke digest_name = nvme_auth_digest_name(hmac_id);
312b61775d1SHannes Reinecke if (!digest_name) {
313b61775d1SHannes Reinecke pr_debug("%s: failed to get digest for %d\n", __func__,
314b61775d1SHannes Reinecke hmac_id);
315b61775d1SHannes Reinecke return -EINVAL;
316b61775d1SHannes Reinecke }
317b61775d1SHannes Reinecke tfm = crypto_alloc_shash(digest_name, 0, 0);
318b61775d1SHannes Reinecke if (IS_ERR(tfm))
319b61775d1SHannes Reinecke return -ENOMEM;
320b61775d1SHannes Reinecke
321b61775d1SHannes Reinecke ret = crypto_shash_tfm_digest(tfm, skey, skey_len, hkey);
322b61775d1SHannes Reinecke if (ret < 0)
323b61775d1SHannes Reinecke pr_debug("%s: Failed to hash digest len %zu\n", __func__,
324b61775d1SHannes Reinecke skey_len);
325b61775d1SHannes Reinecke
326b61775d1SHannes Reinecke crypto_free_shash(tfm);
327b61775d1SHannes Reinecke return ret;
328b61775d1SHannes Reinecke }
329b61775d1SHannes Reinecke
nvme_auth_augmented_challenge(u8 hmac_id,u8 * skey,size_t skey_len,u8 * challenge,u8 * aug,size_t hlen)330b61775d1SHannes Reinecke int nvme_auth_augmented_challenge(u8 hmac_id, u8 *skey, size_t skey_len,
331b61775d1SHannes Reinecke u8 *challenge, u8 *aug, size_t hlen)
332b61775d1SHannes Reinecke {
333b61775d1SHannes Reinecke struct crypto_shash *tfm;
334b61775d1SHannes Reinecke struct shash_desc *desc;
335b61775d1SHannes Reinecke u8 *hashed_key;
336b61775d1SHannes Reinecke const char *hmac_name;
337b61775d1SHannes Reinecke int ret;
338b61775d1SHannes Reinecke
339b61775d1SHannes Reinecke hashed_key = kmalloc(hlen, GFP_KERNEL);
340b61775d1SHannes Reinecke if (!hashed_key)
341b61775d1SHannes Reinecke return -ENOMEM;
342b61775d1SHannes Reinecke
343b61775d1SHannes Reinecke ret = nvme_auth_hash_skey(hmac_id, skey,
344b61775d1SHannes Reinecke skey_len, hashed_key);
345b61775d1SHannes Reinecke if (ret < 0)
346b61775d1SHannes Reinecke goto out_free_key;
347b61775d1SHannes Reinecke
348b61775d1SHannes Reinecke hmac_name = nvme_auth_hmac_name(hmac_id);
349b61775d1SHannes Reinecke if (!hmac_name) {
3509db056e9SColin Ian King pr_warn("%s: invalid hash algorithm %d\n",
351b61775d1SHannes Reinecke __func__, hmac_id);
352b61775d1SHannes Reinecke ret = -EINVAL;
353b61775d1SHannes Reinecke goto out_free_key;
354b61775d1SHannes Reinecke }
355b61775d1SHannes Reinecke
356b61775d1SHannes Reinecke tfm = crypto_alloc_shash(hmac_name, 0, 0);
357b61775d1SHannes Reinecke if (IS_ERR(tfm)) {
358b61775d1SHannes Reinecke ret = PTR_ERR(tfm);
359b61775d1SHannes Reinecke goto out_free_key;
360b61775d1SHannes Reinecke }
361b61775d1SHannes Reinecke
362b61775d1SHannes Reinecke desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm),
363b61775d1SHannes Reinecke GFP_KERNEL);
364b61775d1SHannes Reinecke if (!desc) {
365b61775d1SHannes Reinecke ret = -ENOMEM;
366b61775d1SHannes Reinecke goto out_free_hash;
367b61775d1SHannes Reinecke }
368b61775d1SHannes Reinecke desc->tfm = tfm;
369b61775d1SHannes Reinecke
370b61775d1SHannes Reinecke ret = crypto_shash_setkey(tfm, hashed_key, hlen);
371b61775d1SHannes Reinecke if (ret)
372b61775d1SHannes Reinecke goto out_free_desc;
373b61775d1SHannes Reinecke
374b61775d1SHannes Reinecke ret = crypto_shash_init(desc);
375b61775d1SHannes Reinecke if (ret)
376b61775d1SHannes Reinecke goto out_free_desc;
377b61775d1SHannes Reinecke
378b61775d1SHannes Reinecke ret = crypto_shash_update(desc, challenge, hlen);
379b61775d1SHannes Reinecke if (ret)
380b61775d1SHannes Reinecke goto out_free_desc;
381b61775d1SHannes Reinecke
382b61775d1SHannes Reinecke ret = crypto_shash_final(desc, aug);
383b61775d1SHannes Reinecke out_free_desc:
384b61775d1SHannes Reinecke kfree_sensitive(desc);
385b61775d1SHannes Reinecke out_free_hash:
386b61775d1SHannes Reinecke crypto_free_shash(tfm);
387b61775d1SHannes Reinecke out_free_key:
388b61775d1SHannes Reinecke kfree_sensitive(hashed_key);
389b61775d1SHannes Reinecke return ret;
390b61775d1SHannes Reinecke }
391b61775d1SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge);
392b61775d1SHannes Reinecke
nvme_auth_gen_privkey(struct crypto_kpp * dh_tfm,u8 dh_gid)393b61775d1SHannes Reinecke int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid)
394b61775d1SHannes Reinecke {
395b61775d1SHannes Reinecke int ret;
396b61775d1SHannes Reinecke
397b61775d1SHannes Reinecke ret = crypto_kpp_set_secret(dh_tfm, NULL, 0);
398b61775d1SHannes Reinecke if (ret)
399b61775d1SHannes Reinecke pr_debug("failed to set private key, error %d\n", ret);
400b61775d1SHannes Reinecke
401b61775d1SHannes Reinecke return ret;
402b61775d1SHannes Reinecke }
403b61775d1SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_gen_privkey);
404b61775d1SHannes Reinecke
nvme_auth_gen_pubkey(struct crypto_kpp * dh_tfm,u8 * host_key,size_t host_key_len)405b61775d1SHannes Reinecke int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
406b61775d1SHannes Reinecke u8 *host_key, size_t host_key_len)
407b61775d1SHannes Reinecke {
408b61775d1SHannes Reinecke struct kpp_request *req;
409b61775d1SHannes Reinecke struct crypto_wait wait;
410b61775d1SHannes Reinecke struct scatterlist dst;
411b61775d1SHannes Reinecke int ret;
412b61775d1SHannes Reinecke
413b61775d1SHannes Reinecke req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
414b61775d1SHannes Reinecke if (!req)
415b61775d1SHannes Reinecke return -ENOMEM;
416b61775d1SHannes Reinecke
417b61775d1SHannes Reinecke crypto_init_wait(&wait);
418b61775d1SHannes Reinecke kpp_request_set_input(req, NULL, 0);
419b61775d1SHannes Reinecke sg_init_one(&dst, host_key, host_key_len);
420b61775d1SHannes Reinecke kpp_request_set_output(req, &dst, host_key_len);
421b61775d1SHannes Reinecke kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
422b61775d1SHannes Reinecke crypto_req_done, &wait);
423b61775d1SHannes Reinecke
424b61775d1SHannes Reinecke ret = crypto_wait_req(crypto_kpp_generate_public_key(req), &wait);
425b61775d1SHannes Reinecke kpp_request_free(req);
426b61775d1SHannes Reinecke return ret;
427b61775d1SHannes Reinecke }
428b61775d1SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey);
429b61775d1SHannes Reinecke
nvme_auth_gen_shared_secret(struct crypto_kpp * dh_tfm,u8 * ctrl_key,size_t ctrl_key_len,u8 * sess_key,size_t sess_key_len)430b61775d1SHannes Reinecke int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
431b61775d1SHannes Reinecke u8 *ctrl_key, size_t ctrl_key_len,
432b61775d1SHannes Reinecke u8 *sess_key, size_t sess_key_len)
433b61775d1SHannes Reinecke {
434b61775d1SHannes Reinecke struct kpp_request *req;
435b61775d1SHannes Reinecke struct crypto_wait wait;
436b61775d1SHannes Reinecke struct scatterlist src, dst;
437b61775d1SHannes Reinecke int ret;
438b61775d1SHannes Reinecke
439b61775d1SHannes Reinecke req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
440b61775d1SHannes Reinecke if (!req)
441b61775d1SHannes Reinecke return -ENOMEM;
442b61775d1SHannes Reinecke
443b61775d1SHannes Reinecke crypto_init_wait(&wait);
444b61775d1SHannes Reinecke sg_init_one(&src, ctrl_key, ctrl_key_len);
445b61775d1SHannes Reinecke kpp_request_set_input(req, &src, ctrl_key_len);
446b61775d1SHannes Reinecke sg_init_one(&dst, sess_key, sess_key_len);
447b61775d1SHannes Reinecke kpp_request_set_output(req, &dst, sess_key_len);
448b61775d1SHannes Reinecke kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
449b61775d1SHannes Reinecke crypto_req_done, &wait);
450b61775d1SHannes Reinecke
451b61775d1SHannes Reinecke ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);
452b61775d1SHannes Reinecke
453b61775d1SHannes Reinecke kpp_request_free(req);
454b61775d1SHannes Reinecke return ret;
455b61775d1SHannes Reinecke }
456b61775d1SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret);
457b61775d1SHannes Reinecke
nvme_auth_generate_key(u8 * secret,struct nvme_dhchap_key ** ret_key)458f50fff73SHannes Reinecke int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key)
459f50fff73SHannes Reinecke {
460f50fff73SHannes Reinecke struct nvme_dhchap_key *key;
461f50fff73SHannes Reinecke u8 key_hash;
462f50fff73SHannes Reinecke
463f50fff73SHannes Reinecke if (!secret) {
464f50fff73SHannes Reinecke *ret_key = NULL;
465f50fff73SHannes Reinecke return 0;
466f50fff73SHannes Reinecke }
467f50fff73SHannes Reinecke
468f50fff73SHannes Reinecke if (sscanf(secret, "DHHC-1:%hhd:%*s:", &key_hash) != 1)
469f50fff73SHannes Reinecke return -EINVAL;
470f50fff73SHannes Reinecke
471f50fff73SHannes Reinecke /* Pass in the secret without the 'DHHC-1:XX:' prefix */
472f50fff73SHannes Reinecke key = nvme_auth_extract_key(secret + 10, key_hash);
473f50fff73SHannes Reinecke if (IS_ERR(key)) {
474f50fff73SHannes Reinecke *ret_key = NULL;
475f50fff73SHannes Reinecke return PTR_ERR(key);
476f50fff73SHannes Reinecke }
477f50fff73SHannes Reinecke
478f50fff73SHannes Reinecke *ret_key = key;
479f50fff73SHannes Reinecke return 0;
480f50fff73SHannes Reinecke }
481f50fff73SHannes Reinecke EXPORT_SYMBOL_GPL(nvme_auth_generate_key);
482f50fff73SHannes Reinecke
483f50fff73SHannes Reinecke MODULE_LICENSE("GPL v2");
484