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
nvme_keyring_id(void)17 key_serial_t nvme_keyring_id(void)
18 {
19 return nvme_keyring->serial;
20 }
21 EXPORT_SYMBOL_GPL(nvme_keyring_id);
22
nvme_tls_psk_revoked(struct key * psk)23 static bool nvme_tls_psk_revoked(struct key *psk)
24 {
25 return test_bit(KEY_FLAG_REVOKED, &psk->flags) ||
26 test_bit(KEY_FLAG_INVALIDATED, &psk->flags);
27 }
28
nvme_tls_key_lookup(key_serial_t key_id)29 struct key *nvme_tls_key_lookup(key_serial_t key_id)
30 {
31 struct key *key = key_lookup(key_id);
32
33 if (IS_ERR(key)) {
34 pr_err("key id %08x not found\n", key_id);
35 return key;
36 }
37 if (nvme_tls_psk_revoked(key)) {
38 pr_err("key id %08x revoked\n", key_id);
39 return ERR_PTR(-EKEYREVOKED);
40 }
41 return key;
42 }
43 EXPORT_SYMBOL_GPL(nvme_tls_key_lookup);
44
nvme_tls_psk_describe(const struct key * key,struct seq_file * m)45 static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
46 {
47 seq_puts(m, key->description);
48 seq_printf(m, ": %u", key->datalen);
49 }
50
nvme_tls_psk_match(const struct key * key,const struct key_match_data * match_data)51 static bool nvme_tls_psk_match(const struct key *key,
52 const struct key_match_data *match_data)
53 {
54 const char *match_id;
55 size_t match_len;
56
57 if (!key->description) {
58 pr_debug("%s: no key description\n", __func__);
59 return false;
60 }
61 if (!match_data->raw_data) {
62 pr_debug("%s: no match data\n", __func__);
63 return false;
64 }
65 match_id = match_data->raw_data;
66 match_len = strlen(match_id);
67 pr_debug("%s: match '%s' '%s' len %zd\n",
68 __func__, match_id, key->description, match_len);
69 return !memcmp(key->description, match_id, match_len);
70 }
71
nvme_tls_psk_match_preparse(struct key_match_data * match_data)72 static int nvme_tls_psk_match_preparse(struct key_match_data *match_data)
73 {
74 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
75 match_data->cmp = nvme_tls_psk_match;
76 return 0;
77 }
78
79 static struct key_type nvme_tls_psk_key_type = {
80 .name = "psk",
81 .flags = KEY_TYPE_NET_DOMAIN,
82 .preparse = user_preparse,
83 .free_preparse = user_free_preparse,
84 .match_preparse = nvme_tls_psk_match_preparse,
85 .instantiate = generic_key_instantiate,
86 .revoke = user_revoke,
87 .destroy = user_destroy,
88 .describe = nvme_tls_psk_describe,
89 .read = user_read,
90 };
91
nvme_tls_psk_lookup(struct key * keyring,const char * hostnqn,const char * subnqn,u8 hmac,u8 psk_ver,bool generated)92 static struct key *nvme_tls_psk_lookup(struct key *keyring,
93 const char *hostnqn, const char *subnqn,
94 u8 hmac, u8 psk_ver, bool generated)
95 {
96 char *identity;
97 size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
98 key_ref_t keyref;
99 key_serial_t keyring_id;
100
101 identity = kzalloc(identity_len, GFP_KERNEL);
102 if (!identity)
103 return ERR_PTR(-ENOMEM);
104
105 snprintf(identity, identity_len, "NVMe%u%c%02u %s %s",
106 psk_ver, generated ? 'G' : 'R', hmac, hostnqn, subnqn);
107
108 if (!keyring)
109 keyring = nvme_keyring;
110 keyring_id = key_serial(keyring);
111 pr_debug("keyring %x lookup tls psk '%s'\n",
112 keyring_id, identity);
113 keyref = keyring_search(make_key_ref(keyring, true),
114 &nvme_tls_psk_key_type,
115 identity, false);
116 if (IS_ERR(keyref)) {
117 pr_debug("lookup tls psk '%s' failed, error %ld\n",
118 identity, PTR_ERR(keyref));
119 kfree(identity);
120 return ERR_PTR(-ENOKEY);
121 }
122 kfree(identity);
123
124 return key_ref_to_ptr(keyref);
125 }
126
127 /*
128 * NVMe PSK priority list
129 *
130 * 'Retained' PSKs (ie 'generated == false') should be preferred to 'generated'
131 * PSKs, PSKs with hash (psk_ver 1) should be preferred to PSKs without hash
132 * (psk_ver 0), and SHA-384 should be preferred to SHA-256.
133 */
134 static struct nvme_tls_psk_priority_list {
135 bool generated;
136 u8 psk_ver;
137 enum nvme_tcp_tls_cipher cipher;
138 } nvme_tls_psk_prio[] = {
139 { .generated = false,
140 .psk_ver = 1,
141 .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
142 { .generated = false,
143 .psk_ver = 1,
144 .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
145 { .generated = false,
146 .psk_ver = 0,
147 .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
148 { .generated = false,
149 .psk_ver = 0,
150 .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
151 { .generated = true,
152 .psk_ver = 1,
153 .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
154 { .generated = true,
155 .psk_ver = 1,
156 .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
157 { .generated = true,
158 .psk_ver = 0,
159 .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
160 { .generated = true,
161 .psk_ver = 0,
162 .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
163 };
164
165 /*
166 * nvme_tls_psk_default - Return the preferred PSK to use for TLS ClientHello
167 */
nvme_tls_psk_default(struct key * keyring,const char * hostnqn,const char * subnqn)168 key_serial_t nvme_tls_psk_default(struct key *keyring,
169 const char *hostnqn, const char *subnqn)
170 {
171 struct key *tls_key;
172 key_serial_t tls_key_id;
173 int prio;
174
175 for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
176 bool generated = nvme_tls_psk_prio[prio].generated;
177 u8 ver = nvme_tls_psk_prio[prio].psk_ver;
178 enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;
179
180 tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
181 cipher, ver, generated);
182 if (!IS_ERR(tls_key)) {
183 tls_key_id = tls_key->serial;
184 key_put(tls_key);
185 return tls_key_id;
186 }
187 }
188 return 0;
189 }
190 EXPORT_SYMBOL_GPL(nvme_tls_psk_default);
191
nvme_keyring_init(void)192 static int __init nvme_keyring_init(void)
193 {
194 int err;
195
196 nvme_keyring = keyring_alloc(".nvme",
197 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
198 current_cred(),
199 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
200 (KEY_USR_ALL & ~KEY_USR_SETATTR),
201 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
202 if (IS_ERR(nvme_keyring))
203 return PTR_ERR(nvme_keyring);
204
205 err = register_key_type(&nvme_tls_psk_key_type);
206 if (err) {
207 key_put(nvme_keyring);
208 return err;
209 }
210 return 0;
211 }
212
nvme_keyring_exit(void)213 static void __exit nvme_keyring_exit(void)
214 {
215 unregister_key_type(&nvme_tls_psk_key_type);
216 key_revoke(nvme_keyring);
217 key_put(nvme_keyring);
218 }
219
220 MODULE_LICENSE("GPL v2");
221 MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
222 MODULE_DESCRIPTION("NVMe Keyring implementation");
223 module_init(nvme_keyring_init);
224 module_exit(nvme_keyring_exit);
225