Skip to content

Commit 5bc8f14

Browse files
committed
Merge tag 'nvme-6.7-2023-10-17' of git://git.infradead.org/nvme into for-6.7/block
Pull NVMe updates from Keith: "nvme updates for Linux 6.7 - nvme-auth updates (Mark) - nvme-tcp tls (Hannes) - nvme-fc annotaions (Kees)" * tag 'nvme-6.7-2023-10-17' of git://git.infradead.org/nvme: (24 commits) nvme-auth: allow mixing of secret and hash lengths nvme-auth: use transformed key size to create resp nvme-auth: alloc nvme_dhchap_key as single buffer nvmet-tcp: use 'spin_lock_bh' for state_lock() nvme: rework NVME_AUTH Kconfig selection nvmet-tcp: peek icreq before starting TLS nvmet-tcp: control messages for recvmsg() nvmet-tcp: enable TLS handshake upcall nvmet: Set 'TREQ' to 'required' when TLS is enabled nvmet-tcp: allocate socket file nvmet-tcp: make nvmet_tcp_alloc_queue() a void function nvmet: make TCP sectype settable via configfs nvme-fabrics: parse options 'keyring' and 'tls_key' nvme-tcp: improve icreq/icresp logging nvme-tcp: control message handling for recvmsg() nvme-tcp: enable TLS handshake upcall nvme-tcp: allocate socket file security/keys: export key_lookup() nvme-keyring: implement nvme_tls_psk_default() nvme-tcp: add definitions for TLS cipher suites ...
2 parents ec8cf23 + 3244552 commit 5bc8f14

25 files changed

Lines changed: 1090 additions & 132 deletions

File tree

drivers/nvme/common/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,16 @@
22

33
config NVME_COMMON
44
tristate
5+
6+
config NVME_KEYRING
7+
bool
8+
select KEYS
9+
10+
config NVME_AUTH
11+
bool
12+
select CRYPTO
13+
select CRYPTO_HMAC
14+
select CRYPTO_SHA256
15+
select CRYPTO_SHA512
16+
select CRYPTO_DH
17+
select CRYPTO_DH_RFC7919_GROUPS

drivers/nvme/common/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ ccflags-y += -I$(src)
44

55
obj-$(CONFIG_NVME_COMMON) += nvme-common.o
66

7-
nvme-common-y += auth.o
7+
nvme-common-$(CONFIG_NVME_AUTH) += auth.o
8+
nvme-common-$(CONFIG_NVME_KEYRING) += keyring.o

drivers/nvme/common/auth.c

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ size_t nvme_auth_hmac_hash_len(u8 hmac_id)
150150
}
151151
EXPORT_SYMBOL_GPL(nvme_auth_hmac_hash_len);
152152

