]> Git Repo - J-linux.git/blob - drivers/nvme/common/keyring.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / nvme / common / keyring.c
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 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
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
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
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
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
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  */
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
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
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 <[email protected]>");
222 MODULE_DESCRIPTION("NVMe Keyring implementation");
223 module_init(nvme_keyring_init);
224 module_exit(nvme_keyring_exit);
This page took 0.039261 seconds and 4 git commands to generate.