186fbf5e2SHarald Freudenberger // SPDX-License-Identifier: GPL-2.0
286fbf5e2SHarald Freudenberger /*
386fbf5e2SHarald Freudenberger * pkey cca specific code
486fbf5e2SHarald Freudenberger *
586fbf5e2SHarald Freudenberger * Copyright IBM Corp. 2024
686fbf5e2SHarald Freudenberger */
786fbf5e2SHarald Freudenberger
886fbf5e2SHarald Freudenberger #define KMSG_COMPONENT "pkey"
986fbf5e2SHarald Freudenberger #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1086fbf5e2SHarald Freudenberger
118fcc231cSHarald Freudenberger #include <linux/init.h>
128fcc231cSHarald Freudenberger #include <linux/module.h>
138fcc231cSHarald Freudenberger #include <linux/cpufeature.h>
148fcc231cSHarald Freudenberger
1586fbf5e2SHarald Freudenberger #include "zcrypt_api.h"
1686fbf5e2SHarald Freudenberger #include "zcrypt_ccamisc.h"
1786fbf5e2SHarald Freudenberger #include "pkey_base.h"
1886fbf5e2SHarald Freudenberger
198fcc231cSHarald Freudenberger MODULE_LICENSE("GPL");
208fcc231cSHarald Freudenberger MODULE_AUTHOR("IBM Corporation");
218fcc231cSHarald Freudenberger MODULE_DESCRIPTION("s390 protected key CCA handler");
228fcc231cSHarald Freudenberger
238fcc231cSHarald Freudenberger #if IS_MODULE(CONFIG_PKEY_CCA)
248fcc231cSHarald Freudenberger static struct ap_device_id pkey_cca_card_ids[] = {
258fcc231cSHarald Freudenberger { .dev_type = AP_DEVICE_TYPE_CEX4 },
268fcc231cSHarald Freudenberger { .dev_type = AP_DEVICE_TYPE_CEX5 },
278fcc231cSHarald Freudenberger { .dev_type = AP_DEVICE_TYPE_CEX6 },
288fcc231cSHarald Freudenberger { .dev_type = AP_DEVICE_TYPE_CEX7 },
298fcc231cSHarald Freudenberger { .dev_type = AP_DEVICE_TYPE_CEX8 },
308fcc231cSHarald Freudenberger { /* end of list */ },
318fcc231cSHarald Freudenberger };
328fcc231cSHarald Freudenberger MODULE_DEVICE_TABLE(ap, pkey_cca_card_ids);
338fcc231cSHarald Freudenberger #endif
348fcc231cSHarald Freudenberger
3586fbf5e2SHarald Freudenberger /*
3686fbf5e2SHarald Freudenberger * Check key blob for known and supported CCA key.
3786fbf5e2SHarald Freudenberger */
is_cca_key(const u8 * key,u32 keylen)388fcc231cSHarald Freudenberger static bool is_cca_key(const u8 *key, u32 keylen)
3986fbf5e2SHarald Freudenberger {
4086fbf5e2SHarald Freudenberger struct keytoken_header *hdr = (struct keytoken_header *)key;
4186fbf5e2SHarald Freudenberger
4286fbf5e2SHarald Freudenberger if (keylen < sizeof(*hdr))
4386fbf5e2SHarald Freudenberger return false;
4486fbf5e2SHarald Freudenberger
4586fbf5e2SHarald Freudenberger switch (hdr->type) {
4686fbf5e2SHarald Freudenberger case TOKTYPE_CCA_INTERNAL:
4786fbf5e2SHarald Freudenberger switch (hdr->version) {
4886fbf5e2SHarald Freudenberger case TOKVER_CCA_AES:
4986fbf5e2SHarald Freudenberger case TOKVER_CCA_VLSC:
5086fbf5e2SHarald Freudenberger return true;
5186fbf5e2SHarald Freudenberger default:
5286fbf5e2SHarald Freudenberger return false;
5386fbf5e2SHarald Freudenberger }
5486fbf5e2SHarald Freudenberger case TOKTYPE_CCA_INTERNAL_PKA:
5586fbf5e2SHarald Freudenberger return true;
5686fbf5e2SHarald Freudenberger default:
5786fbf5e2SHarald Freudenberger return false;
5886fbf5e2SHarald Freudenberger }
5986fbf5e2SHarald Freudenberger }
6086fbf5e2SHarald Freudenberger
is_cca_keytype(enum pkey_key_type key_type)618fcc231cSHarald Freudenberger static bool is_cca_keytype(enum pkey_key_type key_type)
6286fbf5e2SHarald Freudenberger {
6386fbf5e2SHarald Freudenberger switch (key_type) {
6486fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_DATA:
6586fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_CIPHER:
6686fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_ECC:
6786fbf5e2SHarald Freudenberger return true;
6886fbf5e2SHarald Freudenberger default:
6986fbf5e2SHarald Freudenberger return false;
7086fbf5e2SHarald Freudenberger }
7186fbf5e2SHarald Freudenberger }
7286fbf5e2SHarald Freudenberger
cca_apqns4key(const u8 * key,u32 keylen,u32 flags,struct pkey_apqn * apqns,size_t * nr_apqns)738fcc231cSHarald Freudenberger static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,
748fcc231cSHarald Freudenberger struct pkey_apqn *apqns, size_t *nr_apqns)
758fcc231cSHarald Freudenberger {
768fcc231cSHarald Freudenberger struct keytoken_header *hdr = (struct keytoken_header *)key;
778fcc231cSHarald Freudenberger u32 _nr_apqns, *_apqns = NULL;
788fcc231cSHarald Freudenberger int rc;
798fcc231cSHarald Freudenberger
808fcc231cSHarald Freudenberger if (!flags)
818fcc231cSHarald Freudenberger flags = PKEY_FLAGS_MATCH_CUR_MKVP | PKEY_FLAGS_MATCH_ALT_MKVP;
828fcc231cSHarald Freudenberger
838fcc231cSHarald Freudenberger if (keylen < sizeof(struct keytoken_header))
848fcc231cSHarald Freudenberger return -EINVAL;
858fcc231cSHarald Freudenberger
868fcc231cSHarald Freudenberger zcrypt_wait_api_operational();
878fcc231cSHarald Freudenberger
888fcc231cSHarald Freudenberger if (hdr->type == TOKTYPE_CCA_INTERNAL) {
898fcc231cSHarald Freudenberger u64 cur_mkvp = 0, old_mkvp = 0;
908fcc231cSHarald Freudenberger int minhwtype = ZCRYPT_CEX3C;
918fcc231cSHarald Freudenberger
928fcc231cSHarald Freudenberger if (hdr->version == TOKVER_CCA_AES) {
938fcc231cSHarald Freudenberger struct secaeskeytoken *t = (struct secaeskeytoken *)key;
948fcc231cSHarald Freudenberger
958fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
968fcc231cSHarald Freudenberger cur_mkvp = t->mkvp;
978fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
988fcc231cSHarald Freudenberger old_mkvp = t->mkvp;
998fcc231cSHarald Freudenberger } else if (hdr->version == TOKVER_CCA_VLSC) {
1008fcc231cSHarald Freudenberger struct cipherkeytoken *t = (struct cipherkeytoken *)key;
1018fcc231cSHarald Freudenberger
1028fcc231cSHarald Freudenberger minhwtype = ZCRYPT_CEX6;
1038fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
1048fcc231cSHarald Freudenberger cur_mkvp = t->mkvp0;
1058fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
1068fcc231cSHarald Freudenberger old_mkvp = t->mkvp0;
1078fcc231cSHarald Freudenberger } else {
1088fcc231cSHarald Freudenberger /* unknown CCA internal token type */
1098fcc231cSHarald Freudenberger return -EINVAL;
1108fcc231cSHarald Freudenberger }
1118fcc231cSHarald Freudenberger rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
1128fcc231cSHarald Freudenberger minhwtype, AES_MK_SET,
1138fcc231cSHarald Freudenberger cur_mkvp, old_mkvp, 1);
1148fcc231cSHarald Freudenberger if (rc)
1158fcc231cSHarald Freudenberger goto out;
1168fcc231cSHarald Freudenberger
1178fcc231cSHarald Freudenberger } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
1188fcc231cSHarald Freudenberger struct eccprivkeytoken *t = (struct eccprivkeytoken *)key;
1198fcc231cSHarald Freudenberger u64 cur_mkvp = 0, old_mkvp = 0;
1208fcc231cSHarald Freudenberger
1218fcc231cSHarald Freudenberger if (t->secid == 0x20) {
1228fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
1238fcc231cSHarald Freudenberger cur_mkvp = t->mkvp;
1248fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
1258fcc231cSHarald Freudenberger old_mkvp = t->mkvp;
1268fcc231cSHarald Freudenberger } else {
1278fcc231cSHarald Freudenberger /* unknown CCA internal 2 token type */
1288fcc231cSHarald Freudenberger return -EINVAL;
1298fcc231cSHarald Freudenberger }
1308fcc231cSHarald Freudenberger rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
1318fcc231cSHarald Freudenberger ZCRYPT_CEX7, APKA_MK_SET,
1328fcc231cSHarald Freudenberger cur_mkvp, old_mkvp, 1);
1338fcc231cSHarald Freudenberger if (rc)
1348fcc231cSHarald Freudenberger goto out;
1358fcc231cSHarald Freudenberger
1368fcc231cSHarald Freudenberger } else {
1378fcc231cSHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n",
1388fcc231cSHarald Freudenberger __func__, hdr->type, hdr->version);
1398fcc231cSHarald Freudenberger return -EINVAL;
1408fcc231cSHarald Freudenberger }
1418fcc231cSHarald Freudenberger
1428fcc231cSHarald Freudenberger if (apqns) {
1438fcc231cSHarald Freudenberger if (*nr_apqns < _nr_apqns)
1448fcc231cSHarald Freudenberger rc = -ENOSPC;
1458fcc231cSHarald Freudenberger else
1468fcc231cSHarald Freudenberger memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
1478fcc231cSHarald Freudenberger }
1488fcc231cSHarald Freudenberger *nr_apqns = _nr_apqns;
1498fcc231cSHarald Freudenberger
1508fcc231cSHarald Freudenberger out:
1518fcc231cSHarald Freudenberger kfree(_apqns);
1528fcc231cSHarald Freudenberger pr_debug("rc=%d\n", rc);
1538fcc231cSHarald Freudenberger return rc;
1548fcc231cSHarald Freudenberger }
1558fcc231cSHarald Freudenberger
cca_apqns4type(enum pkey_key_type ktype,u8 cur_mkvp[32],u8 alt_mkvp[32],u32 flags,struct pkey_apqn * apqns,size_t * nr_apqns)1568fcc231cSHarald Freudenberger static int cca_apqns4type(enum pkey_key_type ktype,
1578fcc231cSHarald Freudenberger u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
1588fcc231cSHarald Freudenberger struct pkey_apqn *apqns, size_t *nr_apqns)
1598fcc231cSHarald Freudenberger {
1608fcc231cSHarald Freudenberger u32 _nr_apqns, *_apqns = NULL;
1618fcc231cSHarald Freudenberger int rc;
1628fcc231cSHarald Freudenberger
1638fcc231cSHarald Freudenberger zcrypt_wait_api_operational();
1648fcc231cSHarald Freudenberger
1658fcc231cSHarald Freudenberger if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {
1668fcc231cSHarald Freudenberger u64 cur_mkvp = 0, old_mkvp = 0;
1678fcc231cSHarald Freudenberger int minhwtype = ZCRYPT_CEX3C;
1688fcc231cSHarald Freudenberger
1698fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
1708fcc231cSHarald Freudenberger cur_mkvp = *((u64 *)cur_mkvp);
1718fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
1728fcc231cSHarald Freudenberger old_mkvp = *((u64 *)alt_mkvp);
1738fcc231cSHarald Freudenberger if (ktype == PKEY_TYPE_CCA_CIPHER)
1748fcc231cSHarald Freudenberger minhwtype = ZCRYPT_CEX6;
1758fcc231cSHarald Freudenberger rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
1768fcc231cSHarald Freudenberger minhwtype, AES_MK_SET,
1778fcc231cSHarald Freudenberger cur_mkvp, old_mkvp, 1);
1788fcc231cSHarald Freudenberger if (rc)
1798fcc231cSHarald Freudenberger goto out;
1808fcc231cSHarald Freudenberger
1818fcc231cSHarald Freudenberger } else if (ktype == PKEY_TYPE_CCA_ECC) {
1828fcc231cSHarald Freudenberger u64 cur_mkvp = 0, old_mkvp = 0;
1838fcc231cSHarald Freudenberger
1848fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
1858fcc231cSHarald Freudenberger cur_mkvp = *((u64 *)cur_mkvp);
1868fcc231cSHarald Freudenberger if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
1878fcc231cSHarald Freudenberger old_mkvp = *((u64 *)alt_mkvp);
1888fcc231cSHarald Freudenberger rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
1898fcc231cSHarald Freudenberger ZCRYPT_CEX7, APKA_MK_SET,
1908fcc231cSHarald Freudenberger cur_mkvp, old_mkvp, 1);
1918fcc231cSHarald Freudenberger if (rc)
1928fcc231cSHarald Freudenberger goto out;
1938fcc231cSHarald Freudenberger
1948fcc231cSHarald Freudenberger } else {
1958fcc231cSHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported key type %d",
1968fcc231cSHarald Freudenberger __func__, (int)ktype);
1978fcc231cSHarald Freudenberger return -EINVAL;
1988fcc231cSHarald Freudenberger }
1998fcc231cSHarald Freudenberger
2008fcc231cSHarald Freudenberger if (apqns) {
2018fcc231cSHarald Freudenberger if (*nr_apqns < _nr_apqns)
2028fcc231cSHarald Freudenberger rc = -ENOSPC;
2038fcc231cSHarald Freudenberger else
2048fcc231cSHarald Freudenberger memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
2058fcc231cSHarald Freudenberger }
2068fcc231cSHarald Freudenberger *nr_apqns = _nr_apqns;
2078fcc231cSHarald Freudenberger
2088fcc231cSHarald Freudenberger out:
2098fcc231cSHarald Freudenberger kfree(_apqns);
2108fcc231cSHarald Freudenberger pr_debug("rc=%d\n", rc);
2118fcc231cSHarald Freudenberger return rc;
2128fcc231cSHarald Freudenberger }
2138fcc231cSHarald Freudenberger
cca_key2protkey(const struct pkey_apqn * apqns,size_t nr_apqns,const u8 * key,u32 keylen,u8 * protkey,u32 * protkeylen,u32 * protkeytype)2148fcc231cSHarald Freudenberger static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
21586fbf5e2SHarald Freudenberger const u8 *key, u32 keylen,
21686fbf5e2SHarald Freudenberger u8 *protkey, u32 *protkeylen, u32 *protkeytype)
21786fbf5e2SHarald Freudenberger {
21886fbf5e2SHarald Freudenberger struct keytoken_header *hdr = (struct keytoken_header *)key;
2198fcc231cSHarald Freudenberger struct pkey_apqn *local_apqns = NULL;
2208fcc231cSHarald Freudenberger int i, rc;
22186fbf5e2SHarald Freudenberger
22286fbf5e2SHarald Freudenberger if (keylen < sizeof(*hdr))
22386fbf5e2SHarald Freudenberger return -EINVAL;
22486fbf5e2SHarald Freudenberger
22586fbf5e2SHarald Freudenberger if (hdr->type == TOKTYPE_CCA_INTERNAL &&
22686fbf5e2SHarald Freudenberger hdr->version == TOKVER_CCA_AES) {
22786fbf5e2SHarald Freudenberger /* CCA AES data key */
22886fbf5e2SHarald Freudenberger if (keylen != sizeof(struct secaeskeytoken))
22986fbf5e2SHarald Freudenberger return -EINVAL;
23086fbf5e2SHarald Freudenberger if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
23186fbf5e2SHarald Freudenberger return -EINVAL;
23286fbf5e2SHarald Freudenberger } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
23386fbf5e2SHarald Freudenberger hdr->version == TOKVER_CCA_VLSC) {
23486fbf5e2SHarald Freudenberger /* CCA AES cipher key */
23586fbf5e2SHarald Freudenberger if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
23686fbf5e2SHarald Freudenberger return -EINVAL;
23786fbf5e2SHarald Freudenberger if (cca_check_secaescipherkey(pkey_dbf_info,
23886fbf5e2SHarald Freudenberger 3, key, 0, 1))
23986fbf5e2SHarald Freudenberger return -EINVAL;
24086fbf5e2SHarald Freudenberger } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
24186fbf5e2SHarald Freudenberger /* CCA ECC (private) key */
24286fbf5e2SHarald Freudenberger if (keylen < sizeof(struct eccprivkeytoken))
24386fbf5e2SHarald Freudenberger return -EINVAL;
24486fbf5e2SHarald Freudenberger if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))
24586fbf5e2SHarald Freudenberger return -EINVAL;
24686fbf5e2SHarald Freudenberger } else {
24786fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n",
24886fbf5e2SHarald Freudenberger __func__, hdr->type, hdr->version);
2498fcc231cSHarald Freudenberger return -EINVAL;
25086fbf5e2SHarald Freudenberger }
25186fbf5e2SHarald Freudenberger
2528fcc231cSHarald Freudenberger zcrypt_wait_api_operational();
2538fcc231cSHarald Freudenberger
2548fcc231cSHarald Freudenberger if (!apqns || (nr_apqns == 1 &&
2558fcc231cSHarald Freudenberger apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
2568fcc231cSHarald Freudenberger nr_apqns = MAXAPQNSINLIST;
2578fcc231cSHarald Freudenberger local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
2588fcc231cSHarald Freudenberger GFP_KERNEL);
2598fcc231cSHarald Freudenberger if (!local_apqns)
2608fcc231cSHarald Freudenberger return -ENOMEM;
2618fcc231cSHarald Freudenberger rc = cca_apqns4key(key, keylen, 0, local_apqns, &nr_apqns);
2628fcc231cSHarald Freudenberger if (rc)
2638fcc231cSHarald Freudenberger goto out;
2648fcc231cSHarald Freudenberger apqns = local_apqns;
2658fcc231cSHarald Freudenberger }
2668fcc231cSHarald Freudenberger
2678fcc231cSHarald Freudenberger for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
2688fcc231cSHarald Freudenberger if (hdr->type == TOKTYPE_CCA_INTERNAL &&
2698fcc231cSHarald Freudenberger hdr->version == TOKVER_CCA_AES) {
2708fcc231cSHarald Freudenberger rc = cca_sec2protkey(apqns[i].card, apqns[i].domain,
2718fcc231cSHarald Freudenberger key, protkey,
2728fcc231cSHarald Freudenberger protkeylen, protkeytype);
2738fcc231cSHarald Freudenberger } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
2748fcc231cSHarald Freudenberger hdr->version == TOKVER_CCA_VLSC) {
2758fcc231cSHarald Freudenberger rc = cca_cipher2protkey(apqns[i].card, apqns[i].domain,
2768fcc231cSHarald Freudenberger key, protkey,
2778fcc231cSHarald Freudenberger protkeylen, protkeytype);
2788fcc231cSHarald Freudenberger } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
2798fcc231cSHarald Freudenberger rc = cca_ecc2protkey(apqns[i].card, apqns[i].domain,
2808fcc231cSHarald Freudenberger key, protkey,
2818fcc231cSHarald Freudenberger protkeylen, protkeytype);
2828fcc231cSHarald Freudenberger } else {
2838fcc231cSHarald Freudenberger rc = -EINVAL;
2848fcc231cSHarald Freudenberger break;
2858fcc231cSHarald Freudenberger }
2868fcc231cSHarald Freudenberger }
2878fcc231cSHarald Freudenberger
2888fcc231cSHarald Freudenberger out:
2898fcc231cSHarald Freudenberger kfree(local_apqns);
2908fcc231cSHarald Freudenberger pr_debug("rc=%d\n", rc);
29186fbf5e2SHarald Freudenberger return rc;
29286fbf5e2SHarald Freudenberger }
29386fbf5e2SHarald Freudenberger
29486fbf5e2SHarald Freudenberger /*
29586fbf5e2SHarald Freudenberger * Generate CCA secure key.
29686fbf5e2SHarald Freudenberger * As of now only CCA AES Data or Cipher secure keys are
29786fbf5e2SHarald Freudenberger * supported.
29886fbf5e2SHarald Freudenberger * keytype is one of the PKEY_KEYTYPE_* constants,
29986fbf5e2SHarald Freudenberger * subtype may be 0 or PKEY_TYPE_CCA_DATA or PKEY_TYPE_CCA_CIPHER,
30086fbf5e2SHarald Freudenberger * keybitsize is the bit size of the key (may be 0 for
30186fbf5e2SHarald Freudenberger * keytype PKEY_KEYTYPE_AES_*).
30286fbf5e2SHarald Freudenberger */
cca_gen_key(const struct pkey_apqn * apqns,size_t nr_apqns,u32 keytype,u32 subtype,u32 keybitsize,u32 flags,u8 * keybuf,u32 * keybuflen,u32 * _keyinfo)3038fcc231cSHarald Freudenberger static int cca_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
30486fbf5e2SHarald Freudenberger u32 keytype, u32 subtype,
30586fbf5e2SHarald Freudenberger u32 keybitsize, u32 flags,
306ea88e171SHarald Freudenberger u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)
30786fbf5e2SHarald Freudenberger {
3088fcc231cSHarald Freudenberger struct pkey_apqn *local_apqns = NULL;
3098fcc231cSHarald Freudenberger int i, len, rc;
31086fbf5e2SHarald Freudenberger
31186fbf5e2SHarald Freudenberger /* check keytype, subtype, keybitsize */
31286fbf5e2SHarald Freudenberger switch (keytype) {
31386fbf5e2SHarald Freudenberger case PKEY_KEYTYPE_AES_128:
31486fbf5e2SHarald Freudenberger case PKEY_KEYTYPE_AES_192:
31586fbf5e2SHarald Freudenberger case PKEY_KEYTYPE_AES_256:
31686fbf5e2SHarald Freudenberger len = pkey_keytype_aes_to_size(keytype);
31786fbf5e2SHarald Freudenberger if (keybitsize && keybitsize != 8 * len) {
31886fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
31986fbf5e2SHarald Freudenberger __func__, keybitsize);
32086fbf5e2SHarald Freudenberger return -EINVAL;
32186fbf5e2SHarald Freudenberger }
32286fbf5e2SHarald Freudenberger keybitsize = 8 * len;
32386fbf5e2SHarald Freudenberger switch (subtype) {
32486fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_DATA:
32586fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_CIPHER:
32686fbf5e2SHarald Freudenberger break;
32786fbf5e2SHarald Freudenberger default:
32886fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",
32986fbf5e2SHarald Freudenberger __func__, subtype);
33086fbf5e2SHarald Freudenberger return -EINVAL;
33186fbf5e2SHarald Freudenberger }
33286fbf5e2SHarald Freudenberger break;
33386fbf5e2SHarald Freudenberger default:
33486fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",
33586fbf5e2SHarald Freudenberger __func__, keytype);
33686fbf5e2SHarald Freudenberger return -EINVAL;
33786fbf5e2SHarald Freudenberger }
33886fbf5e2SHarald Freudenberger
33986fbf5e2SHarald Freudenberger zcrypt_wait_api_operational();
34086fbf5e2SHarald Freudenberger
3418fcc231cSHarald Freudenberger if (!apqns || (nr_apqns == 1 &&
3428fcc231cSHarald Freudenberger apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
3438fcc231cSHarald Freudenberger nr_apqns = MAXAPQNSINLIST;
3448fcc231cSHarald Freudenberger local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
3458fcc231cSHarald Freudenberger GFP_KERNEL);
3468fcc231cSHarald Freudenberger if (!local_apqns)
3478fcc231cSHarald Freudenberger return -ENOMEM;
3488fcc231cSHarald Freudenberger rc = cca_apqns4type(subtype, NULL, NULL, 0,
3498fcc231cSHarald Freudenberger local_apqns, &nr_apqns);
3508fcc231cSHarald Freudenberger if (rc)
3518fcc231cSHarald Freudenberger goto out;
3528fcc231cSHarald Freudenberger apqns = local_apqns;
35386fbf5e2SHarald Freudenberger }
35486fbf5e2SHarald Freudenberger
3558fcc231cSHarald Freudenberger for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
3568fcc231cSHarald Freudenberger if (subtype == PKEY_TYPE_CCA_CIPHER) {
3578fcc231cSHarald Freudenberger rc = cca_gencipherkey(apqns[i].card, apqns[i].domain,
3588fcc231cSHarald Freudenberger keybitsize, flags,
3598fcc231cSHarald Freudenberger keybuf, keybuflen);
3608fcc231cSHarald Freudenberger } else {
3618fcc231cSHarald Freudenberger /* PKEY_TYPE_CCA_DATA */
3628fcc231cSHarald Freudenberger rc = cca_genseckey(apqns[i].card, apqns[i].domain,
3638fcc231cSHarald Freudenberger keybitsize, keybuf);
3648fcc231cSHarald Freudenberger *keybuflen = (rc ? 0 : SECKEYBLOBSIZE);
3658fcc231cSHarald Freudenberger }
3668fcc231cSHarald Freudenberger }
3678fcc231cSHarald Freudenberger
3688fcc231cSHarald Freudenberger out:
3698fcc231cSHarald Freudenberger kfree(local_apqns);
3708fcc231cSHarald Freudenberger pr_debug("rc=%d\n", rc);
37186fbf5e2SHarald Freudenberger return rc;
37286fbf5e2SHarald Freudenberger }
37386fbf5e2SHarald Freudenberger
37486fbf5e2SHarald Freudenberger /*
37586fbf5e2SHarald Freudenberger * Generate CCA secure key with given clear key value.
37686fbf5e2SHarald Freudenberger * As of now only CCA AES Data or Cipher secure keys are
37786fbf5e2SHarald Freudenberger * supported.
37886fbf5e2SHarald Freudenberger * keytype is one of the PKEY_KEYTYPE_* constants,
37986fbf5e2SHarald Freudenberger * subtype may be 0 or PKEY_TYPE_CCA_DATA or PKEY_TYPE_CCA_CIPHER,
38086fbf5e2SHarald Freudenberger * keybitsize is the bit size of the key (may be 0 for
38186fbf5e2SHarald Freudenberger * keytype PKEY_KEYTYPE_AES_*).
38286fbf5e2SHarald Freudenberger */
cca_clr2key(const struct pkey_apqn * apqns,size_t nr_apqns,u32 keytype,u32 subtype,u32 keybitsize,u32 flags,const u8 * clrkey,u32 clrkeylen,u8 * keybuf,u32 * keybuflen,u32 * _keyinfo)3838fcc231cSHarald Freudenberger static int cca_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,
38486fbf5e2SHarald Freudenberger u32 keytype, u32 subtype,
38586fbf5e2SHarald Freudenberger u32 keybitsize, u32 flags,
38686fbf5e2SHarald Freudenberger const u8 *clrkey, u32 clrkeylen,
387ea88e171SHarald Freudenberger u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)
38886fbf5e2SHarald Freudenberger {
3898fcc231cSHarald Freudenberger struct pkey_apqn *local_apqns = NULL;
3908fcc231cSHarald Freudenberger int i, len, rc;
39186fbf5e2SHarald Freudenberger
39286fbf5e2SHarald Freudenberger /* check keytype, subtype, clrkeylen, keybitsize */
39386fbf5e2SHarald Freudenberger switch (keytype) {
39486fbf5e2SHarald Freudenberger case PKEY_KEYTYPE_AES_128:
39586fbf5e2SHarald Freudenberger case PKEY_KEYTYPE_AES_192:
39686fbf5e2SHarald Freudenberger case PKEY_KEYTYPE_AES_256:
39786fbf5e2SHarald Freudenberger len = pkey_keytype_aes_to_size(keytype);
39886fbf5e2SHarald Freudenberger if (keybitsize && keybitsize != 8 * len) {
39986fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
40086fbf5e2SHarald Freudenberger __func__, keybitsize);
40186fbf5e2SHarald Freudenberger return -EINVAL;
40286fbf5e2SHarald Freudenberger }
40386fbf5e2SHarald Freudenberger keybitsize = 8 * len;
40486fbf5e2SHarald Freudenberger if (clrkeylen != len) {
40586fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s invalid clear key len %d != %d\n",
40686fbf5e2SHarald Freudenberger __func__, clrkeylen, len);
40786fbf5e2SHarald Freudenberger return -EINVAL;
40886fbf5e2SHarald Freudenberger }
40986fbf5e2SHarald Freudenberger switch (subtype) {
41086fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_DATA:
41186fbf5e2SHarald Freudenberger case PKEY_TYPE_CCA_CIPHER:
41286fbf5e2SHarald Freudenberger break;
41386fbf5e2SHarald Freudenberger default:
41486fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",
41586fbf5e2SHarald Freudenberger __func__, subtype);
41686fbf5e2SHarald Freudenberger return -EINVAL;
41786fbf5e2SHarald Freudenberger }
41886fbf5e2SHarald Freudenberger break;
41986fbf5e2SHarald Freudenberger default:
42086fbf5e2SHarald Freudenberger PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",
42186fbf5e2SHarald Freudenberger __func__, keytype);
42286fbf5e2SHarald Freudenberger return -EINVAL;
42386fbf5e2SHarald Freudenberger }
42486fbf5e2SHarald Freudenberger
42586fbf5e2SHarald Freudenberger zcrypt_wait_api_operational();
42686fbf5e2SHarald Freudenberger
4278fcc231cSHarald Freudenberger if (!apqns || (nr_apqns == 1 &&
4288fcc231cSHarald Freudenberger apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
4298fcc231cSHarald Freudenberger nr_apqns = MAXAPQNSINLIST;
4308fcc231cSHarald Freudenberger local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
4318fcc231cSHarald Freudenberger GFP_KERNEL);
4328fcc231cSHarald Freudenberger if (!local_apqns)
4338fcc231cSHarald Freudenberger return -ENOMEM;
4348fcc231cSHarald Freudenberger rc = cca_apqns4type(subtype, NULL, NULL, 0,
4358fcc231cSHarald Freudenberger local_apqns, &nr_apqns);
4368fcc231cSHarald Freudenberger if (rc)
4378fcc231cSHarald Freudenberger goto out;
4388fcc231cSHarald Freudenberger apqns = local_apqns;
43986fbf5e2SHarald Freudenberger }
44086fbf5e2SHarald Freudenberger
4418fcc231cSHarald Freudenberger for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
4428fcc231cSHarald Freudenberger if (subtype == PKEY_TYPE_CCA_CIPHER) {
4438fcc231cSHarald Freudenberger rc = cca_clr2cipherkey(apqns[i].card, apqns[i].domain,
4448fcc231cSHarald Freudenberger keybitsize, flags, clrkey,
4458fcc231cSHarald Freudenberger keybuf, keybuflen);
4468fcc231cSHarald Freudenberger } else {
4478fcc231cSHarald Freudenberger /* PKEY_TYPE_CCA_DATA */
4488fcc231cSHarald Freudenberger rc = cca_clr2seckey(apqns[i].card, apqns[i].domain,
4498fcc231cSHarald Freudenberger keybitsize, clrkey, keybuf);
4508fcc231cSHarald Freudenberger *keybuflen = (rc ? 0 : SECKEYBLOBSIZE);
4518fcc231cSHarald Freudenberger }
4528fcc231cSHarald Freudenberger }
4538fcc231cSHarald Freudenberger
4548fcc231cSHarald Freudenberger out:
4558fcc231cSHarald Freudenberger kfree(local_apqns);
4568fcc231cSHarald Freudenberger pr_debug("rc=%d\n", rc);
45786fbf5e2SHarald Freudenberger return rc;
45886fbf5e2SHarald Freudenberger }
45986fbf5e2SHarald Freudenberger
cca_verifykey(const u8 * key,u32 keylen,u16 * card,u16 * dom,u32 * keytype,u32 * keybitsize,u32 * flags)4608fcc231cSHarald Freudenberger static int cca_verifykey(const u8 *key, u32 keylen,
46186fbf5e2SHarald Freudenberger u16 *card, u16 *dom,
46286fbf5e2SHarald Freudenberger u32 *keytype, u32 *keybitsize, u32 *flags)
46386fbf5e2SHarald Freudenberger {
46486fbf5e2SHarald Freudenberger struct keytoken_header *hdr = (struct keytoken_header *)key;
46586fbf5e2SHarald Freudenberger u32 nr_apqns, *apqns = NULL;
46686fbf5e2SHarald Freudenberger int rc;
46786fbf5e2SHarald Freudenberger
46886fbf5e2SHarald Freudenberger if (keylen < sizeof(*hdr))
46986fbf5e2SHarald Freudenberger return -EINVAL;
47086fbf5e2SHarald Freudenberger
47186fbf5e2SHarald Freudenberger zcrypt_wait_api_operational();
47286fbf5e2SHarald Freudenberger
47386fbf5e2SHarald Freudenberger if (hdr->type == TOKTYPE_CCA_INTERNAL &&
47486fbf5e2SHarald Freudenberger hdr->version == TOKVER_CCA_AES) {
47586fbf5e2SHarald Freudenberger struct secaeskeytoken *t = (struct secaeskeytoken *)key;
47686fbf5e2SHarald Freudenberger
47786fbf5e2SHarald Freudenberger rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);
47886fbf5e2SHarald Freudenberger if (rc)
47986fbf5e2SHarald Freudenberger goto out;
48086fbf5e2SHarald Freudenberger *keytype = PKEY_TYPE_CCA_DATA;
48186fbf5e2SHarald Freudenberger *keybitsize = t->bitsize;
48286fbf5e2SHarald Freudenberger rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
48386fbf5e2SHarald Freudenberger ZCRYPT_CEX3C, AES_MK_SET,
48486fbf5e2SHarald Freudenberger t->mkvp, 0, 1);
48586fbf5e2SHarald Freudenberger if (!rc)
48686fbf5e2SHarald Freudenberger *flags = PKEY_FLAGS_MATCH_CUR_MKVP;
48786fbf5e2SHarald Freudenberger if (rc == -ENODEV) {
48886fbf5e2SHarald Freudenberger rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
48986fbf5e2SHarald Freudenberger ZCRYPT_CEX3C, AES_MK_SET,
49086fbf5e2SHarald Freudenberger 0, t->mkvp, 1);
49186fbf5e2SHarald Freudenberger if (!rc)
49286fbf5e2SHarald Freudenberger *flags = PKEY_FLAGS_MATCH_ALT_MKVP;
49386fbf5e2SHarald Freudenberger }
49486fbf5e2SHarald Freudenberger if (rc)
49586fbf5e2SHarald Freudenberger goto out;
49686fbf5e2SHarald Freudenberger
49786fbf5e2SHarald Freudenberger *card = ((struct pkey_apqn *)apqns)->card;
49886fbf5e2SHarald Freudenberger *dom = ((struct pkey_apqn *)apqns)->domain;
49986fbf5e2SHarald Freudenberger
50086fbf5e2SHarald Freudenberger } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
50186fbf5e2SHarald Freudenberger hdr->version == TOKVER_CCA_VLSC) {
50286fbf5e2SHarald Freudenberger struct cipherkeytoken *t = (struct cipherkeytoken *)key;
50386fbf5e2SHarald Freudenberger
50486fbf5e2SHarald Freudenberger rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);
50586fbf5e2SHarald Freudenberger if (rc)
50686fbf5e2SHarald Freudenberger goto out;
50786fbf5e2SHarald Freudenberger *keytype = PKEY_TYPE_CCA_CIPHER;
50886fbf5e2SHarald Freudenberger *keybitsize = PKEY_SIZE_UNKNOWN;
50986fbf5e2SHarald Freudenberger if (!t->plfver && t->wpllen == 512)
51086fbf5e2SHarald Freudenberger *keybitsize = PKEY_SIZE_AES_128;
51186fbf5e2SHarald Freudenberger else if (!t->plfver && t->wpllen == 576)
51286fbf5e2SHarald Freudenberger *keybitsize = PKEY_SIZE_AES_192;
51386fbf5e2SHarald Freudenberger else if (!t->plfver && t->wpllen == 640)
51486fbf5e2SHarald Freudenberger *keybitsize = PKEY_SIZE_AES_256;
51586fbf5e2SHarald Freudenberger rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
51686fbf5e2SHarald Freudenberger ZCRYPT_CEX6, AES_MK_SET,
51786fbf5e2SHarald Freudenberger t->mkvp0, 0, 1);
51886fbf5e2SHarald Freudenberger if (!rc)
51986fbf5e2SHarald Freudenberger *flags = PKEY_FLAGS_MATCH_CUR_MKVP;
52086fbf5e2SHarald Freudenberger if (rc == -ENODEV) {
52186fbf5e2SHarald Freudenberger rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
52286fbf5e2SHarald Freudenberger ZCRYPT_CEX6, AES_MK_SET,
52386fbf5e2SHarald Freudenberger 0, t->mkvp0, 1);
52486fbf5e2SHarald Freudenberger if (!rc)
52586fbf5e2SHarald Freudenberger *flags = PKEY_FLAGS_MATCH_ALT_MKVP;
52686fbf5e2SHarald Freudenberger }
52786fbf5e2SHarald Freudenberger if (rc)
52886fbf5e2SHarald Freudenberger goto out;
52986fbf5e2SHarald Freudenberger
53086fbf5e2SHarald Freudenberger *card = ((struct pkey_apqn *)apqns)->card;
53186fbf5e2SHarald Freudenberger *dom = ((struct pkey_apqn *)apqns)->domain;
53286fbf5e2SHarald Freudenberger
53386fbf5e2SHarald Freudenberger } else {
53486fbf5e2SHarald Freudenberger /* unknown/unsupported key blob */
53586fbf5e2SHarald Freudenberger rc = -EINVAL;
53686fbf5e2SHarald Freudenberger }
53786fbf5e2SHarald Freudenberger
53886fbf5e2SHarald Freudenberger out:
53986fbf5e2SHarald Freudenberger kfree(apqns);
54086fbf5e2SHarald Freudenberger pr_debug("rc=%d\n", rc);
54186fbf5e2SHarald Freudenberger return rc;
54286fbf5e2SHarald Freudenberger }
54386fbf5e2SHarald Freudenberger
544*2fc401b9SHarald Freudenberger /*
545*2fc401b9SHarald Freudenberger * This function provides an alternate but usually slow way
546*2fc401b9SHarald Freudenberger * to convert a 'clear key token' with AES key material into
547*2fc401b9SHarald Freudenberger * a protected key. This is done via an intermediate step
548*2fc401b9SHarald Freudenberger * which creates a CCA AES DATA secure key first and then
549*2fc401b9SHarald Freudenberger * derives the protected key from this secure key.
550*2fc401b9SHarald Freudenberger */
cca_slowpath_key2protkey(const struct pkey_apqn * apqns,size_t nr_apqns,const u8 * key,u32 keylen,u8 * protkey,u32 * protkeylen,u32 * protkeytype)551*2fc401b9SHarald Freudenberger static int cca_slowpath_key2protkey(const struct pkey_apqn *apqns,
552*2fc401b9SHarald Freudenberger size_t nr_apqns,
553*2fc401b9SHarald Freudenberger const u8 *key, u32 keylen,
554*2fc401b9SHarald Freudenberger u8 *protkey, u32 *protkeylen,
555*2fc401b9SHarald Freudenberger u32 *protkeytype)
556*2fc401b9SHarald Freudenberger {
557*2fc401b9SHarald Freudenberger const struct keytoken_header *hdr = (const struct keytoken_header *)key;
558*2fc401b9SHarald Freudenberger const struct clearkeytoken *t = (const struct clearkeytoken *)key;
559*2fc401b9SHarald Freudenberger u32 tmplen, keysize = 0;
560*2fc401b9SHarald Freudenberger u8 *tmpbuf;
561*2fc401b9SHarald Freudenberger int i, rc;
562*2fc401b9SHarald Freudenberger
563*2fc401b9SHarald Freudenberger if (keylen < sizeof(*hdr))
564*2fc401b9SHarald Freudenberger return -EINVAL;
565*2fc401b9SHarald Freudenberger
566*2fc401b9SHarald Freudenberger if (hdr->type == TOKTYPE_NON_CCA &&
567*2fc401b9SHarald Freudenberger hdr->version == TOKVER_CLEAR_KEY)
568*2fc401b9SHarald Freudenberger keysize = pkey_keytype_aes_to_size(t->keytype);
569*2fc401b9SHarald Freudenberger if (!keysize || t->len != keysize)
570*2fc401b9SHarald Freudenberger return -EINVAL;
571*2fc401b9SHarald Freudenberger
572*2fc401b9SHarald Freudenberger /* alloc tmp key buffer */
573*2fc401b9SHarald Freudenberger tmpbuf = kmalloc(SECKEYBLOBSIZE, GFP_ATOMIC);
574*2fc401b9SHarald Freudenberger if (!tmpbuf)
575*2fc401b9SHarald Freudenberger return -ENOMEM;
576*2fc401b9SHarald Freudenberger
577*2fc401b9SHarald Freudenberger /* try two times in case of failure */
578*2fc401b9SHarald Freudenberger for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
579*2fc401b9SHarald Freudenberger tmplen = SECKEYBLOBSIZE;
580*2fc401b9SHarald Freudenberger rc = cca_clr2key(NULL, 0, t->keytype, PKEY_TYPE_CCA_DATA,
581*2fc401b9SHarald Freudenberger 8 * keysize, 0, t->clearkey, t->len,
582*2fc401b9SHarald Freudenberger tmpbuf, &tmplen, NULL);
583*2fc401b9SHarald Freudenberger pr_debug("cca_clr2key()=%d\n", rc);
584*2fc401b9SHarald Freudenberger if (rc)
585*2fc401b9SHarald Freudenberger continue;
586*2fc401b9SHarald Freudenberger rc = cca_key2protkey(NULL, 0, tmpbuf, tmplen,
587*2fc401b9SHarald Freudenberger protkey, protkeylen, protkeytype);
588*2fc401b9SHarald Freudenberger pr_debug("cca_key2protkey()=%d\n", rc);
589*2fc401b9SHarald Freudenberger }
590*2fc401b9SHarald Freudenberger
591*2fc401b9SHarald Freudenberger kfree(tmpbuf);
592*2fc401b9SHarald Freudenberger pr_debug("rc=%d\n", rc);
593*2fc401b9SHarald Freudenberger return rc;
594*2fc401b9SHarald Freudenberger }
595*2fc401b9SHarald Freudenberger
5968fcc231cSHarald Freudenberger static struct pkey_handler cca_handler = {
5978fcc231cSHarald Freudenberger .module = THIS_MODULE,
5988fcc231cSHarald Freudenberger .name = "PKEY CCA handler",
5998fcc231cSHarald Freudenberger .is_supported_key = is_cca_key,
6008fcc231cSHarald Freudenberger .is_supported_keytype = is_cca_keytype,
6018fcc231cSHarald Freudenberger .key_to_protkey = cca_key2protkey,
602*2fc401b9SHarald Freudenberger .slowpath_key_to_protkey = cca_slowpath_key2protkey,
6038fcc231cSHarald Freudenberger .gen_key = cca_gen_key,
6048fcc231cSHarald Freudenberger .clr_to_key = cca_clr2key,
6058fcc231cSHarald Freudenberger .verify_key = cca_verifykey,
6068fcc231cSHarald Freudenberger .apqns_for_key = cca_apqns4key,
6078fcc231cSHarald Freudenberger .apqns_for_keytype = cca_apqns4type,
6088fcc231cSHarald Freudenberger };
6098fcc231cSHarald Freudenberger
6108fcc231cSHarald Freudenberger /*
6118fcc231cSHarald Freudenberger * Module init
6128fcc231cSHarald Freudenberger */
pkey_cca_init(void)6138fcc231cSHarald Freudenberger static int __init pkey_cca_init(void)
61486fbf5e2SHarald Freudenberger {
6158fcc231cSHarald Freudenberger /* register this module as pkey handler for all the cca stuff */
6168fcc231cSHarald Freudenberger return pkey_handler_register(&cca_handler);
61786fbf5e2SHarald Freudenberger }
61886fbf5e2SHarald Freudenberger
6198fcc231cSHarald Freudenberger /*
6208fcc231cSHarald Freudenberger * Module exit
6218fcc231cSHarald Freudenberger */
pkey_cca_exit(void)6228fcc231cSHarald Freudenberger static void __exit pkey_cca_exit(void)
62386fbf5e2SHarald Freudenberger {
6248fcc231cSHarald Freudenberger /* unregister this module as pkey handler */
6258fcc231cSHarald Freudenberger pkey_handler_unregister(&cca_handler);
62686fbf5e2SHarald Freudenberger }
62786fbf5e2SHarald Freudenberger
6288fcc231cSHarald Freudenberger module_init(pkey_cca_init);
6298fcc231cSHarald Freudenberger module_exit(pkey_cca_exit);
630