153+
u32 nvme_auth_key_struct_size(u32 key_len)
154+
{
155+
struct nvme_dhchap_key key;
156+
157+
return struct_size(&key, key, key_len);
158+
}
159+
EXPORT_SYMBOL_GPL(nvme_auth_key_struct_size);
160+
153161
struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
154162
u8 key_hash)
155163
{
@@ -163,14 +171,9 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
163171
p = strrchr(secret, ':');
164172
if (p)
165173
allocated_len = p - secret;
166-
key = kzalloc(sizeof(*key), GFP_KERNEL);
174+
key = nvme_auth_alloc_key(allocated_len, 0);
167175
if (!key)
168176
return ERR_PTR(-ENOMEM);
169-
key->key = kzalloc(allocated_len, GFP_KERNEL);
170-
if (!key->key) {
171-
ret = -ENOMEM;
172-
goto out_free_key;
173-
}
174177

175178
key_len = base64_decode(secret, allocated_len, key->key);
176179
if (key_len < 0) {
@@ -187,14 +190,6 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
187190
goto out_free_secret;
188191
}
189192

190-
if (key_hash > 0 &&
191-
(key_len - 4) != nvme_auth_hmac_hash_len(key_hash)) {
192-
pr_err("Mismatched key len %d for %s\n", key_len,
193-
nvme_auth_hmac_name(key_hash));
194-
ret = -EINVAL;
195-
goto out_free_secret;
196-
}
197-
198193
/* The last four bytes is the CRC in little-endian format */
199194
key_len -= 4;
200195
/*
@@ -213,37 +208,51 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret,
213208
key->hash = key_hash;
214209
return key;
215210
out_free_secret:
216-
kfree_sensitive(key->key);
217-
out_free_key:
218-
kfree(key);
211+
nvme_auth_free_key(key);
219212
return ERR_PTR(ret);
220213
}
221214
EXPORT_SYMBOL_GPL(nvme_auth_extract_key);
222215

216+
struct nvme_dhchap_key *nvme_auth_alloc_key(u32 len, u8 hash)
217+
{
218+
u32 num_bytes = nvme_auth_key_struct_size(len);
219+
struct nvme_dhchap_key *key = kzalloc(num_bytes, GFP_KERNEL);
220+
221+
if (key) {
222+
key->len = len;
223+
key->hash = hash;
224+
}
225+
return key;
226+
}
227+
EXPORT_SYMBOL_GPL(nvme_auth_alloc_key);
228+
223229
void nvme_auth_free_key(struct nvme_dhchap_key *key)
224230
{
225231
if (!key)
226232
return;
227-
kfree_sensitive(key->key);
228-
kfree(key);
233+
kfree_sensitive(key);
229234
}
230235
EXPORT_SYMBOL_GPL(nvme_auth_free_key);
231236

232-
u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
237+
struct nvme_dhchap_key *nvme_auth_transform_key(
238+
struct nvme_dhchap_key *key, char *nqn)
233239
{
234240
const char *hmac_name;
235241
struct crypto_shash *key_tfm;
236242
struct shash_desc *shash;
237-
u8 *transformed_key;
238-
int ret;
243+
struct nvme_dhchap_key *transformed_key;
244+
int ret, key_len;
239245

240-
if (!key || !key->key) {
246+
if (!key) {
241247
pr_warn("No key specified\n");
242248
return ERR_PTR(-ENOKEY);
243249
}
244250
if (key->hash == 0) {
245-
transformed_key = kmemdup(key->key, key->len, GFP_KERNEL);
246-
return transformed_key ? transformed_key : ERR_PTR(-ENOMEM);
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;
247256
}
248257
hmac_name = nvme_auth_hmac_name(key->hash);
249258
if (!hmac_name) {
@@ -253,7 +262,7 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
253262

254263
key_tfm = crypto_alloc_shash(hmac_name, 0, 0);
255264
if (IS_ERR(key_tfm))
256-
return (u8 *)key_tfm;
265+
return ERR_CAST(key_tfm);
257266

258267
shash = kmalloc(sizeof(struct shash_desc) +
259268
crypto_shash_descsize(key_tfm),
@@ -263,7 +272,8 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
263272
goto out_free_key;
264273
}
265274

266-
transformed_key = kzalloc(crypto_shash_digestsize(key_tfm), GFP_KERNEL);
275+
key_len = crypto_shash_digestsize(key_tfm);
276+
transformed_key = nvme_auth_alloc_key(key_len, key->hash);
267277
if (!transformed_key) {
268278
ret = -ENOMEM;
269279
goto out_free_shash;
@@ -282,7 +292,7 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
282292
ret = crypto_shash_update(shash, "NVMe-over-Fabrics", 17);
283293
if (ret < 0)
284294
goto out_free_transformed_key;
285-
ret = crypto_shash_final(shash, transformed_key);
295+
ret = crypto_shash_final(shash, transformed_key->key);
286296
if (ret < 0)
287297
goto out_free_transformed_key;
288298

@@ -292,7 +302,7 @@ u8 *nvme_auth_transform_key(struct nvme_dhchap_key *key, char *nqn)
292302
return transformed_key;
293303

294304
out_free_transformed_key:
295-
kfree_sensitive(transformed_key);
305+
nvme_auth_free_key(transformed_key);
296306
out_free_shash:
297307
kfree(shash);
298308
out_free_key:

drivers/nvme/common/keyring.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (c) 2023 Hannes Reinecke, SUSE Labs
4+
*/
5+
6+
#include <linux/module.h>
7+
#include <linux/seq_file.h>
8+
#include <linux/key.h>
9+
#include <linux/key-type.h>
10+
#include <keys/user-type.h>
11+
#include <linux/nvme.h>
12+
#include <linux/nvme-tcp.h>
13+
#include <linux/nvme-keyring.h>
14+
15+
static struct key *nvme_keyring;
16+
17+
key_serial_t nvme_keyring_id(void)
18+
{
19+
return nvme_keyring->serial;
20+
}
21+
EXPORT_SYMBOL_GPL(nvme_keyring_id);
22+
23+
static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
24+
{
25+
seq_puts(m, key->description);
26+
seq_printf(m, ": %u", key->datalen);
27+
}
28+
29+
static bool nvme_tls_psk_match(const struct key *key,
30+
const struct key_match_data *match_data)
31+
{
32+
const char *match_id;
33+
size_t match_len;
34+
35+
if (!key->description) {
36+
pr_debug("%s: no key description\n", __func__);
37+
return false;
38+
}
39+
match_len = strlen(key->description);
40+
pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len);
41+
42+
if (!match_data->raw_data) {
43+
pr_debug("%s: no match data\n", __func__);
44+
return false;
45+
}
46+
match_id = match_data->raw_data;
47+
pr_debug("%s: match '%s' '%s' len %zd\n",
48+
__func__, match_id, key->description, match_len);
49+
return !memcmp(key->description, match_id, match_len);
50+
}
51+
52+
static int nvme_tls_psk_match_preparse(struct key_match_data *match_data)
53+
{
54+
match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
55+
match_data->cmp = nvme_tls_psk_match;
56+
return 0;
57+
}
58+
59+
static struct key_type nvme_tls_psk_key_type = {
60+
.name = "psk",
61+
.flags = KEY_TYPE_NET_DOMAIN,
62+
.preparse = user_preparse,
63+
.free_preparse = user_free_preparse,
64+
.match_preparse = nvme_tls_psk_match_preparse,
65+
.instantiate = generic_key_instantiate,
66+
.revoke = user_revoke,
67+
.destroy = user_destroy,
68+
.describe = nvme_tls_psk_describe,
69+
.read = user_read,
70+
};
71+
72+
static struct key *nvme_tls_psk_lookup(struct key *keyring,
73+
const char *hostnqn, const char *subnqn,
74+
int hmac, bool generated)
75+
{
76+
char *identity;
77+
size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
78+
key_ref_t keyref;
79+
key_serial_t keyring_id;
80+
81+
identity = kzalloc(identity_len, GFP_KERNEL);
82+
if (!identity)
83+
return ERR_PTR(-ENOMEM);
84+
85+
snprintf(identity, identity_len, "NVMe0%c%02d %s %s",
86+
generated ? 'G' : 'R', hmac, hostnqn, subnqn);
87+
88+
if (!keyring)
89+
keyring = nvme_keyring;
90+
keyring_id = key_serial(keyring);
91+
pr_debug("keyring %x lookup tls psk '%s'\n",
92+
keyring_id, identity);
93+
keyref = keyring_search(make_key_ref(keyring, true),
94+
&nvme_tls_psk_key_type,
95+
identity, false);
96+
if (IS_ERR(keyref)) {
97+
pr_debug("lookup tls psk '%s' failed, error %ld\n",
98+
identity, PTR_ERR(keyref));
99+
kfree(identity);
100+
return ERR_PTR(-ENOKEY);
101+
}
102+
kfree(identity);
103+
104+
return key_ref_to_ptr(keyref);
105+
}
106+
107+
/*
108+
* NVMe PSK priority list
109+
*
110+
* 'Retained' PSKs (ie 'generated == false')
111+
* should be preferred to 'generated' PSKs,
112+
* and SHA-384 should be preferred to SHA-256.
113+
*/
114+
struct nvme_tls_psk_priority_list {
115+
bool generated;
116+
enum nvme_tcp_tls_cipher cipher;
117+
} nvme_tls_psk_prio[] = {
118+
{ .generated = false,
119+
.cipher = NVME_TCP_TLS_CIPHER_SHA384, },
120+
{ .generated = false,
121+
.cipher = NVME_TCP_TLS_CIPHER_SHA256, },
122+
{ .generated = true,
123+
.cipher = NVME_TCP_TLS_CIPHER_SHA384, },
124+
{ .generated = true,
125+
.cipher = NVME_TCP_TLS_CIPHER_SHA256, },
126+
};
127+
128+
/*
129+
* nvme_tls_psk_default - Return the preferred PSK to use for TLS ClientHello
130+
*/
131+
key_serial_t nvme_tls_psk_default(struct key *keyring,
132+
const char *hostnqn, const char *subnqn)
133+
{
134+
struct key *tls_key;
135+
key_serial_t tls_key_id;
136+
int prio;
137+
138+
for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
139+
bool generated = nvme_tls_psk_prio[prio].generated;
140+
enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;
141+
142+
tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
143+
cipher, generated);
144+
if (!IS_ERR(tls_key)) {
145+
tls_key_id = tls_key->serial;
146+
key_put(tls_key);
147+
return tls_key_id;
148+
}
149+
}
150+
return 0;
151+
}
152+
EXPORT_SYMBOL_GPL(nvme_tls_psk_default);
153+
154+
int nvme_keyring_init(void)
155+
{
156+
int err;
157+
158+
nvme_keyring = keyring_alloc(".nvme",
159+
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
160+
current_cred(),
161+
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
162+
(KEY_USR_ALL & ~KEY_USR_SETATTR),
163+
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
164+
if (IS_ERR(nvme_keyring))
165+
return PTR_ERR(nvme_keyring);
166+
167+
err = register_key_type(&nvme_tls_psk_key_type);
168+
if (err) {
169+
key_put(nvme_keyring);
170+
return err;
171+
}
172+
return 0;
173+
}
174+
EXPORT_SYMBOL_GPL(nvme_keyring_init);
175+
176+
void nvme_keyring_exit(void)
177+
{
178+
unregister_key_type(&nvme_tls_psk_key_type);
179+
key_revoke(nvme_keyring);
180+
key_put(nvme_keyring);
181+
}
182+
EXPORT_SYMBOL_GPL(nvme_keyring_exit);

drivers/nvme/host/Kconfig

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,26 @@ config NVME_TCP
9292

9393
If unsure, say N.
9494

95-
config NVME_AUTH
95+
config NVME_TCP_TLS
96+
bool "NVMe over Fabrics TCP TLS encryption support"
97+
depends on NVME_TCP
98+
select NVME_COMMON
99+
select NVME_KEYRING
100+
select NET_HANDSHAKE
101+
select KEYS
102+
help
103+
Enables TLS encryption for NVMe TCP using the netlink handshake API.
104+
105+
The TLS handshake daemon is availble at
106+
https://github.com/oracle/ktls-utils.
107+
108+
If unsure, say N.
109+
110+
config NVME_HOST_AUTH
96111
bool "NVM Express over Fabrics In-Band Authentication"
97112
depends on NVME_CORE
98113
select NVME_COMMON
99-
select CRYPTO
100-
select CRYPTO_HMAC
101-
select CRYPTO_SHA256
102-
select CRYPTO_SHA512
103-
select CRYPTO_DH
104-
select CRYPTO_DH_RFC7919_GROUPS
114+
select NVME_AUTH
105115
help
106116
This provides support for NVMe over Fabrics In-Band Authentication.
107117

drivers/nvme/host/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ nvme-core-$(CONFIG_NVME_MULTIPATH) += multipath.o
1717
nvme-core-$(CONFIG_BLK_DEV_ZONED) += zns.o
1818
nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o
1919
nvme-core-$(CONFIG_NVME_HWMON) += hwmon.o
20-
nvme-core-$(CONFIG_NVME_AUTH) += auth.o
20+
nvme-core-$(CONFIG_NVME_HOST_AUTH) += auth.o
2121

2222
nvme-y += pci.o
2323

0 commit comments

Comments
 (0)