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
15static struct key *nvme_keyring;
16
17key_serial_t nvme_keyring_id(void)
18{
19 return nvme_keyring->serial;
20}
21EXPORT_SYMBOL_GPL(nvme_keyring_id);
22
23static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
24{
25 seq_puts(m, s: key->description);
26 seq_printf(m, fmt: ": %u", key->datalen);
27}
28
29static 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(p: key->description, q: match_id, size: match_len);
50}
51
52static 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
59static 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
72static 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(size: identity_len, GFP_KERNEL);
82 if (!identity)
83 return ERR_PTR(error: -ENOMEM);
84
85 snprintf(buf: identity, size: identity_len, fmt: "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(key: keyring);
91 pr_debug("keyring %x lookup tls psk '%s'\n",
92 keyring_id, identity);
93 keyref = keyring_search(keyring: make_key_ref(key: keyring, possession: true),
94 type: &nvme_tls_psk_key_type,
95 description: identity, recurse: false);
96 if (IS_ERR(ptr: keyref)) {
97 pr_debug("lookup tls psk '%s' failed, error %ld\n",
98 identity, PTR_ERR(keyref));
99 kfree(objp: identity);
100 return ERR_PTR(error: -ENOKEY);
101 }
102 kfree(objp: identity);
103
104 return key_ref_to_ptr(key_ref: 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 */
114static 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 */
131key_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 hmac: cipher, generated);
144 if (!IS_ERR(ptr: tls_key)) {
145 tls_key_id = tls_key->serial;
146 key_put(key: tls_key);
147 return tls_key_id;
148 }
149 }
150 return 0;
151}
152EXPORT_SYMBOL_GPL(nvme_tls_psk_default);
153
154static int __init nvme_keyring_init(void)
155{
156 int err;
157
158 nvme_keyring = keyring_alloc(description: ".nvme",
159 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
160 current_cred(),
161 perm: (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
175static void __exit nvme_keyring_exit(void)
176{
177 unregister_key_type(ktype: &nvme_tls_psk_key_type);
178 key_revoke(key: nvme_keyring);
179 key_put(key: nvme_keyring);
180}
181
182MODULE_LICENSE("GPL v2");
183MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
184MODULE_DESCRIPTION("NVMe Keyring implementation");
185module_init(nvme_keyring_init);
186module_exit(nvme_keyring_exit);
187

source code of linux/drivers/nvme/common/keyring.c