]> Git Repo - linux.git/blob - drivers/s390/crypto/pkey_base.c
Linux 6.14-rc3
[linux.git] / drivers / s390 / crypto / pkey_base.c
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 #if IS_MODULE(CONFIG_PKEY_CCA)
308                 "pkey_cca",
309 #endif
310 #if IS_MODULE(CONFIG_PKEY_EP11)
311                 "pkey_ep11",
312 #endif
313 #if IS_MODULE(CONFIG_PKEY_PCKMO)
314                 "pkey_pckmo",
315 #endif
316 #if IS_MODULE(CONFIG_PKEY_UV)
317                 "pkey_uv",
318 #endif
319         };
320         int i;
321
322         for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) {
323                 const struct pkey_handler *h;
324                 bool found = false;
325
326                 rcu_read_lock();
327                 list_for_each_entry_rcu(h, &handler_list, list) {
328                         if (h->module &&
329                             !strcmp(h->module->name, pkey_handler_modules[i])) {
330                                 found = true;
331                                 break;
332                         }
333                 }
334                 rcu_read_unlock();
335                 if (!found) {
336                         pr_debug("request_module(%s)\n", pkey_handler_modules[i]);
337                         request_module(pkey_handler_modules[i]);
338                 }
339         }
340 #endif
341 }
342 EXPORT_SYMBOL(pkey_handler_request_modules);
343
344 /*
345  * Module init
346  */
347 static int __init pkey_init(void)
348 {
349         int rc;
350
351         /* init debug feature */
352         pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
353         debug_register_view(pkey_dbf_info, &debug_sprintf_view);
354         debug_set_level(pkey_dbf_info, 4);
355
356         /* the handler registry does not need any init */
357
358         rc = pkey_api_init();
359         if (rc)
360                 debug_unregister(pkey_dbf_info);
361
362         return rc;
363 }
364
365 /*
366  * Module exit
367  */
368 static void __exit pkey_exit(void)
369 {
370         pkey_api_exit();
371 }
372
373 module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init);
374 module_exit(pkey_exit);
This page took 0.051251 seconds and 4 git commands to generate.