Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * pkey cca specific code
4 *
5 * Copyright IBM Corp. 2024
6 */
7
8#define pr_fmt(fmt) "pkey: " fmt
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/cpufeature.h>
13
14#include "zcrypt_ccamisc.h"
15#include "pkey_base.h"
16
17MODULE_LICENSE("GPL");
18MODULE_AUTHOR("IBM Corporation");
19MODULE_DESCRIPTION("s390 protected key CCA handler");
20
21#if IS_MODULE(CONFIG_PKEY_CCA)
22static struct ap_device_id pkey_cca_card_ids[] = {
23 { .dev_type = AP_DEVICE_TYPE_CEX4 },
24 { .dev_type = AP_DEVICE_TYPE_CEX5 },
25 { .dev_type = AP_DEVICE_TYPE_CEX6 },
26 { .dev_type = AP_DEVICE_TYPE_CEX7 },
27 { .dev_type = AP_DEVICE_TYPE_CEX8 },
28 { /* end of list */ },
29};
30MODULE_DEVICE_TABLE(ap, pkey_cca_card_ids);
31#endif
32
33/*
34 * Check key blob for known and supported CCA key.
35 */
36static bool is_cca_key(const u8 *key, u32 keylen)
37{
38 struct keytoken_header *hdr = (struct keytoken_header *)key;
39
40 if (keylen < sizeof(*hdr))
41 return false;
42
43 switch (hdr->type) {
44 case TOKTYPE_CCA_INTERNAL:
45 switch (hdr->version) {
46 case TOKVER_CCA_AES:
47 case TOKVER_CCA_VLSC:
48 return true;
49 default:
50 return false;
51 }
52 case TOKTYPE_CCA_INTERNAL_PKA:
53 return true;
54 default:
55 return false;
56 }
57}
58
59static bool is_cca_keytype(enum pkey_key_type key_type)
60{
61 switch (key_type) {
62 case PKEY_TYPE_CCA_DATA:
63 case PKEY_TYPE_CCA_CIPHER:
64 case PKEY_TYPE_CCA_ECC:
65 return true;
66 default:
67 return false;
68 }
69}
70
71static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,
72 struct pkey_apqn *apqns, size_t *nr_apqns, u32 pflags)
73{
74 struct keytoken_header *hdr = (struct keytoken_header *)key;
75 u32 _apqns[MAXAPQNSINLIST], _nr_apqns = ARRAY_SIZE(_apqns);
76 u32 xflags;
77 int rc;
78
79 xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
80
81 if (!flags)
82 flags = PKEY_FLAGS_MATCH_CUR_MKVP | PKEY_FLAGS_MATCH_ALT_MKVP;
83
84 if (keylen < sizeof(struct keytoken_header))
85 return -EINVAL;
86
87 zcrypt_wait_api_operational();
88
89 if (hdr->type == TOKTYPE_CCA_INTERNAL) {
90 u64 cur_mkvp = 0, old_mkvp = 0;
91 int minhwtype = ZCRYPT_CEX3C;
92
93 if (hdr->version == TOKVER_CCA_AES) {
94 struct secaeskeytoken *t = (struct secaeskeytoken *)key;
95
96 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
97 cur_mkvp = t->mkvp;
98 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
99 old_mkvp = t->mkvp;
100 } else if (hdr->version == TOKVER_CCA_VLSC) {
101 struct cipherkeytoken *t = (struct cipherkeytoken *)key;
102
103 minhwtype = ZCRYPT_CEX6;
104 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
105 cur_mkvp = t->mkvp0;
106 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
107 old_mkvp = t->mkvp0;
108 } else {
109 /* unknown CCA internal token type */
110 return -EINVAL;
111 }
112 rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
113 minhwtype, AES_MK_SET,
114 cur_mkvp, old_mkvp, xflags);
115 if (rc)
116 goto out;
117
118 } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
119 struct eccprivkeytoken *t = (struct eccprivkeytoken *)key;
120 u64 cur_mkvp = 0, old_mkvp = 0;
121
122 if (t->secid == 0x20) {
123 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
124 cur_mkvp = t->mkvp;
125 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
126 old_mkvp = t->mkvp;
127 } else {
128 /* unknown CCA internal 2 token type */
129 return -EINVAL;
130 }
131 rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
132 ZCRYPT_CEX7, APKA_MK_SET,
133 cur_mkvp, old_mkvp, xflags);
134 if (rc)
135 goto out;
136
137 } else {
138 PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n",
139 __func__, hdr->type, hdr->version);
140 return -EINVAL;
141 }
142
143 if (apqns) {
144 if (*nr_apqns < _nr_apqns)
145 rc = -ENOSPC;
146 else
147 memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
148 }
149 *nr_apqns = _nr_apqns;
150
151out:
152 pr_debug("rc=%d\n", rc);
153 return rc;
154}
155
156static int cca_apqns4type(enum pkey_key_type ktype,
157 u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
158 struct pkey_apqn *apqns, size_t *nr_apqns,
159 u32 pflags)
160{
161 u32 _apqns[MAXAPQNSINLIST], _nr_apqns = ARRAY_SIZE(_apqns);
162 u32 xflags;
163 int rc;
164
165 xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
166
167 zcrypt_wait_api_operational();
168
169 if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {
170 u64 cur_mkvp = 0, old_mkvp = 0;
171 int minhwtype = ZCRYPT_CEX3C;
172
173 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
174 cur_mkvp = *((u64 *)cur_mkvp);
175 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
176 old_mkvp = *((u64 *)alt_mkvp);
177 if (ktype == PKEY_TYPE_CCA_CIPHER)
178 minhwtype = ZCRYPT_CEX6;
179 rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
180 minhwtype, AES_MK_SET,
181 cur_mkvp, old_mkvp, xflags);
182 if (rc)
183 goto out;
184
185 } else if (ktype == PKEY_TYPE_CCA_ECC) {
186 u64 cur_mkvp = 0, old_mkvp = 0;
187
188 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
189 cur_mkvp = *((u64 *)cur_mkvp);
190 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
191 old_mkvp = *((u64 *)alt_mkvp);
192 rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
193 ZCRYPT_CEX7, APKA_MK_SET,
194 cur_mkvp, old_mkvp, xflags);
195 if (rc)
196 goto out;
197
198 } else {
199 PKEY_DBF_ERR("%s unknown/unsupported key type %d",
200 __func__, (int)ktype);
201 return -EINVAL;
202 }
203
204 if (apqns) {
205 if (*nr_apqns < _nr_apqns)
206 rc = -ENOSPC;
207 else
208 memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
209 }
210 *nr_apqns = _nr_apqns;
211
212out:
213 pr_debug("rc=%d\n", rc);
214 return rc;
215}
216
217static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
218 const u8 *key, u32 keylen,
219 u8 *protkey, u32 *protkeylen, u32 *protkeytype,
220 u32 pflags)
221{
222 struct keytoken_header *hdr = (struct keytoken_header *)key;
223 struct pkey_apqn _apqns[MAXAPQNSINLIST];
224 u32 xflags;
225 int i, rc;
226
227 xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
228
229 if (keylen < sizeof(*hdr))
230 return -EINVAL;
231
232 if (hdr->type == TOKTYPE_CCA_INTERNAL &&
233 hdr->version == TOKVER_CCA_AES) {
234 /* CCA AES data key */
235 if (keylen < sizeof(struct secaeskeytoken))
236 return -EINVAL;
237 if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
238 return -EINVAL;
239 } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
240 hdr->version == TOKVER_CCA_VLSC) {
241 /* CCA AES cipher key */
242 if (keylen < hdr->len)
243 return -EINVAL;
244 if (cca_check_secaescipherkey(pkey_dbf_info,
245 3, key, 0, 1))
246 return -EINVAL;
247 } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
248 /* CCA ECC (private) key */
249 if (keylen < sizeof(struct eccprivkeytoken))
250 return -EINVAL;
251 if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))
252 return -EINVAL;
253 } else {
254 PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n",
255 __func__, hdr->type, hdr->version);
256 return -EINVAL;
257 }
258
259 zcrypt_wait_api_operational();
260
261 if (!apqns || (nr_apqns == 1 &&
262 apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
263 nr_apqns = MAXAPQNSINLIST;
264 rc = cca_apqns4key(key, keylen, 0, _apqns, &nr_apqns, pflags);
265 if (rc)
266 goto out;
267 apqns = _apqns;
268 }
269
270 for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
271 if (hdr->type == TOKTYPE_CCA_INTERNAL &&
272 hdr->version == TOKVER_CCA_AES) {
273 rc = cca_sec2protkey(apqns[i].card, apqns[i].domain,
274 key, protkey,
275 protkeylen, protkeytype, xflags);
276 } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
277 hdr->version == TOKVER_CCA_VLSC) {
278 rc = cca_cipher2protkey(apqns[i].card, apqns[i].domain,
279 key, protkey,
280 protkeylen, protkeytype, xflags);
281 } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
282 rc = cca_ecc2protkey(apqns[i].card, apqns[i].domain,
283 key, protkey,
284 protkeylen, protkeytype, xflags);
285 } else {
286 rc = -EINVAL;
287 break;
288 }
289 }
290
291out:
292 pr_debug("rc=%d\n", rc);
293 return rc;
294}
295
296/*
297 * Generate CCA secure key.
298 * As of now only CCA AES Data or Cipher secure keys are
299 * supported.
300 * keytype is one of the PKEY_KEYTYPE_* constants,
301 * subtype may be 0 or PKEY_TYPE_CCA_DATA or PKEY_TYPE_CCA_CIPHER,
302 * keybitsize is the bit size of the key (may be 0 for
303 * keytype PKEY_KEYTYPE_AES_*).
304 */
305static int cca_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
306 u32 keytype, u32 subtype,
307 u32 keybitsize, u32 flags,
308 u8 *keybuf, u32 *keybuflen, u32 *_keyinfo, u32 pflags)
309{
310 struct pkey_apqn _apqns[MAXAPQNSINLIST];
311 int i, len, rc;
312 u32 xflags;
313
314 xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
315
316 /* check keytype, subtype, keybitsize */
317 switch (keytype) {
318 case PKEY_KEYTYPE_AES_128:
319 case PKEY_KEYTYPE_AES_192:
320 case PKEY_KEYTYPE_AES_256:
321 len = pkey_keytype_aes_to_size(keytype);
322 if (keybitsize && keybitsize != 8 * len) {
323 PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
324 __func__, keybitsize);
325 return -EINVAL;
326 }
327 keybitsize = 8 * len;
328 switch (subtype) {
329 case PKEY_TYPE_CCA_DATA:
330 case PKEY_TYPE_CCA_CIPHER:
331 break;
332 default:
333 PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",
334 __func__, subtype);
335 return -EINVAL;
336 }
337 break;
338 default:
339 PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",
340 __func__, keytype);
341 return -EINVAL;
342 }
343
344 zcrypt_wait_api_operational();
345
346 if (!apqns || (nr_apqns == 1 &&
347 apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
348 nr_apqns = MAXAPQNSINLIST;
349 rc = cca_apqns4type(subtype, NULL, NULL, 0,
350 _apqns, &nr_apqns, pflags);
351 if (rc)
352 goto out;
353 apqns = _apqns;
354 }
355
356 for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
357 if (subtype == PKEY_TYPE_CCA_CIPHER) {
358 rc = cca_gencipherkey(apqns[i].card, apqns[i].domain,
359 keybitsize, flags,
360 keybuf, keybuflen, xflags);
361 } else {
362 /* PKEY_TYPE_CCA_DATA */
363 rc = cca_genseckey(apqns[i].card, apqns[i].domain,
364 keybitsize, keybuf, xflags);
365 *keybuflen = (rc ? 0 : SECKEYBLOBSIZE);
366 }
367 }
368
369out:
370 pr_debug("rc=%d\n", rc);
371 return rc;
372}
373
374/*
375 * Generate CCA secure key with given clear key value.
376 * As of now only CCA AES Data or Cipher secure keys are
377 * supported.
378 * keytype is one of the PKEY_KEYTYPE_* constants,
379 * subtype may be 0 or PKEY_TYPE_CCA_DATA or PKEY_TYPE_CCA_CIPHER,
380 * keybitsize is the bit size of the key (may be 0 for
381 * keytype PKEY_KEYTYPE_AES_*).
382 */
383static int cca_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,
384 u32 keytype, u32 subtype,
385 u32 keybitsize, u32 flags,
386 const u8 *clrkey, u32 clrkeylen,
387 u8 *keybuf, u32 *keybuflen, u32 *_keyinfo, u32 pflags)
388{
389 struct pkey_apqn _apqns[MAXAPQNSINLIST];
390 int i, len, rc;
391 u32 xflags;
392
393 xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
394
395 /* check keytype, subtype, clrkeylen, keybitsize */
396 switch (keytype) {
397 case PKEY_KEYTYPE_AES_128:
398 case PKEY_KEYTYPE_AES_192:
399 case PKEY_KEYTYPE_AES_256:
400 len = pkey_keytype_aes_to_size(keytype);
401 if (keybitsize && keybitsize != 8 * len) {
402 PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
403 __func__, keybitsize);
404 return -EINVAL;
405 }
406 keybitsize = 8 * len;
407 if (clrkeylen != len) {
408 PKEY_DBF_ERR("%s invalid clear key len %d != %d\n",
409 __func__, clrkeylen, len);
410 return -EINVAL;
411 }
412 switch (subtype) {
413 case PKEY_TYPE_CCA_DATA:
414 case PKEY_TYPE_CCA_CIPHER:
415 break;
416 default:
417 PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",
418 __func__, subtype);
419 return -EINVAL;
420 }
421 break;
422 default:
423 PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",
424 __func__, keytype);
425 return -EINVAL;
426 }
427
428 zcrypt_wait_api_operational();
429
430 if (!apqns || (nr_apqns == 1 &&
431 apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
432 nr_apqns = MAXAPQNSINLIST;
433 rc = cca_apqns4type(subtype, NULL, NULL, 0,
434 _apqns, &nr_apqns, pflags);
435 if (rc)
436 goto out;
437 apqns = _apqns;
438 }
439
440 for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
441 if (subtype == PKEY_TYPE_CCA_CIPHER) {
442 rc = cca_clr2cipherkey(apqns[i].card, apqns[i].domain,
443 keybitsize, flags, clrkey,
444 keybuf, keybuflen, xflags);
445 } else {
446 /* PKEY_TYPE_CCA_DATA */
447 rc = cca_clr2seckey(apqns[i].card, apqns[i].domain,
448 keybitsize, clrkey, keybuf, xflags);
449 *keybuflen = (rc ? 0 : SECKEYBLOBSIZE);
450 }
451 }
452
453out:
454 pr_debug("rc=%d\n", rc);
455 return rc;
456}
457
458static int cca_verifykey(const u8 *key, u32 keylen,
459 u16 *card, u16 *dom,
460 u32 *keytype, u32 *keybitsize, u32 *flags, u32 pflags)
461{
462 struct keytoken_header *hdr = (struct keytoken_header *)key;
463 u32 apqns[MAXAPQNSINLIST], nr_apqns = ARRAY_SIZE(apqns);
464 u32 xflags;
465 int rc;
466
467 xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
468
469 if (keylen < sizeof(*hdr))
470 return -EINVAL;
471
472 zcrypt_wait_api_operational();
473
474 if (hdr->type == TOKTYPE_CCA_INTERNAL &&
475 hdr->version == TOKVER_CCA_AES) {
476 struct secaeskeytoken *t = (struct secaeskeytoken *)key;
477
478 rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);
479 if (rc)
480 goto out;
481 *keytype = PKEY_TYPE_CCA_DATA;
482 *keybitsize = t->bitsize;
483 rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
484 ZCRYPT_CEX3C, AES_MK_SET,
485 t->mkvp, 0, xflags);
486 if (!rc)
487 *flags = PKEY_FLAGS_MATCH_CUR_MKVP;
488 if (rc == -ENODEV) {
489 nr_apqns = ARRAY_SIZE(apqns);
490 rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
491 ZCRYPT_CEX3C, AES_MK_SET,
492 0, t->mkvp, xflags);
493 if (!rc)
494 *flags = PKEY_FLAGS_MATCH_ALT_MKVP;
495 }
496 if (rc)
497 goto out;
498
499 *card = ((struct pkey_apqn *)apqns)->card;
500 *dom = ((struct pkey_apqn *)apqns)->domain;
501
502 } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
503 hdr->version == TOKVER_CCA_VLSC) {
504 struct cipherkeytoken *t = (struct cipherkeytoken *)key;
505
506 rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);
507 if (rc)
508 goto out;
509 *keytype = PKEY_TYPE_CCA_CIPHER;
510 *keybitsize = PKEY_SIZE_UNKNOWN;
511 if (!t->plfver && t->wpllen == 512)
512 *keybitsize = PKEY_SIZE_AES_128;
513 else if (!t->plfver && t->wpllen == 576)
514 *keybitsize = PKEY_SIZE_AES_192;
515 else if (!t->plfver && t->wpllen == 640)
516 *keybitsize = PKEY_SIZE_AES_256;
517 rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
518 ZCRYPT_CEX6, AES_MK_SET,
519 t->mkvp0, 0, xflags);
520 if (!rc)
521 *flags = PKEY_FLAGS_MATCH_CUR_MKVP;
522 if (rc == -ENODEV) {
523 nr_apqns = ARRAY_SIZE(apqns);
524 rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
525 ZCRYPT_CEX6, AES_MK_SET,
526 0, t->mkvp0, xflags);
527 if (!rc)
528 *flags = PKEY_FLAGS_MATCH_ALT_MKVP;
529 }
530 if (rc)
531 goto out;
532
533 *card = ((struct pkey_apqn *)apqns)->card;
534 *dom = ((struct pkey_apqn *)apqns)->domain;
535
536 } else {
537 /* unknown/unsupported key blob */
538 rc = -EINVAL;
539 }
540
541out:
542 pr_debug("rc=%d\n", rc);
543 return rc;
544}
545
546/*
547 * This function provides an alternate but usually slow way
548 * to convert a 'clear key token' with AES key material into
549 * a protected key. This is done via an intermediate step
550 * which creates a CCA AES DATA secure key first and then
551 * derives the protected key from this secure key.
552 */
553static int cca_slowpath_key2protkey(const struct pkey_apqn *apqns,
554 size_t nr_apqns,
555 const u8 *key, u32 keylen,
556 u8 *protkey, u32 *protkeylen,
557 u32 *protkeytype, u32 pflags)
558{
559 const struct keytoken_header *hdr = (const struct keytoken_header *)key;
560 const struct clearkeytoken *t = (const struct clearkeytoken *)key;
561 u8 tmpbuf[SECKEYBLOBSIZE]; /* 64 bytes */
562 u32 tmplen, keysize = 0;
563 int i, rc;
564
565 if (keylen < sizeof(*hdr))
566 return -EINVAL;
567
568 if (hdr->type == TOKTYPE_NON_CCA &&
569 hdr->version == TOKVER_CLEAR_KEY)
570 keysize = pkey_keytype_aes_to_size(t->keytype);
571 if (!keysize || t->len != keysize)
572 return -EINVAL;
573
574 /* try two times in case of failure */
575 for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
576 tmplen = SECKEYBLOBSIZE;
577 rc = cca_clr2key(NULL, 0, t->keytype, PKEY_TYPE_CCA_DATA,
578 8 * keysize, 0, t->clearkey, t->len,
579 tmpbuf, &tmplen, NULL, pflags);
580 pr_debug("cca_clr2key()=%d\n", rc);
581 if (rc)
582 continue;
583 rc = cca_key2protkey(NULL, 0, tmpbuf, tmplen,
584 protkey, protkeylen, protkeytype, pflags);
585 pr_debug("cca_key2protkey()=%d\n", rc);
586 }
587
588 pr_debug("rc=%d\n", rc);
589 return rc;
590}
591
592static struct pkey_handler cca_handler = {
593 .module = THIS_MODULE,
594 .name = "PKEY CCA handler",
595 .is_supported_key = is_cca_key,
596 .is_supported_keytype = is_cca_keytype,
597 .key_to_protkey = cca_key2protkey,
598 .slowpath_key_to_protkey = cca_slowpath_key2protkey,
599 .gen_key = cca_gen_key,
600 .clr_to_key = cca_clr2key,
601 .verify_key = cca_verifykey,
602 .apqns_for_key = cca_apqns4key,
603 .apqns_for_keytype = cca_apqns4type,
604};
605
606/*
607 * Module init
608 */
609static int __init pkey_cca_init(void)
610{
611 /* register this module as pkey handler for all the cca stuff */
612 return pkey_handler_register(&cca_handler);
613}
614
615/*
616 * Module exit
617 */
618static void __exit pkey_cca_exit(void)
619{
620 /* unregister this module as pkey handler */
621 pkey_handler_unregister(&cca_handler);
622}
623
624module_init(pkey_cca_init);
625module_exit(pkey_cca_exit);