xref: /linux/drivers/s390/crypto/pkey_base.c (revision bca5cfbb694d66a1c482d0c347eee80f6afbc870)
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 				u32 xflags)
155 {
156 	const struct pkey_handler *h;
157 	int rc = -ENODEV;
158 
159 	h = pkey_handler_get_keybased(key, keylen);
160 	if (h && h->key_to_protkey) {
161 		rc = h->key_to_protkey(apqns, nr_apqns, key, keylen,
162 				       protkey, protkeylen,
163 				       protkeytype, xflags);
164 	}
165 	pkey_handler_put(h);
166 
167 	return rc;
168 }
169 EXPORT_SYMBOL(pkey_handler_key_to_protkey);
170 
171 /*
172  * This handler invocation is special as there may be more than
173  * one handler providing support for the very same key (type).
174  * And the handler may not respond true on is_supported_key(),
175  * so simple try and check return value here.
176  */
177 int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
178 					 size_t nr_apqns,
179 					 const u8 *key, u32 keylen,
180 					 u8 *protkey, u32 *protkeylen,
181 					 u32 *protkeytype, u32 xflags)
182 {
183 	const struct pkey_handler *h, *htmp[10];
184 	int i, n = 0, rc = -ENODEV;
185 
186 	rcu_read_lock();
187 	list_for_each_entry_rcu(h, &handler_list, list) {
188 		if (!try_module_get(h->module))
189 			continue;
190 		if (h->slowpath_key_to_protkey && n < ARRAY_SIZE(htmp))
191 			htmp[n++] = h;
192 		else
193 			module_put(h->module);
194 	}
195 	rcu_read_unlock();
196 
197 	for (i = 0; i < n; i++) {
198 		h = htmp[i];
199 		if (rc)
200 			rc = h->slowpath_key_to_protkey(apqns, nr_apqns,
201 							key, keylen,
202 							protkey, protkeylen,
203 							protkeytype, xflags);
204 		module_put(h->module);
205 	}
206 
207 	return rc;
208 }
209 EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey);
210 
211 int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
212 			 u32 keytype, u32 keysubtype,
213 			 u32 keybitsize, u32 flags,
214 			 u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags)
215 {
216 	const struct pkey_handler *h;
217 	int rc = -ENODEV;
218 
219 	h = pkey_handler_get_keytypebased(keysubtype);
220 	if (h && h->gen_key) {
221 		rc = h->gen_key(apqns, nr_apqns, keytype, keysubtype,
222 				keybitsize, flags,
223 				keybuf, keybuflen, keyinfo, xflags);
224 	}
225 	pkey_handler_put(h);
226 
227 	return rc;
228 }
229 EXPORT_SYMBOL(pkey_handler_gen_key);
230 
231 int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns,
232 			    u32 keytype, u32 keysubtype,
233 			    u32 keybitsize, u32 flags,
234 			    const u8 *clrkey, u32 clrkeylen,
235 			    u8 *keybuf, u32 *keybuflen, u32 *keyinfo,
236 			    u32 xflags)
237 {
238 	const struct pkey_handler *h;
239 	int rc = -ENODEV;
240 
241 	h = pkey_handler_get_keytypebased(keysubtype);
242 	if (h && h->clr_to_key) {
243 		rc = h->clr_to_key(apqns, nr_apqns, keytype, keysubtype,
244 				   keybitsize, flags, clrkey, clrkeylen,
245 				   keybuf, keybuflen, keyinfo, xflags);
246 	}
247 	pkey_handler_put(h);
248 
249 	return rc;
250 }
251 EXPORT_SYMBOL(pkey_handler_clr_to_key);
252 
253 int pkey_handler_verify_key(const u8 *key, u32 keylen,
254 			    u16 *card, u16 *dom,
255 			    u32 *keytype, u32 *keybitsize, u32 *flags,
256 			    u32 xflags)
257 {
258 	const struct pkey_handler *h;
259 	int rc = -ENODEV;
260 
261 	h = pkey_handler_get_keybased(key, keylen);
262 	if (h && h->verify_key) {
263 		rc = h->verify_key(key, keylen, card, dom,
264 				   keytype, keybitsize, flags, xflags);
265 	}
266 	pkey_handler_put(h);
267 
268 	return rc;
269 }
270 EXPORT_SYMBOL(pkey_handler_verify_key);
271 
272 int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags,
273 			       struct pkey_apqn *apqns, size_t *nr_apqns,
274 			       u32 xflags)
275 {
276 	const struct pkey_handler *h;
277 	int rc = -ENODEV;
278 
279 	h = pkey_handler_get_keybased(key, keylen);
280 	if (h && h->apqns_for_key)
281 		rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns,
282 				      xflags);
283 	pkey_handler_put(h);
284 
285 	return rc;
286 }
287 EXPORT_SYMBOL(pkey_handler_apqns_for_key);
288 
289 int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype,
290 				   u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
291 				   struct pkey_apqn *apqns, size_t *nr_apqns,
292 				   u32 xflags)
293 {
294 	const struct pkey_handler *h;
295 	int rc = -ENODEV;
296 
297 	h = pkey_handler_get_keytypebased(keysubtype);
298 	if (h && h->apqns_for_keytype) {
299 		rc = h->apqns_for_keytype(keysubtype,
300 					  cur_mkvp, alt_mkvp, flags,
301 					  apqns, nr_apqns, xflags);
302 	}
303 	pkey_handler_put(h);
304 
305 	return rc;
306 }
307 EXPORT_SYMBOL(pkey_handler_apqns_for_keytype);
308 
309 void pkey_handler_request_modules(void)
310 {
311 #ifdef CONFIG_MODULES
312 	static const char * const pkey_handler_modules[] = {
313 #if IS_MODULE(CONFIG_PKEY_CCA)
314 		"pkey_cca",
315 #endif
316 #if IS_MODULE(CONFIG_PKEY_EP11)
317 		"pkey_ep11",
318 #endif
319 #if IS_MODULE(CONFIG_PKEY_PCKMO)
320 		"pkey_pckmo",
321 #endif
322 #if IS_MODULE(CONFIG_PKEY_UV)
323 		"pkey_uv",
324 #endif
325 	};
326 	int i;
327 
328 	for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) {
329 		const struct pkey_handler *h;
330 		bool found = false;
331 
332 		rcu_read_lock();
333 		list_for_each_entry_rcu(h, &handler_list, list) {
334 			if (h->module &&
335 			    !strcmp(h->module->name, pkey_handler_modules[i])) {
336 				found = true;
337 				break;
338 			}
339 		}
340 		rcu_read_unlock();
341 		if (!found) {
342 			pr_debug("request_module(%s)\n", pkey_handler_modules[i]);
343 			request_module(pkey_handler_modules[i]);
344 		}
345 	}
346 #endif
347 }
348 EXPORT_SYMBOL(pkey_handler_request_modules);
349 
350 /*
351  * Module init
352  */
353 static int __init pkey_init(void)
354 {
355 	int rc;
356 
357 	/* init debug feature */
358 	pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
359 	debug_register_view(pkey_dbf_info, &debug_sprintf_view);
360 	debug_set_level(pkey_dbf_info, 4);
361 
362 	/* the handler registry does not need any init */
363 
364 	rc = pkey_api_init();
365 	if (rc)
366 		debug_unregister(pkey_dbf_info);
367 
368 	return rc;
369 }
370 
371 /*
372  * Module exit
373  */
374 static void __exit pkey_exit(void)
375 {
376 	pkey_api_exit();
377 }
378 
379 module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init);
380 module_exit(pkey_exit);
381