xref: /linux/drivers/nvme/common/keyring.c (revision c748a6d77c06a78651030e17da6beb278a1c9470)
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 static int __init 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 
175 static void __exit nvme_keyring_exit(void)
176 {
177 	unregister_key_type(&nvme_tls_psk_key_type);
178 	key_revoke(nvme_keyring);
179 	key_put(nvme_keyring);
180 }
181 
182 MODULE_LICENSE("GPL v2");
183 MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
184 module_init(nvme_keyring_init);
185 module_exit(nvme_keyring_exit);
186