xref: /linux/drivers/s390/crypto/pkey_base.c (revision 2cd86f02c017bf9733e5cd891381b7d40f6f37ad)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  pkey base: debug feature, pkey handler registry
4  *
5  *  Copyright IBM Corp. 2024
6  */
7 
8 #define KMSG_COMPONENT "pkey"
9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10 
11 #include <linux/cpufeature.h>
12 #include <linux/init.h>
13 #include <linux/list.h>
14 #include <linux/module.h>
15 #include <linux/rculist.h>
16 
17 #include "pkey_base.h"
18 
19 MODULE_LICENSE("GPL");
20 MODULE_AUTHOR("IBM Corporation");
21 MODULE_DESCRIPTION("s390 protected key base and api");
22 
23 /*
24  * pkey debug feature
25  */
26 debug_info_t *pkey_dbf_info;
27 EXPORT_SYMBOL(pkey_dbf_info);
28 
29 /*
30  * pkey handler registry
31  */
32 
33 static DEFINE_SPINLOCK(handler_list_write_lock);
34 static LIST_HEAD(handler_list);
35 
36 int pkey_handler_register(struct pkey_handler *handler)
37 {
38 	const struct pkey_handler *h;
39 
40 	if (!handler ||
41 	    !handler->is_supported_key ||
42 	    !handler->is_supported_keytype)
43 		return -EINVAL;
44 
45 	if (!try_module_get(handler->module))
46 		return -ENXIO;
47 
48 	spin_lock(&handler_list_write_lock);
49 
50 	rcu_read_lock();
51 	list_for_each_entry_rcu(h, &handler_list, list) {
52 		if (h == handler) {
53 			rcu_read_unlock();
54 			spin_unlock(&handler_list_write_lock);
55 			module_put(handler->module);
56 			return -EEXIST;
57 		}
58 	}
59 	rcu_read_unlock();
60 
61 	list_add_rcu(&handler->list, &handler_list);
62 	spin_unlock(&handler_list_write_lock);
63 	synchronize_rcu();
64 
65 	module_put(handler->module);
66 
67 	PKEY_DBF_INFO("%s pkey handler '%s' registered\n", __func__,
68 		      handler->name ?: "<no name>");
69 
70 	return 0;
71 }
72 EXPORT_SYMBOL(pkey_handler_register);
73 
74 int pkey_handler_unregister(struct pkey_handler *handler)
75 {
76 	spin_lock(&handler_list_write_lock);
77 	list_del_rcu(&handler->list);
78 	INIT_LIST_HEAD_RCU(&handler->list);
79 	spin_unlock(&handler_list_write_lock);
80 	synchronize_rcu();
81 
82 	PKEY_DBF_INFO("%s pkey handler '%s' unregistered\n", __func__,
83 		      handler->name ?: "<no name>");
84 
85 	return 0;
86 }
87 EXPORT_SYMBOL(pkey_handler_unregister);
88 
89 /*
90  * Handler invocation functions.
91  */
92 
93 const struct pkey_handler *pkey_handler_get_keybased(const u8 *key, u32 keylen)
94 {
95 	const struct pkey_handler *h;
96 
97 	rcu_read_lock();
98 	list_for_each_entry_rcu(h, &handler_list, list) {
99 		if (!try_module_get(h->module))
100 			continue;
101 		if (h->is_supported_key(key, keylen)) {
102 			rcu_read_unlock();
103 			return h;
104 		}
105 		module_put(h->module);
106 	}
107 	rcu_read_unlock();
108 
109 	return NULL;
110 }
111 EXPORT_SYMBOL(pkey_handler_get_keybased);
112 
113 const struct pkey_handler *pkey_handler_get_keytypebased(enum pkey_key_type kt)
114 {
115 	const struct pkey_handler *h;
116 
117 	rcu_read_lock();
118 	list_for_each_entry_rcu(h, &handler_list, list) {
119 		if (!try_module_get(h->module))
120 			continue;
121 		if (h->is_supported_keytype(kt)) {
122 			rcu_read_unlock();
123 			return h;
124 		}
125 		module_put(h->module);
126 	}
127 	rcu_read_unlock();
128 
129 	return NULL;
130 }
131 EXPORT_SYMBOL(pkey_handler_get_keytypebased);
132 
133 void pkey_handler_put(const struct pkey_handler *handler)
134 {
135 	const struct pkey_handler *h;
136 
137 	if (!handler)
138 		return;
139 
140 	rcu_read_lock();
141 	list_for_each_entry_rcu(h, &handler_list, list) {
142 		if (h == handler) {
143 			module_put(h->module);
144 			break;
145 		}
146 	}
147 	rcu_read_unlock();
148 }
149 EXPORT_SYMBOL(pkey_handler_put);
150 
151 int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
152 				const u8 *key, u32 keylen,
153 				u8 *protkey, u32 *protkeylen, u32 *protkeytype)
154 {
155 	const struct pkey_handler *h;
156 	int rc = -ENODEV;
157 
158 	h = pkey_handler_get_keybased(key, keylen);
159 	if (h && h->key_to_protkey) {
160 		rc = h->key_to_protkey(apqns, nr_apqns, key, keylen,
161 				       protkey, protkeylen,
162 				       protkeytype);
163 	}
164 	pkey_handler_put(h);
165 
166 	return rc;
167 }
168 EXPORT_SYMBOL(pkey_handler_key_to_protkey);
169 
170 /*
171  * This handler invocation is special as there may be more than
172  * one handler providing support for the very same key (type).
173  * And the handler may not respond true on is_supported_key(),
174  * so simple try and check return value here.
175  */
176 int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
177 					 size_t nr_apqns,
178 					 const u8 *key, u32 keylen,
179 					 u8 *protkey, u32 *protkeylen,
180 					 u32 *protkeytype)
181 {
182 	const struct pkey_handler *h, *htmp[10];
183 	int i, n = 0, rc = -ENODEV;
184 
185 	rcu_read_lock();
186 	list_for_each_entry_rcu(h, &handler_list, list) {
187 		if (!try_module_get(h->module))
188 			continue;
189 		if (h->slowpath_key_to_protkey && n < ARRAY_SIZE(htmp))
190 			htmp[n++] = h;
191 		else
192 			module_put(h->module);
193 	}
194 	rcu_read_unlock();
195 
196 	for (i = 0; i < n; i++) {
197 		h = htmp[i];
198 		if (rc)
199 			rc = h->slowpath_key_to_protkey(apqns, nr_apqns,
200 							key, keylen,
201 							protkey, protkeylen,
202 							protkeytype);
203 		module_put(h->module);
204 	}
205 
206 	return rc;
207 }
208 EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey);
209 
210 int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
211 			 u32 keytype, u32 keysubtype,
212 			 u32 keybitsize, u32 flags,
213 			 u8 *keybuf, u32 *keybuflen, u32 *keyinfo)
214 {
215 	const struct pkey_handler *h;
216 	int rc = -ENODEV;
217 
218 	h = pkey_handler_get_keytypebased(keysubtype);
219 	if (h && h->gen_key) {
220 		rc = h->gen_key(apqns, nr_apqns, keytype, keysubtype,
221 				keybitsize, flags,
222 				keybuf, keybuflen, keyinfo);
223 	}
224 	pkey_handler_put(h);
225 
226 	return rc;
227 }
228 EXPORT_SYMBOL(pkey_handler_gen_key);
229 
230 int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns,
231 			    u32 keytype, u32 keysubtype,
232 			    u32 keybitsize, u32 flags,
233 			    const u8 *clrkey, u32 clrkeylen,
234 			    u8 *keybuf, u32 *keybuflen, u32 *keyinfo)
235 {
236 	const struct pkey_handler *h;
237 	int rc = -ENODEV;
238 
239 	h = pkey_handler_get_keytypebased(keysubtype);
240 	if (h && h->clr_to_key) {
241 		rc = h->clr_to_key(apqns, nr_apqns, keytype, keysubtype,
242 				   keybitsize, flags, clrkey, clrkeylen,
243 				   keybuf, keybuflen, keyinfo);
244 	}
245 	pkey_handler_put(h);
246 
247 	return rc;
248 }
249 EXPORT_SYMBOL(pkey_handler_clr_to_key);
250 
251 int pkey_handler_verify_key(const u8 *key, u32 keylen,
252 			    u16 *card, u16 *dom,
253 			    u32 *keytype, u32 *keybitsize, u32 *flags)
254 {
255 	const struct pkey_handler *h;
256 	int rc = -ENODEV;
257 
258 	h = pkey_handler_get_keybased(key, keylen);
259 	if (h && h->verify_key) {
260 		rc = h->verify_key(key, keylen, card, dom,
261 				   keytype, keybitsize, flags);
262 	}
263 	pkey_handler_put(h);
264 
265 	return rc;
266 }
267 EXPORT_SYMBOL(pkey_handler_verify_key);
268 
269 int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags,
270 			       struct pkey_apqn *apqns, size_t *nr_apqns)
271 {
272 	const struct pkey_handler *h;
273 	int rc = -ENODEV;
274 
275 	h = pkey_handler_get_keybased(key, keylen);
276 	if (h && h->apqns_for_key)
277 		rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns);
278 	pkey_handler_put(h);
279 
280 	return rc;
281 }
282 EXPORT_SYMBOL(pkey_handler_apqns_for_key);
283 
284 int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype,
285 				   u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
286 				   struct pkey_apqn *apqns, size_t *nr_apqns)
287 {
288 	const struct pkey_handler *h;
289 	int rc = -ENODEV;
290 
291 	h = pkey_handler_get_keytypebased(keysubtype);
292 	if (h && h->apqns_for_keytype) {
293 		rc = h->apqns_for_keytype(keysubtype,
294 					  cur_mkvp, alt_mkvp, flags,
295 					  apqns, nr_apqns);
296 	}
297 	pkey_handler_put(h);
298 
299 	return rc;
300 }
301 EXPORT_SYMBOL(pkey_handler_apqns_for_keytype);
302 
303 void pkey_handler_request_modules(void)
304 {
305 #ifdef CONFIG_MODULES
306 	static const char * const pkey_handler_modules[] = {
307 		"pkey_cca", "pkey_ep11", "pkey_pckmo" };
308 	int i;
309 
310 	for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) {
311 		const struct pkey_handler *h;
312 		bool found = false;
313 
314 		rcu_read_lock();
315 		list_for_each_entry_rcu(h, &handler_list, list) {
316 			if (h->module &&
317 			    !strcmp(h->module->name, pkey_handler_modules[i])) {
318 				found = true;
319 				break;
320 			}
321 		}
322 		rcu_read_unlock();
323 		if (!found) {
324 			pr_debug("request_module(%s)\n", pkey_handler_modules[i]);
325 			request_module(pkey_handler_modules[i]);
326 		}
327 	}
328 #endif
329 }
330 EXPORT_SYMBOL(pkey_handler_request_modules);
331 
332 /*
333  * Module init
334  */
335 static int __init pkey_init(void)
336 {
337 	int rc;
338 
339 	/* init debug feature */
340 	pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
341 	debug_register_view(pkey_dbf_info, &debug_sprintf_view);
342 	debug_set_level(pkey_dbf_info, 4);
343 
344 	/* the handler registry does not need any init */
345 
346 	rc = pkey_api_init();
347 	if (rc)
348 		debug_unregister(pkey_dbf_info);
349 
350 	return rc;
351 }
352 
353 /*
354  * Module exit
355  */
356 static void __exit pkey_exit(void)
357 {
358 	pkey_api_exit();
359 }
360 
361 module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init);
362 module_exit(pkey_exit);
363