diff options
author | Harald Freudenberger <freude@linux.ibm.com> | 2024-08-22 11:32:19 +0200 |
---|---|---|
committer | Vasily Gorbik <gor@linux.ibm.com> | 2024-08-29 22:56:34 +0200 |
commit | 8fcc231ce3bea12b78bb94b280cdc03cff342435 (patch) | |
tree | 4ca85e885a942c42c2c2fe59973cf84797585a24 /drivers/s390 | |
parent | s390/pkey: Unify pkey cca, ep11 and pckmo functions signatures (diff) | |
download | linux-8fcc231ce3bea12b78bb94b280cdc03cff342435.tar.xz linux-8fcc231ce3bea12b78bb94b280cdc03cff342435.zip |
s390/pkey: Introduce pkey base with handler registry and handler modules
Introduce pkey base kernel code with a simple pkey handler registry.
Regroup the pkey code into these kernel modules:
- pkey is the pkey api supporting the ioctls, sysfs and in-kernel api.
Also the pkey base code which offers the handler registry and
handler wrapping invocation functions is integrated there. This
module is automatically loaded in via CPU feature if the MSA feature
is available.
- pkey-cca is the CCA related handler code kernel module a offering
CCA specific implementation for pkey. This module is loaded in
via MODULE_DEVICE_TABLE when a CEX[4-8] card becomes available.
- pkey-ep11 is the EP11 related handler code kernel module offering an
EP11 specific implementation for pkey. This module is loaded in via
MODULE_DEVICE_TABLE when a CEX[4-8] card becomes available.
- pkey-pckmo is the PCKMO related handler code kernel module. This
module is loaded in via CPU feature if the MSA feature is available,
but on init a check for availability of the pckmo instruction is
performed.
The handler modules register via a pkey_handler struct at the pkey
base code and the pkey customer (that is currently the pkey api code
fetches a handler via pkey handler registry functions and calls the
unified handler functions via the pkey base handler functions.
As a result the pkey-cca, pkey-ep11 and pkey-pckmo modules get
independent from each other and it becomes possible to write new
handlers which offer another kind of implementation without implicit
dependencies to other handler implementations and/or kernel device
drivers.
For each of these 4 kernel modules there is an individual Kconfig
entry: CONFIG_PKEY for the base and api, CONFIG_PKEY_CCA for the PKEY
CCA support handler, CONFIG_PKEY_EP11 for the EP11 support handler and
CONFIG_PKEY_PCKMO for the pckmo support. The both CEX related handler
modules (PKEY CCA and PKEY EP11) have a dependency to the zcrypt api
of the zcrypt device driver.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/crypto/Makefile | 16 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_api.c | 690 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_base.c | 293 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_base.h | 130 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_cca.c | 489 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_ep11.c | 418 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_pckmo.c | 412 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_sysfs.c | 121 |
8 files changed, 1433 insertions, 1136 deletions
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index 863d6fbd2e79..c88b6e071847 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -13,10 +13,22 @@ obj-$(CONFIG_ZCRYPT) += zcrypt.o # adapter drivers depend on ap.o and zcrypt.o obj-$(CONFIG_ZCRYPT) += zcrypt_cex4.o -# pkey kernel module -pkey-objs := pkey_api.o pkey_cca.o pkey_ep11.o pkey_pckmo.o pkey_sysfs.o +# pkey base and api module +pkey-objs := pkey_base.o pkey_api.o pkey_sysfs.o obj-$(CONFIG_PKEY) += pkey.o +# pkey cca handler module +pkey-cca-objs := pkey_cca.o +obj-$(CONFIG_PKEY_CCA) += pkey-cca.o + +# pkey ep11 handler module +pkey-ep11-objs := pkey_ep11.o +obj-$(CONFIG_PKEY_EP11) += pkey-ep11.o + +# pkey pckmo handler module +pkey-pckmo-objs := pkey_pckmo.o +obj-$(CONFIG_PKEY_PCKMO) += pkey-pckmo.o + # adjunct processor matrix vfio_ap-objs := vfio_ap_drv.o vfio_ap_ops.o obj-$(CONFIG_VFIO_AP) += vfio_ap.o diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 31382c23ec14..c59051ab1cfb 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -10,271 +10,26 @@ #define KMSG_COMPONENT "pkey" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include <linux/fs.h> #include <linux/init.h> #include <linux/miscdevice.h> -#include <linux/module.h> #include <linux/slab.h> -#include <linux/kallsyms.h> -#include <linux/debugfs.h> -#include <linux/cpufeature.h> -#include <asm/zcrypt.h> -#include <asm/cpacf.h> -#include <asm/pkey.h> #include "zcrypt_api.h" #include "zcrypt_ccamisc.h" -#include "zcrypt_ep11misc.h" #include "pkey_base.h" -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("s390 protected key interface"); - -/* - * Debug feature data and functions - */ - -debug_info_t *pkey_dbf_info; - -static void __init pkey_debug_init(void) -{ - /* 5 arguments per dbf entry (including the format string ptr) */ - pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long)); - debug_register_view(pkey_dbf_info, &debug_sprintf_view); - debug_set_level(pkey_dbf_info, 3); -} - -static void __exit pkey_debug_exit(void) -{ - debug_unregister(pkey_dbf_info); -} - /* * Helper functions */ -static int apqns4key(const u8 *key, size_t keylen, u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns) -{ - if (pkey_is_cca_key(key, keylen)) { - return pkey_cca_apqns4key(key, keylen, flags, - apqns, nr_apqns); - } else if (pkey_is_ep11_key(key, keylen)) { - return pkey_ep11_apqns4key(key, keylen, flags, - apqns, nr_apqns); - } else { - struct keytoken_header *hdr = (struct keytoken_header *)key; - - PKEY_DBF_ERR("%s unknown/unsupported key type %d version %d\n", - __func__, hdr->type, hdr->version); - return -EINVAL; - } -} - -static int apqns4keytype(enum pkey_key_type ktype, - u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns) -{ - if (pkey_is_cca_keytype(ktype)) { - return pkey_cca_apqns4type(ktype, cur_mkvp, alt_mkvp, flags, - apqns, nr_apqns); - } else if (pkey_is_ep11_keytype(ktype)) { - return pkey_ep11_apqns4type(ktype, cur_mkvp, alt_mkvp, flags, - apqns, nr_apqns); - } else { - PKEY_DBF_ERR("%s unknown/unsupported key type %d\n", - __func__, ktype); - return -EINVAL; - } -} - -static int genseck2(const struct pkey_apqn *apqns, size_t nr_apqns, - enum pkey_key_type keytype, enum pkey_key_size keybitsize, - u32 flags, u8 *keybuf, u32 *keybuflen) -{ - int i, rc; - u32 u; - - if (pkey_is_cca_keytype(keytype)) { - /* As of now only CCA AES key generation is supported */ - u = pkey_aes_bitsize_to_keytype(keybitsize); - if (!u) { - PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n", - __func__, keybitsize); - return -EINVAL; - } - for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { - rc = pkey_cca_gen_key(apqns[i].card, - apqns[i].domain, - u, keytype, keybitsize, flags, - keybuf, keybuflen, NULL); - } - } else if (pkey_is_ep11_keytype(keytype)) { - /* As of now only EP11 AES key generation is supported */ - u = pkey_aes_bitsize_to_keytype(keybitsize); - if (!u) { - PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n", - __func__, keybitsize); - return -EINVAL; - } - for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { - rc = pkey_ep11_gen_key(apqns[i].card, - apqns[i].domain, - u, keytype, keybitsize, flags, - keybuf, keybuflen, NULL); - } - } else { - PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", - __func__, keytype); - return -EINVAL; - } - - return rc; -} - -static int clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns, - enum pkey_key_type keytype, enum pkey_key_size kbitsize, - u32 flags, const u8 *clrkey, u8 *keybuf, u32 *keybuflen) -{ - int i, rc; - u32 u; - - if (pkey_is_cca_keytype(keytype)) { - /* As of now only CCA AES key generation is supported */ - u = pkey_aes_bitsize_to_keytype(kbitsize); - if (!u) { - PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n", - __func__, kbitsize); - return -EINVAL; - } - for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { - rc = pkey_cca_clr2key(apqns[i].card, - apqns[i].domain, - u, keytype, kbitsize, flags, - clrkey, kbitsize / 8, - keybuf, keybuflen, NULL); - } - } else if (pkey_is_ep11_keytype(keytype)) { - /* As of now only EP11 AES key generation is supported */ - u = pkey_aes_bitsize_to_keytype(kbitsize); - if (!u) { - PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n", - __func__, kbitsize); - return -EINVAL; - } - for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { - rc = pkey_ep11_clr2key(apqns[i].card, - apqns[i].domain, - u, keytype, kbitsize, flags, - clrkey, kbitsize / 8, - keybuf, keybuflen, NULL); - } - } else { - PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", - __func__, keytype); - return -EINVAL; - } - - return rc; -} - -static int ccakey2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, - const u8 *key, size_t keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) -{ - struct pkey_apqn *local_apqns = NULL; - int i, j, rc; - - /* alloc space for list of apqns if no list given */ - if (!apqns || (nr_apqns == 1 && - apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { - nr_apqns = MAXAPQNSINLIST; - local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), - GFP_KERNEL); - if (!local_apqns) - return -ENOMEM; - apqns = local_apqns; - } - - /* try two times in case of failure */ - for (i = 0, rc = -ENODEV; i < 2 && rc; i++) { - if (local_apqns) { - /* gather list of apqns able to deal with this key */ - nr_apqns = MAXAPQNSINLIST; - rc = pkey_cca_apqns4key(key, keylen, 0, - local_apqns, &nr_apqns); - if (rc) - continue; - } - /* go through the list of apqns until success or end */ - for (j = 0, rc = -ENODEV; j < nr_apqns && rc; j++) { - rc = pkey_cca_key2protkey(apqns[j].card, - apqns[j].domain, - key, keylen, - protkey, protkeylen, - protkeytype); - } - } - - kfree(local_apqns); - - return rc; -} - -static int ep11key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, - const u8 *key, size_t keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) -{ - struct pkey_apqn *local_apqns = NULL; - int i, j, rc; - - /* alloc space for list of apqns if no list given */ - if (!apqns || (nr_apqns == 1 && - apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { - nr_apqns = MAXAPQNSINLIST; - local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), - GFP_KERNEL); - if (!local_apqns) - return -ENOMEM; - apqns = local_apqns; - } - - /* try two times in case of failure */ - for (i = 0, rc = -ENODEV; i < 2 && rc; i++) { - if (local_apqns) { - /* gather list of apqns able to deal with this key */ - nr_apqns = MAXAPQNSINLIST; - rc = pkey_ep11_apqns4key(key, keylen, 0, - local_apqns, &nr_apqns); - if (rc) - continue; - } - /* go through the list of apqns until success or end */ - for (j = 0, rc = -ENODEV; j < nr_apqns && rc; j++) { - rc = pkey_ep11_key2protkey(apqns[j].card, - apqns[j].domain, - key, keylen, - protkey, protkeylen, - protkeytype); - } - } - - kfree(local_apqns); - - return rc; -} - -static int pckmokey2protkey_fallback(const struct clearkeytoken *t, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) +static int key2protkey_fallback(const struct clearkeytoken *t, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { size_t tmpbuflen = max_t(size_t, SECKEYBLOBSIZE, MAXEP11AESKEYBLOBSIZE); - struct pkey_apqn *apqns = NULL; - u32 keysize, tmplen; + u32 keysize, keybitsize, tmplen; u8 *tmpbuf = NULL; - size_t nr_apqns; - int i, j, rc; + int i, rc; /* As of now only for AES keys a fallback is available */ @@ -289,110 +44,53 @@ static int pckmokey2protkey_fallback(const struct clearkeytoken *t, __func__, t->len); return -EINVAL; } + keybitsize = 8 * keysize; - /* alloc tmp buffer and space for apqns */ + /* alloc tmp key buffer */ tmpbuf = kmalloc(tmpbuflen, GFP_ATOMIC); if (!tmpbuf) return -ENOMEM; - nr_apqns = MAXAPQNSINLIST; - apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL); - if (!apqns) { - kfree(tmpbuf); - return -ENOMEM; - } /* try two times in case of failure */ for (i = 0, rc = -ENODEV; i < 2 && rc; i++) { /* CCA secure key way */ - nr_apqns = MAXAPQNSINLIST; - rc = pkey_cca_apqns4type(PKEY_TYPE_CCA_DATA, - NULL, NULL, 0, apqns, &nr_apqns); - pr_debug("pkey_cca_apqns4type(CCA_DATA)=%d\n", rc); - if (rc) - goto try_via_ep11; - for (j = 0, rc = -ENODEV; j < nr_apqns && rc; j++) { - tmplen = tmpbuflen; - rc = pkey_cca_clr2key(apqns[j].card, apqns[j].domain, - t->keytype, PKEY_TYPE_CCA_DATA, - 8 * keysize, 0, - t->clearkey, t->len, - tmpbuf, &tmplen, NULL); - pr_debug("pkey_cca_clr2key()=%d\n", rc); - } + tmplen = tmpbuflen; + rc = pkey_handler_clr_to_key(NULL, 0, + t->keytype, PKEY_TYPE_CCA_DATA, + keybitsize, 0, + t->clearkey, t->len, + tmpbuf, &tmplen, NULL); + pr_debug("clr_to_key()=%d\n", rc); if (rc) goto try_via_ep11; - for (j = 0, rc = -ENODEV; j < nr_apqns && rc; j++) { - rc = pkey_cca_key2protkey(apqns[j].card, - apqns[j].domain, - tmpbuf, tmplen, - protkey, protkeylen, - protkeytype); - pr_debug("pkey_cca_key2protkey()=%d\n", rc); - } + rc = pkey_handler_key_to_protkey(NULL, 0, + tmpbuf, tmplen, + protkey, protkeylen, + protkeytype); + pr_debug("key_to_protkey()=%d\n", rc); if (!rc) break; try_via_ep11: /* the CCA way failed, try via EP11 */ - nr_apqns = MAXAPQNSINLIST; - rc = pkey_ep11_apqns4type(PKEY_TYPE_EP11_AES, - NULL, NULL, 0, apqns, &nr_apqns); - pr_debug("pkey_ep11_apqns4type(EP11_AES)=%d\n", rc); - if (rc) - continue; - for (j = 0, rc = -ENODEV; j < nr_apqns && rc; j++) { - tmplen = tmpbuflen; - rc = pkey_ep11_clr2key(apqns[j].card, apqns[j].domain, - t->keytype, PKEY_TYPE_EP11_AES, - 8 * keysize, 0, - t->clearkey, t->len, - tmpbuf, &tmplen, NULL); - pr_debug("pkey_ep11_clr2key()=%d\n", rc); - } + tmplen = tmpbuflen; + rc = pkey_handler_clr_to_key(NULL, 0, + t->keytype, PKEY_TYPE_EP11_AES, + keybitsize, 0, + t->clearkey, t->len, + tmpbuf, &tmplen, NULL); + pr_debug("clr_to_key()=%d\n", rc); if (rc) continue; - for (j = 0, rc = -ENODEV; j < nr_apqns && rc; j++) { - rc = pkey_ep11_key2protkey(apqns[j].card, - apqns[j].domain, - tmpbuf, tmplen, - protkey, protkeylen, - protkeytype); - pr_debug("pkey_ep11_key2protkey()=%d\n", rc); - } + rc = pkey_handler_key_to_protkey(NULL, 0, + tmpbuf, tmplen, + protkey, protkeylen, + protkeytype); + pr_debug("key_to_protkey()=%d\n", rc); } kfree(tmpbuf); - kfree(apqns); - - return rc; -} - -static int pckmokey2protkey(const u8 *key, size_t keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) -{ - int rc; - - rc = pkey_pckmo_key2protkey(0, 0, key, keylen, - protkey, protkeylen, protkeytype); - if (rc == -ENODEV) { - struct keytoken_header *hdr = (struct keytoken_header *)key; - struct clearkeytoken *t = (struct clearkeytoken *)key; - - /* maybe a fallback is possible */ - if (hdr->type == TOKTYPE_NON_CCA && - hdr->version == TOKVER_CLEAR_KEY) { - rc = pckmokey2protkey_fallback(t, protkey, - protkeylen, - protkeytype); - if (rc) - rc = -ENODEV; - } - } - - if (rc) - PKEY_DBF_ERR("%s unable to build protected key from clear, rc=%d", - __func__, rc); return rc; } @@ -401,22 +99,26 @@ static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, const u8 *key, size_t keylen, u8 *protkey, u32 *protkeylen, u32 *protkeytype) { - if (pkey_is_cca_key(key, keylen)) { - return ccakey2protkey(apqns, nr_apqns, key, keylen, - protkey, protkeylen, protkeytype); - } else if (pkey_is_ep11_key(key, keylen)) { - return ep11key2protkey(apqns, nr_apqns, key, keylen, - protkey, protkeylen, protkeytype); - } else if (pkey_is_pckmo_key(key, keylen)) { - return pckmokey2protkey(key, keylen, - protkey, protkeylen, protkeytype); - } else { - struct keytoken_header *hdr = (struct keytoken_header *)key; - - PKEY_DBF_ERR("%s unknown/unsupported key type %d version %d\n", - __func__, hdr->type, hdr->version); - return -EINVAL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + int i, rc; + + /* retry two times */ + for (rc = -ENODEV, i = 0; rc && i < 2; i++) { + /* First try the direct way */ + rc = pkey_handler_key_to_protkey(apqns, nr_apqns, + key, keylen, + protkey, protkeylen, + protkeytype); + /* For some clear key tokens there exists a fallback way */ + if (rc && + hdr->type == TOKTYPE_NON_CCA && + hdr->version == TOKVER_CLEAR_KEY) + rc = key2protkey_fallback((struct clearkeytoken *)key, + protkey, protkeylen, + protkeytype); } + + return rc; } /* @@ -453,16 +155,20 @@ static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns) static int pkey_ioctl_genseck(struct pkey_genseck __user *ugs) { struct pkey_genseck kgs; + struct pkey_apqn apqn; u32 keybuflen; int rc; if (copy_from_user(&kgs, ugs, sizeof(kgs))) return -EFAULT; + + apqn.card = kgs.cardnr; + apqn.domain = kgs.domain; keybuflen = sizeof(kgs.seckey.seckey); - rc = pkey_cca_gen_key(kgs.cardnr, kgs.domain, - kgs.keytype, PKEY_TYPE_CCA_DATA, 0, 0, - kgs.seckey.seckey, &keybuflen, NULL); - pr_debug("pkey_cca_gen_key()=%d\n", rc); + rc = pkey_handler_gen_key(&apqn, 1, + kgs.keytype, PKEY_TYPE_CCA_DATA, 0, 0, + kgs.seckey.seckey, &keybuflen, NULL); + pr_debug("gen_key()=%d\n", rc); if (!rc && copy_to_user(ugs, &kgs, sizeof(kgs))) rc = -EFAULT; memzero_explicit(&kgs, sizeof(kgs)); @@ -473,18 +179,22 @@ static int pkey_ioctl_genseck(struct pkey_genseck __user *ugs) static int pkey_ioctl_clr2seck(struct pkey_clr2seck __user *ucs) { struct pkey_clr2seck kcs; + struct pkey_apqn apqn; u32 keybuflen; int rc; if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; + + apqn.card = kcs.cardnr; + apqn.domain = kcs.domain; keybuflen = sizeof(kcs.seckey.seckey); - rc = pkey_cca_clr2key(kcs.cardnr, kcs.domain, - kcs.keytype, PKEY_TYPE_CCA_DATA, 0, 0, - kcs.clrkey.clrkey, - pkey_keytype_aes_to_size(kcs.keytype), - kcs.seckey.seckey, &keybuflen, NULL); - pr_debug("pkey_cca_clr2key()=%d\n", rc); + rc = pkey_handler_clr_to_key(&apqn, 1, + kcs.keytype, PKEY_TYPE_CCA_DATA, 0, 0, + kcs.clrkey.clrkey, + pkey_keytype_aes_to_size(kcs.keytype), + kcs.seckey.seckey, &keybuflen, NULL); + pr_debug("clr_to_key()=%d\n", rc); if (!rc && copy_to_user(ucs, &kcs, sizeof(kcs))) rc = -EFAULT; memzero_explicit(&kcs, sizeof(kcs)); @@ -495,16 +205,21 @@ static int pkey_ioctl_clr2seck(struct pkey_clr2seck __user *ucs) static int pkey_ioctl_sec2protk(struct pkey_sec2protk __user *usp) { struct pkey_sec2protk ksp; + struct pkey_apqn apqn; int rc; if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; + + apqn.card = ksp.cardnr; + apqn.domain = ksp.domain; ksp.protkey.len = sizeof(ksp.protkey.protkey); - rc = pkey_cca_key2protkey(ksp.cardnr, ksp.domain, - ksp.seckey.seckey, sizeof(ksp.seckey.seckey), - ksp.protkey.protkey, - &ksp.protkey.len, &ksp.protkey.type); - pr_debug("pkey_cca_key2protkey()=%d\n", rc); + rc = pkey_handler_key_to_protkey(&apqn, 1, + ksp.seckey.seckey, + sizeof(ksp.seckey.seckey), + ksp.protkey.protkey, + &ksp.protkey.len, &ksp.protkey.type); + pr_debug("key_to_protkey()=%d\n", rc); if (!rc && copy_to_user(usp, &ksp, sizeof(ksp))) rc = -EFAULT; memzero_explicit(&ksp, sizeof(ksp)); @@ -515,16 +230,43 @@ static int pkey_ioctl_sec2protk(struct pkey_sec2protk __user *usp) static int pkey_ioctl_clr2protk(struct pkey_clr2protk __user *ucp) { struct pkey_clr2protk kcp; + struct clearkeytoken *t; + u32 keylen; + u8 *tmpbuf; int rc; if (copy_from_user(&kcp, ucp, sizeof(kcp))) return -EFAULT; + + /* build a 'clear key token' from the clear key value */ + keylen = pkey_keytype_aes_to_size(kcp.keytype); + if (!keylen) { + PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", + __func__, kcp.keytype); + memzero_explicit(&kcp, sizeof(kcp)); + return -EINVAL; + } + tmpbuf = kzalloc(sizeof(*t) + keylen, GFP_KERNEL); + if (!tmpbuf) { + memzero_explicit(&kcp, sizeof(kcp)); + return -ENOMEM; + } + t = (struct clearkeytoken *)tmpbuf; + t->type = TOKTYPE_NON_CCA; + t->version = TOKVER_CLEAR_KEY; + t->keytype = (keylen - 8) >> 3; + t->len = keylen; + memcpy(t->clearkey, kcp.clrkey.clrkey, keylen); kcp.protkey.len = sizeof(kcp.protkey.protkey); - rc = pkey_pckmo_clr2key(0, 0, kcp.keytype, 0, 0, 0, - kcp.clrkey.clrkey, 0, - kcp.protkey.protkey, - &kcp.protkey.len, &kcp.protkey.type); - pr_debug("pkey_pckmo_clr2key()=%d\n", rc); + + rc = key2protkey(NULL, 0, + tmpbuf, sizeof(*t) + keylen, + kcp.protkey.protkey, + &kcp.protkey.len, &kcp.protkey.type); + pr_debug("key2protkey()=%d\n", rc); + + kfree_sensitive(tmpbuf); + if (!rc && copy_to_user(ucp, &kcp, sizeof(kcp))) rc = -EFAULT; memzero_explicit(&kcp, sizeof(kcp)); @@ -542,23 +284,21 @@ static int pkey_ioctl_findcard(struct pkey_findcard __user *ufc) if (copy_from_user(&kfc, ufc, sizeof(kfc))) return -EFAULT; - if (!pkey_is_cca_key(kfc.seckey.seckey, sizeof(kfc.seckey.seckey))) - return -EINVAL; - nr_apqns = MAXAPQNSINLIST; apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL); if (!apqns) return -ENOMEM; - rc = pkey_cca_apqns4key(kfc.seckey.seckey, - sizeof(kfc.seckey.seckey), - PKEY_FLAGS_MATCH_CUR_MKVP, - apqns, &nr_apqns); - if (rc == -ENODEV) - rc = pkey_cca_apqns4key(kfc.seckey.seckey, + + rc = pkey_handler_apqns_for_key(kfc.seckey.seckey, sizeof(kfc.seckey.seckey), - PKEY_FLAGS_MATCH_ALT_MKVP, + PKEY_FLAGS_MATCH_CUR_MKVP, apqns, &nr_apqns); - pr_debug("pkey_cca_apqns4key()=%d\n", rc); + if (rc == -ENODEV) + rc = pkey_handler_apqns_for_key(kfc.seckey.seckey, + sizeof(kfc.seckey.seckey), + PKEY_FLAGS_MATCH_ALT_MKVP, + apqns, &nr_apqns); + pr_debug("apqns_for_key()=%d\n", rc); if (rc) { kfree(apqns); return rc; @@ -575,38 +315,19 @@ static int pkey_ioctl_findcard(struct pkey_findcard __user *ufc) static int pkey_ioctl_skey2pkey(struct pkey_skey2pkey __user *usp) { struct pkey_skey2pkey ksp; - struct pkey_apqn *apqns; - size_t nr_apqns; - int i, rc; + int rc; if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - if (!pkey_is_cca_key(ksp.seckey.seckey, sizeof(ksp.seckey.seckey))) - return -EINVAL; - - nr_apqns = MAXAPQNSINLIST; - apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL); - if (!apqns) - return -ENOMEM; - rc = pkey_cca_apqns4key(ksp.seckey.seckey, sizeof(ksp.seckey.seckey), - 0, apqns, &nr_apqns); - pr_debug("pkey_cca_apqns4key()=%d\n", rc); - if (rc) { - kfree(apqns); - return rc; - } ksp.protkey.len = sizeof(ksp.protkey.protkey); - for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { - rc = pkey_cca_key2protkey(apqns[i].card, apqns[i].domain, - ksp.seckey.seckey, - sizeof(ksp.seckey.seckey), - ksp.protkey.protkey, - &ksp.protkey.len, - &ksp.protkey.type); - pr_debug("pkey_cca_key2protkey()=%d\n", rc); - } - kfree(apqns); + rc = pkey_handler_key_to_protkey(NULL, 0, + ksp.seckey.seckey, + sizeof(ksp.seckey.seckey), + ksp.protkey.protkey, + &ksp.protkey.len, + &ksp.protkey.type); + pr_debug("key_to_protkey()=%d\n", rc); if (!rc && copy_to_user(usp, &ksp, sizeof(ksp))) rc = -EFAULT; memzero_explicit(&ksp, sizeof(ksp)); @@ -622,12 +343,14 @@ static int pkey_ioctl_verifykey(struct pkey_verifykey __user *uvk) if (copy_from_user(&kvk, uvk, sizeof(kvk))) return -EFAULT; + kvk.cardnr = 0xFFFF; kvk.domain = 0xFFFF; - rc = pkey_cca_verifykey(kvk.seckey.seckey, sizeof(kvk.seckey.seckey), - &kvk.cardnr, &kvk.domain, - &keytype, &keybitsize, &flags); - pr_debug("pkey_cca_verifykey()=%d\n", rc); + rc = pkey_handler_verify_key(kvk.seckey.seckey, + sizeof(kvk.seckey.seckey), + &kvk.cardnr, &kvk.domain, + &keytype, &keybitsize, &flags); + pr_debug("verify_key()=%d\n", rc); if (!rc && keytype != PKEY_TYPE_CCA_DATA) rc = -EINVAL; kvk.attributes = PKEY_VERIFY_ATTR_AES; @@ -648,11 +371,13 @@ static int pkey_ioctl_genprotk(struct pkey_genprotk __user *ugp) if (copy_from_user(&kgp, ugp, sizeof(kgp))) return -EFAULT; + kgp.protkey.len = sizeof(kgp.protkey.protkey); - rc = pkey_pckmo_gen_key(0, 0, kgp.keytype, 0, 0, 0, - kgp.protkey.protkey, - &kgp.protkey.len, &kgp.protkey.type); - pr_debug("pkey_pckmo_gen_key()=%d\n", rc); + rc = pkey_handler_gen_key(NULL, 0, kgp.keytype, + PKEY_TYPE_PROTKEY, 0, 0, + kgp.protkey.protkey, &kgp.protkey.len, + &kgp.protkey.type); + pr_debug("gen_key()=%d\n", rc); if (!rc && copy_to_user(ugp, &kgp, sizeof(kgp))) rc = -EFAULT; memzero_explicit(&kgp, sizeof(kgp)); @@ -663,13 +388,40 @@ static int pkey_ioctl_genprotk(struct pkey_genprotk __user *ugp) static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp) { struct pkey_verifyprotk kvp; + struct protaeskeytoken *t; + u32 keytype; + u8 *tmpbuf; int rc; if (copy_from_user(&kvp, uvp, sizeof(kvp))) return -EFAULT; - rc = pkey_pckmo_verifykey(kvp.protkey.protkey, kvp.protkey.len, - 0, 0, &kvp.protkey.type, 0, 0); - pr_debug("pkey_pckmo_verifykey()=%d\n", rc); + + keytype = pkey_aes_bitsize_to_keytype(8 * kvp.protkey.len); + if (!keytype) { + PKEY_DBF_ERR("%s unknown/unsupported protkey length %u\n", + __func__, kvp.protkey.len); + memzero_explicit(&kvp, sizeof(kvp)); + return -EINVAL; + } + + /* build a 'protected key token' from the raw protected key */ + tmpbuf = kzalloc(sizeof(*t), GFP_KERNEL); + if (!tmpbuf) { + memzero_explicit(&kvp, sizeof(kvp)); + return -ENOMEM; + } + t = (struct protaeskeytoken *)tmpbuf; + t->type = TOKTYPE_NON_CCA; + t->version = TOKVER_PROTECTED_KEY; + t->keytype = keytype; + t->len = kvp.protkey.len; + memcpy(t->protkey, kvp.protkey.protkey, kvp.protkey.len); + + rc = pkey_handler_verify_key(tmpbuf, sizeof(*t), + NULL, NULL, NULL, NULL, NULL); + pr_debug("verify_key()=%d\n", rc); + + kfree_sensitive(tmpbuf); memzero_explicit(&kvp, sizeof(kvp)); return rc; @@ -706,9 +458,16 @@ static int pkey_ioctl_genseck2(struct pkey_genseck2 __user *ugs) struct pkey_apqn *apqns; u8 *kkey; int rc; + u32 u; if (copy_from_user(&kgs, ugs, sizeof(kgs))) return -EFAULT; + u = pkey_aes_bitsize_to_keytype(kgs.size); + if (!u) { + PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, kgs.size); + return -EINVAL; + } apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries); if (IS_ERR(apqns)) return PTR_ERR(apqns); @@ -717,10 +476,10 @@ static int pkey_ioctl_genseck2(struct pkey_genseck2 __user *ugs) kfree(apqns); return -ENOMEM; } - rc = genseck2(apqns, kgs.apqn_entries, - kgs.type, kgs.size, kgs.keygenflags, - kkey, &klen); - pr_debug("genseckey2()=%d\n", rc); + rc = pkey_handler_gen_key(apqns, kgs.apqn_entries, + u, kgs.type, kgs.size, kgs.keygenflags, + kkey, &klen, NULL); + pr_debug("gen_key()=%d\n", rc); kfree(apqns); if (rc) { kfree_sensitive(kkey); @@ -751,9 +510,17 @@ static int pkey_ioctl_clr2seck2(struct pkey_clr2seck2 __user *ucs) struct pkey_apqn *apqns; u8 *kkey; int rc; + u32 u; if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; + u = pkey_aes_bitsize_to_keytype(kcs.size); + if (!u) { + PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, kcs.size); + memzero_explicit(&kcs, sizeof(kcs)); + return -EINVAL; + } apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries); if (IS_ERR(apqns)) { memzero_explicit(&kcs, sizeof(kcs)); @@ -765,10 +532,11 @@ static int pkey_ioctl_clr2seck2(struct pkey_clr2seck2 __user *ucs) memzero_explicit(&kcs, sizeof(kcs)); return -ENOMEM; } - rc = clr2seckey2(apqns, kcs.apqn_entries, - kcs.type, kcs.size, kcs.keygenflags, - kcs.clrkey.clrkey, kkey, &klen); - pr_debug("clr2seckey2()=%d\n", rc); + rc = pkey_handler_clr_to_key(apqns, kcs.apqn_entries, + u, kcs.type, kcs.size, kcs.keygenflags, + kcs.clrkey.clrkey, kcs.size / 8, + kkey, &klen, NULL); + pr_debug("clr_to_key()=%d\n", rc); kfree(apqns); if (rc) { kfree_sensitive(kkey); @@ -807,26 +575,17 @@ static int pkey_ioctl_verifykey2(struct pkey_verifykey2 __user *uvk) kkey = _copy_key_from_user(kvk.key, kvk.keylen); if (IS_ERR(kkey)) return PTR_ERR(kkey); - if (pkey_is_cca_key(kkey, kvk.keylen)) { - rc = pkey_cca_verifykey(kkey, kvk.keylen, - &kvk.cardnr, &kvk.domain, - &kvk.type, &kvk.size, &kvk.flags); - pr_debug("pkey_cca_verifykey()=%d\n", rc); - } else if (pkey_is_ep11_key(kkey, kvk.keylen)) { - rc = pkey_ep11_verifykey(kkey, kvk.keylen, - &kvk.cardnr, &kvk.domain, - &kvk.type, &kvk.size, &kvk.flags); - pr_debug("pkey_ep11_verifykey()=%d\n", rc); - } else { - rc = -EINVAL; - } + + rc = pkey_handler_verify_key(kkey, kvk.keylen, + &kvk.cardnr, &kvk.domain, + &kvk.type, &kvk.size, &kvk.flags); + pr_debug("verify_key()=%d\n", rc); + kfree_sensitive(kkey); - if (rc) - return rc; - if (copy_to_user(uvk, &kvk, sizeof(kvk))) + if (!rc && copy_to_user(uvk, &kvk, sizeof(kvk))) return -EFAULT; - return 0; + return rc; } static int pkey_ioctl_kblob2protk2(struct pkey_kblob2pkey2 __user *utp) @@ -883,9 +642,9 @@ static int pkey_ioctl_apqns4k(struct pkey_apqns4key __user *uak) kfree(apqns); return PTR_ERR(kkey); } - rc = apqns4key(kkey, kak.keylen, kak.flags, - apqns, &nr_apqns); - pr_debug("apqns4key()=%d\n", rc); + rc = pkey_handler_apqns_for_key(kkey, kak.keylen, kak.flags, + apqns, &nr_apqns); + pr_debug("apqns_for_key()=%d\n", rc); kfree_sensitive(kkey); if (rc && rc != -ENOSPC) { kfree(apqns); @@ -929,9 +688,10 @@ static int pkey_ioctl_apqns4kt(struct pkey_apqns4keytype __user *uat) if (!apqns) return -ENOMEM; } - rc = apqns4keytype(kat.type, kat.cur_mkvp, kat.alt_mkvp, - kat.flags, apqns, &nr_apqns); - pr_debug("apqns4keytype()=%d\n", rc); + rc = pkey_handler_apqns_for_keytype(kat.type, + kat.cur_mkvp, kat.alt_mkvp, + kat.flags, apqns, &nr_apqns); + pr_debug("apqns_for_keytype()=%d\n", rc); if (rc && rc != -ENOSPC) { kfree(apqns); return rc; @@ -1092,43 +852,13 @@ static struct miscdevice pkey_dev = { .groups = pkey_attr_groups, }; -/* - * Module init - */ -static int __init pkey_init(void) +int __init pkey_api_init(void) { - cpacf_mask_t func_mask; - - /* - * The pckmo instruction should be available - even if we don't - * actually invoke it. This instruction comes with MSA 3 which - * is also the minimum level for the kmc instructions which - * are able to work with protected keys. - */ - if (!cpacf_query(CPACF_PCKMO, &func_mask)) - return -ENODEV; - - /* check for kmc instructions available */ - if (!cpacf_query(CPACF_KMC, &func_mask)) - return -ENODEV; - if (!cpacf_test_func(&func_mask, CPACF_KMC_PAES_128) || - !cpacf_test_func(&func_mask, CPACF_KMC_PAES_192) || - !cpacf_test_func(&func_mask, CPACF_KMC_PAES_256)) - return -ENODEV; - - pkey_debug_init(); - + /* register as a misc device */ return misc_register(&pkey_dev); } -/* - * Module exit - */ -static void __exit pkey_exit(void) +void __exit pkey_api_exit(void) { misc_deregister(&pkey_dev); - pkey_debug_exit(); } - -module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init); -module_exit(pkey_exit); diff --git a/drivers/s390/crypto/pkey_base.c b/drivers/s390/crypto/pkey_base.c new file mode 100644 index 000000000000..e7abc32ca5f9 --- /dev/null +++ b/drivers/s390/crypto/pkey_base.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pkey base: debug feature, pkey handler registry + * + * Copyright IBM Corp. 2024 + */ + +#define KMSG_COMPONENT "pkey" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/cpufeature.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/rculist.h> + +#include "pkey_base.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("s390 protected key base and api"); + +/* + * pkey debug feature + */ +debug_info_t *pkey_dbf_info; +EXPORT_SYMBOL(pkey_dbf_info); + +/* + * pkey handler registry + */ + +static DEFINE_SPINLOCK(handler_list_write_lock); +static LIST_HEAD(handler_list); + +int pkey_handler_register(struct pkey_handler *handler) +{ + const struct pkey_handler *h; + + if (!handler || + !handler->is_supported_key || + !handler->is_supported_keytype) + return -EINVAL; + + if (!try_module_get(handler->module)) + return -ENXIO; + + spin_lock(&handler_list_write_lock); + + rcu_read_lock(); + list_for_each_entry_rcu(h, &handler_list, list) { + if (h == handler) { + rcu_read_unlock(); + spin_unlock(&handler_list_write_lock); + module_put(handler->module); + return -EEXIST; + } + } + rcu_read_unlock(); + + list_add_rcu(&handler->list, &handler_list); + spin_unlock(&handler_list_write_lock); + synchronize_rcu(); + + module_put(handler->module); + + PKEY_DBF_INFO("%s pkey handler '%s' registered\n", __func__, + handler->name ?: "<no name>"); + + return 0; +} +EXPORT_SYMBOL(pkey_handler_register); + +int pkey_handler_unregister(struct pkey_handler *handler) +{ + spin_lock(&handler_list_write_lock); + list_del_rcu(&handler->list); + INIT_LIST_HEAD_RCU(&handler->list); + spin_unlock(&handler_list_write_lock); + synchronize_rcu(); + + PKEY_DBF_INFO("%s pkey handler '%s' unregistered\n", __func__, + handler->name ?: "<no name>"); + + return 0; +} +EXPORT_SYMBOL(pkey_handler_unregister); + +/* + * Handler invocation functions. + */ + +const struct pkey_handler *pkey_handler_get_keybased(const u8 *key, u32 keylen) +{ + const struct pkey_handler *h; + + rcu_read_lock(); + list_for_each_entry_rcu(h, &handler_list, list) { + if (!try_module_get(h->module)) + continue; + if (h->is_supported_key(key, keylen)) { + rcu_read_unlock(); + return h; + } + module_put(h->module); + } + rcu_read_unlock(); + + return NULL; +} +EXPORT_SYMBOL(pkey_handler_get_keybased); + +const struct pkey_handler *pkey_handler_get_keytypebased(enum pkey_key_type kt) +{ + const struct pkey_handler *h; + + rcu_read_lock(); + list_for_each_entry_rcu(h, &handler_list, list) { + if (!try_module_get(h->module)) + continue; + if (h->is_supported_keytype(kt)) { + rcu_read_unlock(); + return h; + } + module_put(h->module); + } + rcu_read_unlock(); + + return NULL; +} +EXPORT_SYMBOL(pkey_handler_get_keytypebased); + +void pkey_handler_put(const struct pkey_handler *handler) +{ + const struct pkey_handler *h; + + if (!handler) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(h, &handler_list, list) { + if (h == handler) { + module_put(h->module); + break; + } + } + rcu_read_unlock(); +} +EXPORT_SYMBOL(pkey_handler_put); + +int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + const struct pkey_handler *h; + int rc = -ENODEV; + + h = pkey_handler_get_keybased(key, keylen); + if (h && h->key_to_protkey) { + rc = h->key_to_protkey(apqns, nr_apqns, key, keylen, + protkey, protkeylen, + protkeytype); + } + pkey_handler_put(h); + + return rc; +} +EXPORT_SYMBOL(pkey_handler_key_to_protkey); + +int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns, + u32 keytype, u32 keysubtype, + u32 keybitsize, u32 flags, + u8 *keybuf, u32 *keybuflen, u32 *keyinfo) +{ + const struct pkey_handler *h; + int rc = -ENODEV; + + h = pkey_handler_get_keytypebased(keysubtype); + if (h && h->gen_key) { + rc = h->gen_key(apqns, nr_apqns, keytype, keysubtype, + keybitsize, flags, + keybuf, keybuflen, keyinfo); + } + pkey_handler_put(h); + + return rc; +} +EXPORT_SYMBOL(pkey_handler_gen_key); + +int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns, + u32 keytype, u32 keysubtype, + u32 keybitsize, u32 flags, + const u8 *clrkey, u32 clrkeylen, + u8 *keybuf, u32 *keybuflen, u32 *keyinfo) +{ + const struct pkey_handler *h; + int rc = -ENODEV; + + h = pkey_handler_get_keytypebased(keysubtype); + if (h && h->clr_to_key) { + rc = h->clr_to_key(apqns, nr_apqns, keytype, keysubtype, + keybitsize, flags, clrkey, clrkeylen, + keybuf, keybuflen, keyinfo); + } + pkey_handler_put(h); + + return rc; +} +EXPORT_SYMBOL(pkey_handler_clr_to_key); + +int pkey_handler_verify_key(const u8 *key, u32 keylen, + u16 *card, u16 *dom, + u32 *keytype, u32 *keybitsize, u32 *flags) +{ + const struct pkey_handler *h; + int rc = -ENODEV; + + h = pkey_handler_get_keybased(key, keylen); + if (h && h->verify_key) { + rc = h->verify_key(key, keylen, card, dom, + keytype, keybitsize, flags); + } + pkey_handler_put(h); + + return rc; +} +EXPORT_SYMBOL(pkey_handler_verify_key); + +int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + const struct pkey_handler *h; + int rc = -ENODEV; + + h = pkey_handler_get_keybased(key, keylen); + if (h && h->apqns_for_key) + rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns); + pkey_handler_put(h); + + return rc; +} +EXPORT_SYMBOL(pkey_handler_apqns_for_key); + +int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + const struct pkey_handler *h; + int rc = -ENODEV; + + h = pkey_handler_get_keytypebased(keysubtype); + if (h && h->apqns_for_keytype) { + rc = h->apqns_for_keytype(keysubtype, + cur_mkvp, alt_mkvp, flags, + apqns, nr_apqns); + } + pkey_handler_put(h); + + return rc; +} +EXPORT_SYMBOL(pkey_handler_apqns_for_keytype); + +/* + * Module init + */ +static int __init pkey_init(void) +{ + int rc; + + /* init debug feature */ + pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long)); + debug_register_view(pkey_dbf_info, &debug_sprintf_view); + debug_set_level(pkey_dbf_info, 4); + + /* the handler registry does not need any init */ + + rc = pkey_api_init(); + if (rc) + debug_unregister(pkey_dbf_info); + + return rc; +} + +/* + * Module exit + */ +static void __exit pkey_exit(void) +{ + pkey_api_exit(); +} + +module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init); +module_exit(pkey_exit); diff --git a/drivers/s390/crypto/pkey_base.h b/drivers/s390/crypto/pkey_base.h index 560106cbd450..7f97c6e598da 100644 --- a/drivers/s390/crypto/pkey_base.h +++ b/drivers/s390/crypto/pkey_base.h @@ -86,84 +86,84 @@ static inline u32 pkey_aes_bitsize_to_keytype(u32 keybitsize) } /* - * pkey_cca.c: + * pkey_api.c: */ - -bool pkey_is_cca_key(const u8 *key, u32 keylen); -bool pkey_is_cca_keytype(enum pkey_key_type); -int pkey_cca_key2protkey(u16 card, u16 dom, - const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype); -int pkey_cca_gen_key(u16 card, u16 dom, - u32 keytype, u32 keysubtype, - u32 keybitsize, u32 flags, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo); -int pkey_cca_clr2key(u16 card, u16 dom, - u32 keytype, u32 keysubtype, - u32 keybitsize, u32 flags, - const u8 *clrkey, u32 clrkeylen, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo); -int pkey_cca_verifykey(const u8 *key, u32 keylen, - u16 *card, u16 *dom, - u32 *keytype, u32 *keybitsize, u32 *flags); -int pkey_cca_apqns4key(const u8 *key, u32 keylen, u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns); -int pkey_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); +int __init pkey_api_init(void); +void __exit pkey_api_exit(void); /* - * pkey_ep11.c: + * pkey_sysfs.c: */ -bool pkey_is_ep11_key(const u8 *key, u32 keylen); -bool pkey_is_ep11_keytype(enum pkey_key_type); -int pkey_ep11_key2protkey(u16 card, u16 dom, - const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype); -int pkey_ep11_gen_key(u16 card, u16 dom, - u32 keytype, u32 keysubtype, - u32 keybitsize, u32 flags, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo); -int pkey_ep11_clr2key(u16 card, u16 dom, - u32 keytype, u32 keysubtype, - u32 keybitsize, u32 flags, - const u8 *clrkey, u32 clrkeylen, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo); -int pkey_ep11_verifykey(const u8 *key, u32 keylen, - u16 *card, u16 *dom, - u32 *keytype, u32 *keybitsize, u32 *flags); -int pkey_ep11_apqns4key(const u8 *key, u32 keylen, u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns); -int pkey_ep11_apqns4type(enum pkey_key_type ktype, - u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns); +extern const struct attribute_group *pkey_attr_groups[]; /* - * pkey_pckmo.c: + * pkey handler registry */ -bool pkey_is_pckmo_key(const u8 *key, u32 keylen); -int pkey_pckmo_key2protkey(u16 _card, u16 _dom, - const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype); -int pkey_pckmo_gen_key(u16 _card, u16 _dom, - u32 keytype, u32 _keysubtype, - u32 _keybitsize, u32 _flags, +struct pkey_handler { + struct module *module; + const char *name; + /* + * is_supported_key() and is_supported_keytype() are called + * within an rcu_read_lock() scope and thus must not sleep! + */ + bool (*is_supported_key)(const u8 *key, u32 keylen); + bool (*is_supported_keytype)(enum pkey_key_type); + int (*key_to_protkey)(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype); + int (*gen_key)(const struct pkey_apqn *apqns, size_t nr_apqns, + u32 keytype, u32 keysubtype, + u32 keybitsize, u32 flags, u8 *keybuf, u32 *keybuflen, u32 *keyinfo); -int pkey_pckmo_clr2key(u16 _card, u16 _dom, - u32 keytype, u32 _keysubtype, - u32 _keybitsize, u32 _flags, - const u8 *clrkey, u32 clrkeylen, - u8 *keybuf, u32 *keybuflen, u32 *keyinfo); -int pkey_pckmo_verifykey(const u8 *key, u32 keylen, - u16 *_card, u16 *_dom, - u32 *keytype, u32 *_keybitsize, u32 *_flags); + int (*clr_to_key)(const struct pkey_apqn *apqns, size_t nr_apqns, + u32 keytype, u32 keysubtype, + u32 keybitsize, u32 flags, + const u8 *clrkey, u32 clrkeylen, + u8 *keybuf, u32 *keybuflen, u32 *keyinfo); + int (*verify_key)(const u8 *key, u32 keylen, + u16 *card, u16 *dom, + u32 *keytype, u32 *keybitsize, u32 *flags); + int (*apqns_for_key)(const u8 *key, u32 keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns); + int (*apqns_for_keytype)(enum pkey_key_type ktype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns); + /* used internal by pkey base */ + struct list_head list; +}; + +int pkey_handler_register(struct pkey_handler *handler); +int pkey_handler_unregister(struct pkey_handler *handler); /* - * pkey_sysfs.c: + * invocation function for the registered pkey handlers */ -extern const struct attribute_group *pkey_attr_groups[]; +const struct pkey_handler *pkey_handler_get_keybased(const u8 *key, u32 keylen); +const struct pkey_handler *pkey_handler_get_keytypebased(enum pkey_key_type kt); +void pkey_handler_put(const struct pkey_handler *handler); + +int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype); +int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns, + u32 keytype, u32 keysubtype, + u32 keybitsize, u32 flags, + u8 *keybuf, u32 *keybuflen, u32 *keyinfo); +int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns, + u32 keytype, u32 keysubtype, + u32 keybitsize, u32 flags, + const u8 *clrkey, u32 clrkeylen, + u8 *keybuf, u32 *keybuflen, u32 *keyinfo); +int pkey_handler_verify_key(const u8 *key, u32 keylen, + u16 *card, u16 *dom, + u32 *keytype, u32 *keybitsize, u32 *flags); +int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns); +int pkey_handler_apqns_for_keytype(enum pkey_key_type ktype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns); #endif /* _PKEY_BASE_H_ */ diff --git a/drivers/s390/crypto/pkey_cca.c b/drivers/s390/crypto/pkey_cca.c index 1bf9019ec561..ba2ae253b2ba 100644 --- a/drivers/s390/crypto/pkey_cca.c +++ b/drivers/s390/crypto/pkey_cca.c @@ -8,15 +8,34 @@ #define KMSG_COMPONENT "pkey" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/init.h> +#include <linux/module.h> +#include <linux/cpufeature.h> + #include "zcrypt_api.h" #include "zcrypt_ccamisc.h" - #include "pkey_base.h" +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("s390 protected key CCA handler"); + +#if IS_MODULE(CONFIG_PKEY_CCA) +static struct ap_device_id pkey_cca_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4 }, + { .dev_type = AP_DEVICE_TYPE_CEX5 }, + { .dev_type = AP_DEVICE_TYPE_CEX6 }, + { .dev_type = AP_DEVICE_TYPE_CEX7 }, + { .dev_type = AP_DEVICE_TYPE_CEX8 }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(ap, pkey_cca_card_ids); +#endif + /* * Check key blob for known and supported CCA key. */ -bool pkey_is_cca_key(const u8 *key, u32 keylen) +static bool is_cca_key(const u8 *key, u32 keylen) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -39,7 +58,7 @@ bool pkey_is_cca_key(const u8 *key, u32 keylen) } } -bool pkey_is_cca_keytype(enum pkey_key_type key_type) +static bool is_cca_keytype(enum pkey_key_type key_type) { switch (key_type) { case PKEY_TYPE_CCA_DATA: @@ -51,18 +70,158 @@ bool pkey_is_cca_keytype(enum pkey_key_type key_type) } } -int pkey_cca_key2protkey(u16 card, u16 dom, - const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) +static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) { struct keytoken_header *hdr = (struct keytoken_header *)key; + u32 _nr_apqns, *_apqns = NULL; int rc; - if (keylen < sizeof(*hdr)) + if (!flags) + flags = PKEY_FLAGS_MATCH_CUR_MKVP | PKEY_FLAGS_MATCH_ALT_MKVP; + + if (keylen < sizeof(struct keytoken_header)) return -EINVAL; zcrypt_wait_api_operational(); + if (hdr->type == TOKTYPE_CCA_INTERNAL) { + u64 cur_mkvp = 0, old_mkvp = 0; + int minhwtype = ZCRYPT_CEX3C; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp; + } else if (hdr->version == TOKVER_CCA_VLSC) { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + minhwtype = ZCRYPT_CEX6; + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp0; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp0; + } else { + /* unknown CCA internal token type */ + return -EINVAL; + } + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, AES_MK_SET, + cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + + } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) { + struct eccprivkeytoken *t = (struct eccprivkeytoken *)key; + u64 cur_mkvp = 0, old_mkvp = 0; + + if (t->secid == 0x20) { + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp; + } else { + /* unknown CCA internal 2 token type */ + return -EINVAL; + } + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + ZCRYPT_CEX7, APKA_MK_SET, + cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + + } else { + PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n", + __func__, hdr->type, hdr->version); + return -EINVAL; + } + + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + +out: + kfree(_apqns); + pr_debug("rc=%d\n", rc); + return rc; +} + +static int 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) +{ + u32 _nr_apqns, *_apqns = NULL; + int rc; + + zcrypt_wait_api_operational(); + + if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) { + u64 cur_mkvp = 0, old_mkvp = 0; + int minhwtype = ZCRYPT_CEX3C; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = *((u64 *)cur_mkvp); + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = *((u64 *)alt_mkvp); + if (ktype == PKEY_TYPE_CCA_CIPHER) + minhwtype = ZCRYPT_CEX6; + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, AES_MK_SET, + cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + + } else if (ktype == PKEY_TYPE_CCA_ECC) { + u64 cur_mkvp = 0, old_mkvp = 0; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = *((u64 *)cur_mkvp); + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = *((u64 *)alt_mkvp); + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + ZCRYPT_CEX7, APKA_MK_SET, + cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + + } else { + PKEY_DBF_ERR("%s unknown/unsupported key type %d", + __func__, (int)ktype); + return -EINVAL; + } + + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + +out: + kfree(_apqns); + pr_debug("rc=%d\n", rc); + return rc; +} + +static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + struct pkey_apqn *local_apqns = NULL; + int i, rc; + + if (keylen < sizeof(*hdr)) + return -EINVAL; + if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_AES) { /* CCA AES data key */ @@ -70,8 +229,6 @@ int pkey_cca_key2protkey(u16 card, u16 dom, return -EINVAL; if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0)) return -EINVAL; - rc = cca_sec2protkey(card, dom, key, protkey, - protkeylen, protkeytype); } else if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_VLSC) { /* CCA AES cipher key */ @@ -80,23 +237,57 @@ int pkey_cca_key2protkey(u16 card, u16 dom, if (cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1)) return -EINVAL; - rc = cca_cipher2protkey(card, dom, key, protkey, - protkeylen, protkeytype); } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) { /* CCA ECC (private) key */ if (keylen < sizeof(struct eccprivkeytoken)) return -EINVAL; if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1)) return -EINVAL; - rc = cca_ecc2protkey(card, dom, key, protkey, - protkeylen, protkeytype); } else { PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n", __func__, hdr->type, hdr->version); - rc = -EINVAL; + return -EINVAL; } - pr_debug("card=%d dom=%d rc=%d\n", card, dom, rc); + zcrypt_wait_api_operational(); + + if (!apqns || (nr_apqns == 1 && + apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { + nr_apqns = MAXAPQNSINLIST; + local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!local_apqns) + return -ENOMEM; + rc = cca_apqns4key(key, keylen, 0, local_apqns, &nr_apqns); + if (rc) + goto out; + apqns = local_apqns; + } + + for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { + if (hdr->type == TOKTYPE_CCA_INTERNAL && + hdr->version == TOKVER_CCA_AES) { + rc = cca_sec2protkey(apqns[i].card, apqns[i].domain, + key, protkey, + protkeylen, protkeytype); + } else if (hdr->type == TOKTYPE_CCA_INTERNAL && + hdr->version == TOKVER_CCA_VLSC) { + rc = cca_cipher2protkey(apqns[i].card, apqns[i].domain, + key, protkey, + protkeylen, protkeytype); + } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) { + rc = cca_ecc2protkey(apqns[i].card, apqns[i].domain, + key, protkey, + protkeylen, protkeytype); + } else { + rc = -EINVAL; + break; + } + } + +out: + kfree(local_apqns); + pr_debug("rc=%d\n", rc); return rc; } @@ -109,12 +300,13 @@ int pkey_cca_key2protkey(u16 card, u16 dom, * keybitsize is the bit size of the key (may be 0 for * keytype PKEY_KEYTYPE_AES_*). */ -int pkey_cca_gen_key(u16 card, u16 dom, - u32 keytype, u32 subtype, - u32 keybitsize, u32 flags, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo) +static int 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) { - int len, rc; + struct pkey_apqn *local_apqns = NULL; + int i, len, rc; /* check keytype, subtype, keybitsize */ switch (keytype) { @@ -129,7 +321,6 @@ int pkey_cca_gen_key(u16 card, u16 dom, } keybitsize = 8 * len; switch (subtype) { - case 0: case PKEY_TYPE_CCA_DATA: case PKEY_TYPE_CCA_CIPHER: break; @@ -147,16 +338,36 @@ int pkey_cca_gen_key(u16 card, u16 dom, zcrypt_wait_api_operational(); - if (subtype == PKEY_TYPE_CCA_CIPHER) { - rc = cca_gencipherkey(card, dom, keybitsize, flags, - keybuf, keybuflen); - } else { - /* 0 or PKEY_TYPE_CCA_DATA */ - rc = cca_genseckey(card, dom, keybitsize, keybuf); - *keybuflen = (rc ? 0 : SECKEYBLOBSIZE); + if (!apqns || (nr_apqns == 1 && + apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { + nr_apqns = MAXAPQNSINLIST; + local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!local_apqns) + return -ENOMEM; + rc = cca_apqns4type(subtype, NULL, NULL, 0, + local_apqns, &nr_apqns); + if (rc) + goto out; + apqns = local_apqns; + } + + for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { + if (subtype == PKEY_TYPE_CCA_CIPHER) { + rc = cca_gencipherkey(apqns[i].card, apqns[i].domain, + keybitsize, flags, + keybuf, keybuflen); + } else { + /* PKEY_TYPE_CCA_DATA */ + rc = cca_genseckey(apqns[i].card, apqns[i].domain, + keybitsize, keybuf); + *keybuflen = (rc ? 0 : SECKEYBLOBSIZE); + } } - pr_debug("card=%d dom=%d rc=%d\n", card, dom, rc); +out: + kfree(local_apqns); + pr_debug("rc=%d\n", rc); return rc; } @@ -169,13 +380,14 @@ int pkey_cca_gen_key(u16 card, u16 dom, * keybitsize is the bit size of the key (may be 0 for * keytype PKEY_KEYTYPE_AES_*). */ -int pkey_cca_clr2key(u16 card, u16 dom, - u32 keytype, u32 subtype, - u32 keybitsize, u32 flags, - const u8 *clrkey, u32 clrkeylen, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo) +static int 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) { - int len, rc; + struct pkey_apqn *local_apqns = NULL; + int i, len, rc; /* check keytype, subtype, clrkeylen, keybitsize */ switch (keytype) { @@ -195,7 +407,6 @@ int pkey_cca_clr2key(u16 card, u16 dom, return -EINVAL; } switch (subtype) { - case 0: case PKEY_TYPE_CCA_DATA: case PKEY_TYPE_CCA_CIPHER: break; @@ -213,23 +424,42 @@ int pkey_cca_clr2key(u16 card, u16 dom, zcrypt_wait_api_operational(); - if (subtype == PKEY_TYPE_CCA_CIPHER) { - rc = cca_clr2cipherkey(card, dom, keybitsize, - flags, clrkey, keybuf, keybuflen); - } else { - /* 0 or PKEY_TYPE_CCA_DATA */ - rc = cca_clr2seckey(card, dom, keybitsize, - clrkey, keybuf); - *keybuflen = (rc ? 0 : SECKEYBLOBSIZE); + if (!apqns || (nr_apqns == 1 && + apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { + nr_apqns = MAXAPQNSINLIST; + local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!local_apqns) + return -ENOMEM; + rc = cca_apqns4type(subtype, NULL, NULL, 0, + local_apqns, &nr_apqns); + if (rc) + goto out; + apqns = local_apqns; + } + + for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { + if (subtype == PKEY_TYPE_CCA_CIPHER) { + rc = cca_clr2cipherkey(apqns[i].card, apqns[i].domain, + keybitsize, flags, clrkey, + keybuf, keybuflen); + } else { + /* PKEY_TYPE_CCA_DATA */ + rc = cca_clr2seckey(apqns[i].card, apqns[i].domain, + keybitsize, clrkey, keybuf); + *keybuflen = (rc ? 0 : SECKEYBLOBSIZE); + } } - pr_debug("card=%d dom=%d rc=%d\n", card, dom, rc); +out: + kfree(local_apqns); + pr_debug("rc=%d\n", rc); return rc; } -int pkey_cca_verifykey(const u8 *key, u32 keylen, - u16 *card, u16 *dom, - u32 *keytype, u32 *keybitsize, u32 *flags) +static int cca_verifykey(const u8 *key, u32 keylen, + u16 *card, u16 *dom, + u32 *keytype, u32 *keybitsize, u32 *flags) { struct keytoken_header *hdr = (struct keytoken_header *)key; u32 nr_apqns, *apqns = NULL; @@ -311,143 +541,36 @@ out: return rc; } -int pkey_cca_apqns4key(const u8 *key, u32 keylen, u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns) -{ - struct keytoken_header *hdr = (struct keytoken_header *)key; - u32 _nr_apqns, *_apqns = NULL; - int rc; - - if (!flags) - flags = PKEY_FLAGS_MATCH_CUR_MKVP | PKEY_FLAGS_MATCH_ALT_MKVP; - - if (keylen < sizeof(struct keytoken_header)) - return -EINVAL; - - zcrypt_wait_api_operational(); - - if (hdr->type == TOKTYPE_CCA_INTERNAL) { - u64 cur_mkvp = 0, old_mkvp = 0; - int minhwtype = ZCRYPT_CEX3C; - - if (hdr->version == TOKVER_CCA_AES) { - struct secaeskeytoken *t = (struct secaeskeytoken *)key; - - if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) - cur_mkvp = t->mkvp; - if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) - old_mkvp = t->mkvp; - } else if (hdr->version == TOKVER_CCA_VLSC) { - struct cipherkeytoken *t = (struct cipherkeytoken *)key; - - minhwtype = ZCRYPT_CEX6; - if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) - cur_mkvp = t->mkvp0; - if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) - old_mkvp = t->mkvp0; - } else { - /* unknown CCA internal token type */ - return -EINVAL; - } - rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - minhwtype, AES_MK_SET, - cur_mkvp, old_mkvp, 1); - if (rc) - goto out; - - } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) { - struct eccprivkeytoken *t = (struct eccprivkeytoken *)key; - u64 cur_mkvp = 0, old_mkvp = 0; - - if (t->secid == 0x20) { - if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) - cur_mkvp = t->mkvp; - if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) - old_mkvp = t->mkvp; - } else { - /* unknown CCA internal 2 token type */ - return -EINVAL; - } - rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - ZCRYPT_CEX7, APKA_MK_SET, - cur_mkvp, old_mkvp, 1); - if (rc) - goto out; +static struct pkey_handler cca_handler = { + .module = THIS_MODULE, + .name = "PKEY CCA handler", + .is_supported_key = is_cca_key, + .is_supported_keytype = is_cca_keytype, + .key_to_protkey = cca_key2protkey, + .gen_key = cca_gen_key, + .clr_to_key = cca_clr2key, + .verify_key = cca_verifykey, + .apqns_for_key = cca_apqns4key, + .apqns_for_keytype = cca_apqns4type, +}; - } else { - PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n", - __func__, hdr->type, hdr->version); - return -EINVAL; - } - - if (apqns) { - if (*nr_apqns < _nr_apqns) - rc = -ENOSPC; - else - memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); - } - *nr_apqns = _nr_apqns; - -out: - kfree(_apqns); - pr_debug("rc=%d\n", rc); - return rc; +/* + * Module init + */ +static int __init pkey_cca_init(void) +{ + /* register this module as pkey handler for all the cca stuff */ + return pkey_handler_register(&cca_handler); } -int pkey_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) +/* + * Module exit + */ +static void __exit pkey_cca_exit(void) { - u32 _nr_apqns, *_apqns = NULL; - int rc; - - zcrypt_wait_api_operational(); - - if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) { - u64 cur_mkvp = 0, old_mkvp = 0; - int minhwtype = ZCRYPT_CEX3C; - - if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) - cur_mkvp = *((u64 *)cur_mkvp); - if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) - old_mkvp = *((u64 *)alt_mkvp); - if (ktype == PKEY_TYPE_CCA_CIPHER) - minhwtype = ZCRYPT_CEX6; - rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - minhwtype, AES_MK_SET, - cur_mkvp, old_mkvp, 1); - if (rc) - goto out; - - } else if (ktype == PKEY_TYPE_CCA_ECC) { - u64 cur_mkvp = 0, old_mkvp = 0; - - if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) - cur_mkvp = *((u64 *)cur_mkvp); - if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) - old_mkvp = *((u64 *)alt_mkvp); - rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - ZCRYPT_CEX7, APKA_MK_SET, - cur_mkvp, old_mkvp, 1); - if (rc) - goto out; - - } else { - PKEY_DBF_ERR("%s unknown/unsupported key type %d", - __func__, (int)ktype); - return -EINVAL; - } - - if (apqns) { - if (*nr_apqns < _nr_apqns) - rc = -ENOSPC; - else - memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); - } - *nr_apqns = _nr_apqns; - -out: - kfree(_apqns); - pr_debug("rc=%d\n", rc); - return rc; + /* unregister this module as pkey handler */ + pkey_handler_unregister(&cca_handler); } + +module_init(pkey_cca_init); +module_exit(pkey_cca_exit); diff --git a/drivers/s390/crypto/pkey_ep11.c b/drivers/s390/crypto/pkey_ep11.c index 4c49e07ece74..624e55195d93 100644 --- a/drivers/s390/crypto/pkey_ep11.c +++ b/drivers/s390/crypto/pkey_ep11.c @@ -8,16 +8,35 @@ #define KMSG_COMPONENT "pkey" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/init.h> +#include <linux/module.h> +#include <linux/cpufeature.h> + #include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "zcrypt_ep11misc.h" - #include "pkey_base.h" +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("s390 protected key EP11 handler"); + +#if IS_MODULE(CONFIG_PKEY_EP11) +static struct ap_device_id pkey_ep11_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4 }, + { .dev_type = AP_DEVICE_TYPE_CEX5 }, + { .dev_type = AP_DEVICE_TYPE_CEX6 }, + { .dev_type = AP_DEVICE_TYPE_CEX7 }, + { .dev_type = AP_DEVICE_TYPE_CEX8 }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(ap, pkey_ep11_card_ids); +#endif + /* * Check key blob for known and supported EP11 key. */ -bool pkey_is_ep11_key(const u8 *key, u32 keylen) +static bool is_ep11_key(const u8 *key, u32 keylen) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -39,7 +58,7 @@ bool pkey_is_ep11_key(const u8 *key, u32 keylen) } } -bool pkey_is_ep11_keytype(enum pkey_key_type key_type) +static bool is_ep11_keytype(enum pkey_key_type key_type) { switch (key_type) { case PKEY_TYPE_EP11: @@ -51,18 +70,131 @@ bool pkey_is_ep11_keytype(enum pkey_key_type key_type) } } -int pkey_ep11_key2protkey(u16 card, u16 dom, - const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) +static int ep11_apqns4key(const u8 *key, u32 keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) { struct keytoken_header *hdr = (struct keytoken_header *)key; + u32 _nr_apqns, *_apqns = NULL; int rc; - if (keylen < sizeof(*hdr)) + if (!flags) + flags = PKEY_FLAGS_MATCH_CUR_MKVP; + + if (keylen < sizeof(struct keytoken_header) || flags == 0) + return -EINVAL; + + zcrypt_wait_api_operational(); + + if (hdr->type == TOKTYPE_NON_CCA && + (hdr->version == TOKVER_EP11_AES_WITH_HEADER || + hdr->version == TOKVER_EP11_ECC_WITH_HEADER) && + is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { + struct ep11keyblob *kb = (struct ep11keyblob *) + (key + sizeof(struct ep11kblob_header)); + int minhwtype = 0, api = 0; + + if (flags != PKEY_FLAGS_MATCH_CUR_MKVP) + return -EINVAL; + if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) { + minhwtype = ZCRYPT_CEX7; + api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4; + } + rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, api, kb->wkvp); + if (rc) + goto out; + + } else if (hdr->type == TOKTYPE_NON_CCA && + hdr->version == TOKVER_EP11_AES && + is_ep11_keyblob(key)) { + struct ep11keyblob *kb = (struct ep11keyblob *)key; + int minhwtype = 0, api = 0; + + if (flags != PKEY_FLAGS_MATCH_CUR_MKVP) + return -EINVAL; + if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) { + minhwtype = ZCRYPT_CEX7; + api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4; + } + rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, api, kb->wkvp); + if (rc) + goto out; + + } else { + PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n", + __func__, hdr->type, hdr->version); return -EINVAL; + } + + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + +out: + kfree(_apqns); + pr_debug("rc=%d\n", rc); + return rc; +} + +static int ep11_apqns4type(enum pkey_key_type ktype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + u32 _nr_apqns, *_apqns = NULL; + int rc; zcrypt_wait_api_operational(); + if (ktype == PKEY_TYPE_EP11 || + ktype == PKEY_TYPE_EP11_AES || + ktype == PKEY_TYPE_EP11_ECC) { + u8 *wkvp = NULL; + int api; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + wkvp = cur_mkvp; + api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4; + rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + ZCRYPT_CEX7, api, wkvp); + if (rc) + goto out; + + } else { + PKEY_DBF_ERR("%s unknown/unsupported key type %d\n", + __func__, (int)ktype); + return -EINVAL; + } + + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + +out: + kfree(_apqns); + pr_debug("rc=%d\n", rc); + return rc; +} + +static int ep11_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + struct pkey_apqn *local_apqns = NULL; + int i, rc; + + if (keylen < sizeof(*hdr)) + return -EINVAL; + if (hdr->type == TOKTYPE_NON_CCA && hdr->version == TOKVER_EP11_AES_WITH_HEADER && is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { @@ -70,8 +202,6 @@ int pkey_ep11_key2protkey(u16 card, u16 dom, if (ep11_check_aes_key_with_hdr(pkey_dbf_info, 3, key, keylen, 1)) return -EINVAL; - rc = ep11_kblob2protkey(card, dom, key, hdr->len, - protkey, protkeylen, protkeytype); } else if (hdr->type == TOKTYPE_NON_CCA && hdr->version == TOKVER_EP11_ECC_WITH_HEADER && is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { @@ -79,23 +209,61 @@ int pkey_ep11_key2protkey(u16 card, u16 dom, if (ep11_check_ecc_key_with_hdr(pkey_dbf_info, 3, key, keylen, 1)) return -EINVAL; - rc = ep11_kblob2protkey(card, dom, key, hdr->len, - protkey, protkeylen, protkeytype); } else if (hdr->type == TOKTYPE_NON_CCA && hdr->version == TOKVER_EP11_AES && is_ep11_keyblob(key)) { /* EP11 AES key blob with header in session field */ if (ep11_check_aes_key(pkey_dbf_info, 3, key, keylen, 1)) return -EINVAL; - rc = ep11_kblob2protkey(card, dom, key, hdr->len, - protkey, protkeylen, protkeytype); } else { PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n", __func__, hdr->type, hdr->version); return -EINVAL; } - pr_debug("card=%d dom=%d rc=%d\n", card, dom, rc); + zcrypt_wait_api_operational(); + + if (!apqns || (nr_apqns == 1 && + apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { + nr_apqns = MAXAPQNSINLIST; + local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!local_apqns) + return -ENOMEM; + rc = ep11_apqns4key(key, keylen, 0, local_apqns, &nr_apqns); + if (rc) + goto out; + apqns = local_apqns; + } + + for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { + if (hdr->type == TOKTYPE_NON_CCA && + hdr->version == TOKVER_EP11_AES_WITH_HEADER && + is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { + rc = ep11_kblob2protkey(apqns[i].card, apqns[i].domain, + key, hdr->len, protkey, + protkeylen, protkeytype); + } else if (hdr->type == TOKTYPE_NON_CCA && + hdr->version == TOKVER_EP11_ECC_WITH_HEADER && + is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { + rc = ep11_kblob2protkey(apqns[i].card, apqns[i].domain, + key, hdr->len, protkey, + protkeylen, protkeytype); + } else if (hdr->type == TOKTYPE_NON_CCA && + hdr->version == TOKVER_EP11_AES && + is_ep11_keyblob(key)) { + rc = ep11_kblob2protkey(apqns[i].card, apqns[i].domain, + key, hdr->len, protkey, + protkeylen, protkeytype); + } else { + rc = -EINVAL; + break; + } + } + +out: + kfree(local_apqns); + pr_debug("rc=%d\n", rc); return rc; } @@ -108,12 +276,13 @@ int pkey_ep11_key2protkey(u16 card, u16 dom, * keybitsize is the bit size of the key (may be 0 for * keytype PKEY_KEYTYPE_AES_*). */ -int pkey_ep11_gen_key(u16 card, u16 dom, - u32 keytype, u32 subtype, - u32 keybitsize, u32 flags, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo) +static int ep11_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) { - int len, rc; + struct pkey_apqn *local_apqns = NULL; + int i, len, rc; /* check keytype, subtype, keybitsize */ switch (keytype) { @@ -128,9 +297,6 @@ int pkey_ep11_gen_key(u16 card, u16 dom, } keybitsize = 8 * len; switch (subtype) { - case 0: - subtype = PKEY_TYPE_EP11_AES; - break; case PKEY_TYPE_EP11: case PKEY_TYPE_EP11_AES: break; @@ -148,10 +314,29 @@ int pkey_ep11_gen_key(u16 card, u16 dom, zcrypt_wait_api_operational(); - rc = ep11_genaeskey(card, dom, keybitsize, flags, - keybuf, keybuflen, subtype); + if (!apqns || (nr_apqns == 1 && + apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { + nr_apqns = MAXAPQNSINLIST; + local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!local_apqns) + return -ENOMEM; + rc = ep11_apqns4type(subtype, NULL, NULL, 0, + local_apqns, &nr_apqns); + if (rc) + goto out; + apqns = local_apqns; + } + + for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { + rc = ep11_genaeskey(apqns[i].card, apqns[i].domain, + keybitsize, flags, + keybuf, keybuflen, subtype); + } - pr_debug("card=%d dom=%d rc=%d\n", card, dom, rc); +out: + kfree(local_apqns); + pr_debug("rc=%d\n", rc); return rc; } @@ -164,13 +349,14 @@ int pkey_ep11_gen_key(u16 card, u16 dom, * keybitsize is the bit size of the key (may be 0 for * keytype PKEY_KEYTYPE_AES_*). */ -int pkey_ep11_clr2key(u16 card, u16 dom, - u32 keytype, u32 subtype, - u32 keybitsize, u32 flags, - const u8 *clrkey, u32 clrkeylen, - u8 *keybuf, u32 *keybuflen, u32 *_keyinfo) +static int ep11_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) { - int len, rc; + struct pkey_apqn *local_apqns = NULL; + int i, len, rc; /* check keytype, subtype, clrkeylen, keybitsize */ switch (keytype) { @@ -190,9 +376,6 @@ int pkey_ep11_clr2key(u16 card, u16 dom, return -EINVAL; } switch (subtype) { - case 0: - subtype = PKEY_TYPE_EP11_AES; - break; case PKEY_TYPE_EP11: case PKEY_TYPE_EP11_AES: break; @@ -210,16 +393,35 @@ int pkey_ep11_clr2key(u16 card, u16 dom, zcrypt_wait_api_operational(); - rc = ep11_clr2keyblob(card, dom, keybitsize, flags, - clrkey, keybuf, keybuflen, subtype); + if (!apqns || (nr_apqns == 1 && + apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) { + nr_apqns = MAXAPQNSINLIST; + local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!local_apqns) + return -ENOMEM; + rc = ep11_apqns4type(subtype, NULL, NULL, 0, + local_apqns, &nr_apqns); + if (rc) + goto out; + apqns = local_apqns; + } + + for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) { + rc = ep11_clr2keyblob(apqns[i].card, apqns[i].domain, + keybitsize, flags, clrkey, + keybuf, keybuflen, subtype); + } - pr_debug("card=%d dom=%d rc=%d\n", card, dom, rc); +out: + kfree(local_apqns); + pr_debug("rc=%d\n", rc); return rc; } -int pkey_ep11_verifykey(const u8 *key, u32 keylen, - u16 *card, u16 *dom, - u32 *keytype, u32 *keybitsize, u32 *flags) +static int ep11_verifykey(const u8 *key, u32 keylen, + u16 *card, u16 *dom, + u32 *keytype, u32 *keybitsize, u32 *flags) { struct keytoken_header *hdr = (struct keytoken_header *)key; u32 nr_apqns, *apqns = NULL; @@ -288,116 +490,36 @@ out: return rc; } -int pkey_ep11_apqns4key(const u8 *key, u32 keylen, u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns) -{ - struct keytoken_header *hdr = (struct keytoken_header *)key; - u32 _nr_apqns, *_apqns = NULL; - int rc; - - if (!flags) - flags = PKEY_FLAGS_MATCH_CUR_MKVP; - - if (keylen < sizeof(struct keytoken_header) || flags == 0) - return -EINVAL; - - zcrypt_wait_api_operational(); - - if (hdr->type == TOKTYPE_NON_CCA && - (hdr->version == TOKVER_EP11_AES_WITH_HEADER || - hdr->version == TOKVER_EP11_ECC_WITH_HEADER) && - is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { - struct ep11keyblob *kb = (struct ep11keyblob *) - (key + sizeof(struct ep11kblob_header)); - int minhwtype = 0, api = 0; - - if (flags != PKEY_FLAGS_MATCH_CUR_MKVP) - return -EINVAL; - if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) { - minhwtype = ZCRYPT_CEX7; - api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4; - } - rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - minhwtype, api, kb->wkvp); - if (rc) - goto out; - - } else if (hdr->type == TOKTYPE_NON_CCA && - hdr->version == TOKVER_EP11_AES && - is_ep11_keyblob(key)) { - struct ep11keyblob *kb = (struct ep11keyblob *)key; - int minhwtype = 0, api = 0; - - if (flags != PKEY_FLAGS_MATCH_CUR_MKVP) - return -EINVAL; - if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) { - minhwtype = ZCRYPT_CEX7; - api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4; - } - rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - minhwtype, api, kb->wkvp); - if (rc) - goto out; - - } else { - PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n", - __func__, hdr->type, hdr->version); - return -EINVAL; - } - - if (apqns) { - if (*nr_apqns < _nr_apqns) - rc = -ENOSPC; - else - memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); - } - *nr_apqns = _nr_apqns; +static struct pkey_handler ep11_handler = { + .module = THIS_MODULE, + .name = "PKEY EP11 handler", + .is_supported_key = is_ep11_key, + .is_supported_keytype = is_ep11_keytype, + .key_to_protkey = ep11_key2protkey, + .gen_key = ep11_gen_key, + .clr_to_key = ep11_clr2key, + .verify_key = ep11_verifykey, + .apqns_for_key = ep11_apqns4key, + .apqns_for_keytype = ep11_apqns4type, +}; -out: - kfree(_apqns); - pr_debug("rc=%d\n", rc); - return rc; +/* + * Module init + */ +static int __init pkey_ep11_init(void) +{ + /* register this module as pkey handler for all the ep11 stuff */ + return pkey_handler_register(&ep11_handler); } -int pkey_ep11_apqns4type(enum pkey_key_type ktype, - u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, - struct pkey_apqn *apqns, size_t *nr_apqns) +/* + * Module exit + */ +static void __exit pkey_ep11_exit(void) { - u32 _nr_apqns, *_apqns = NULL; - int rc; - - zcrypt_wait_api_operational(); - - if (ktype == PKEY_TYPE_EP11 || - ktype == PKEY_TYPE_EP11_AES || - ktype == PKEY_TYPE_EP11_ECC) { - u8 *wkvp = NULL; - int api; - - if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) - wkvp = cur_mkvp; - api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4; - rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, - ZCRYPT_CEX7, api, wkvp); - if (rc) - goto out; - - } else { - PKEY_DBF_ERR("%s unknown/unsupported key type %d\n", - __func__, (int)ktype); - return -EINVAL; - } - - if (apqns) { - if (*nr_apqns < _nr_apqns) - rc = -ENOSPC; - else - memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); - } - *nr_apqns = _nr_apqns; - -out: - kfree(_apqns); - pr_debug("rc=%d\n", rc); - return rc; + /* unregister this module as pkey handler */ + pkey_handler_unregister(&ep11_handler); } + +module_init(pkey_ep11_init); +module_exit(pkey_ep11_exit); diff --git a/drivers/s390/crypto/pkey_pckmo.c b/drivers/s390/crypto/pkey_pckmo.c index d2c2c61f449b..0667e5510671 100644 --- a/drivers/s390/crypto/pkey_pckmo.c +++ b/drivers/s390/crypto/pkey_pckmo.c @@ -8,71 +8,20 @@ #define KMSG_COMPONENT "pkey" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/init.h> +#include <linux/module.h> +#include <linux/cpufeature.h> #include <asm/cpacf.h> #include <crypto/aes.h> #include <linux/random.h> #include "zcrypt_api.h" #include "zcrypt_ccamisc.h" - #include "pkey_base.h" -/* - * Prototypes - */ - -static bool is_pckmo_key(const u8 *key, u32 keylen); -static int pckmo_key2protkey(const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype); -static int pckmo_gen_protkey(u32 keytype, - u8 *protkey, u32 *protkeylen, u32 *protkeytype); -static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype); -static int pckmo_verify_protkey(const u8 *protkey, u32 protkeylen, - u32 protkeytype); - -/* - * Wrapper functions - */ - -bool pkey_is_pckmo_key(const u8 *key, u32 keylen) -{ - return is_pckmo_key(key, keylen); -} - -int pkey_pckmo_key2protkey(u16 _card, u16 _dom, - const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *keyinfo) -{ - return pckmo_key2protkey(key, keylen, - protkey, protkeylen, keyinfo); -} - -int pkey_pckmo_gen_key(u16 _card, u16 _dom, - u32 keytype, u32 _keysubtype, - u32 _keybitsize, u32 _flags, - u8 *keybuf, u32 *keybuflen, u32 *keyinfo) -{ - return pckmo_gen_protkey(keytype, - keybuf, keybuflen, keyinfo); -} - -int pkey_pckmo_clr2key(u16 _card, u16 _dom, - u32 keytype, u32 _keysubtype, - u32 _keybitsize, u32 _flags, - const u8 *clrkey, u32 clrkeylen, - u8 *keybuf, u32 *keybuflen, u32 *keyinfo) -{ - return pckmo_clr2protkey(keytype, clrkey, clrkeylen, - keybuf, keybuflen, keyinfo); -} - -int pkey_pckmo_verifykey(const u8 *key, u32 keylen, - u16 *_card, u16 *_dom, - u32 *keytype, u32 *_keybitsize, u32 *_flags) -{ - return pckmo_verify_protkey(key, keylen, *keytype); -} +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("s390 protected key PCKMO handler"); /* * Check key blob for known and supported here. @@ -112,122 +61,14 @@ static bool is_pckmo_key(const u8 *key, u32 keylen) } } -static int pckmo_key2protkey(const u8 *key, u32 keylen, - u8 *protkey, u32 *protkeylen, u32 *protkeytype) +static bool is_pckmo_keytype(enum pkey_key_type keytype) { - struct keytoken_header *hdr = (struct keytoken_header *)key; - int rc = -EINVAL; - - if (keylen < sizeof(*hdr)) - return -EINVAL; - if (hdr->type != TOKTYPE_NON_CCA) - return -EINVAL; - - switch (hdr->version) { - case TOKVER_PROTECTED_KEY: { - struct protaeskeytoken *t; - - if (keylen != sizeof(struct protaeskeytoken)) - goto out; - t = (struct protaeskeytoken *)key; - rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); - if (rc) - goto out; - memcpy(protkey, t->protkey, t->len); - *protkeylen = t->len; - *protkeytype = t->keytype; - break; - } - case TOKVER_CLEAR_KEY: { - struct clearkeytoken *t = (struct clearkeytoken *)key; - u32 keysize = 0; - - if (keylen < sizeof(struct clearkeytoken) || - keylen != sizeof(*t) + t->len) - goto out; - switch (t->keytype) { - case PKEY_KEYTYPE_AES_128: - case PKEY_KEYTYPE_AES_192: - case PKEY_KEYTYPE_AES_256: - keysize = pkey_keytype_aes_to_size(t->keytype); - break; - case PKEY_KEYTYPE_ECC_P256: - keysize = 32; - break; - case PKEY_KEYTYPE_ECC_P384: - keysize = 48; - break; - case PKEY_KEYTYPE_ECC_P521: - keysize = 80; - break; - case PKEY_KEYTYPE_ECC_ED25519: - keysize = 32; - break; - case PKEY_KEYTYPE_ECC_ED448: - keysize = 64; - break; - default: - break; - } - if (!keysize) { - PKEY_DBF_ERR("%s clear key token: unknown keytype %u\n", - __func__, t->keytype); - goto out; - } - if (t->len != keysize) { - PKEY_DBF_ERR("%s clear key token: invalid key len %u\n", - __func__, t->len); - goto out; - } - rc = pckmo_clr2protkey(t->keytype, t->clearkey, t->len, - protkey, protkeylen, protkeytype); - break; - } + switch (keytype) { + case PKEY_TYPE_PROTKEY: + return true; default: - PKEY_DBF_ERR("%s unknown non-CCA token version %d\n", - __func__, hdr->version); - break; - } - -out: - pr_debug("rc=%d\n", rc); - return rc; -} - -/* - * Generate a random protected key. - * Currently only the generation of AES protected keys - * is supported. - */ -static int pckmo_gen_protkey(u32 keytype, u8 *protkey, - u32 *protkeylen, u32 *protkeytype) -{ - u8 clrkey[32]; - int keysize; - int rc; - - keysize = pkey_keytype_aes_to_size(keytype); - if (!keysize) { - PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", __func__, - keytype); - return -EINVAL; + return false; } - - /* generate a dummy random clear key */ - get_random_bytes(clrkey, keysize); - - /* convert it to a dummy protected key */ - rc = pckmo_clr2protkey(keytype, clrkey, keysize, - protkey, protkeylen, protkeytype); - if (rc) - goto out; - - /* replace the key part of the protected key with random bytes */ - get_random_bytes(protkey, keysize); - -out: - pr_debug("rc=%d\n", rc); - return rc; } /* @@ -346,7 +187,7 @@ out: } /* - * Verify a protected key blob. + * Verify a raw protected key blob. * Currently only AES protected keys are supported. */ static int pckmo_verify_protkey(const u8 *protkey, u32 protkeylen, @@ -405,3 +246,232 @@ out: pr_debug("rc=%d\n", rc); return rc; } + +static int pckmo_key2protkey(const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + int rc = -EINVAL; + + if (keylen < sizeof(*hdr)) + return -EINVAL; + if (hdr->type != TOKTYPE_NON_CCA) + return -EINVAL; + + switch (hdr->version) { + case TOKVER_PROTECTED_KEY: { + struct protaeskeytoken *t; + + if (keylen != sizeof(struct protaeskeytoken)) + goto out; + t = (struct protaeskeytoken *)key; + rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); + if (rc) + goto out; + memcpy(protkey, t->protkey, t->len); + *protkeylen = t->len; + *protkeytype = t->keytype; + break; + } + case TOKVER_CLEAR_KEY: { + struct clearkeytoken *t = (struct clearkeytoken *)key; + u32 keysize = 0; + + if (keylen < sizeof(struct clearkeytoken) || + keylen != sizeof(*t) + t->len) + goto out; + switch (t->keytype) { + case PKEY_KEYTYPE_AES_128: + case PKEY_KEYTYPE_AES_192: + case PKEY_KEYTYPE_AES_256: + keysize = pkey_keytype_aes_to_size(t->keytype); + break; + case PKEY_KEYTYPE_ECC_P256: + keysize = 32; + break; + case PKEY_KEYTYPE_ECC_P384: + keysize = 48; + break; + case PKEY_KEYTYPE_ECC_P521: + keysize = 80; + break; + case PKEY_KEYTYPE_ECC_ED25519: + keysize = 32; + break; + case PKEY_KEYTYPE_ECC_ED448: + keysize = 64; + break; + default: + break; + } + if (!keysize) { + PKEY_DBF_ERR("%s clear key token: unknown keytype %u\n", + __func__, t->keytype); + goto out; + } + if (t->len != keysize) { + PKEY_DBF_ERR("%s clear key token: invalid key len %u\n", + __func__, t->len); + goto out; + } + rc = pckmo_clr2protkey(t->keytype, t->clearkey, t->len, + protkey, protkeylen, protkeytype); + break; + } + default: + PKEY_DBF_ERR("%s unknown non-CCA token version %d\n", + __func__, hdr->version); + break; + } + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +/* + * Generate a random protected key. + * Currently only the generation of AES protected keys + * is supported. + */ +static int pckmo_gen_protkey(u32 keytype, u32 subtype, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + u8 clrkey[32]; + int keysize; + int rc; + + keysize = pkey_keytype_aes_to_size(keytype); + if (!keysize) { + PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", __func__, + keytype); + return -EINVAL; + } + if (subtype != PKEY_TYPE_PROTKEY) { + PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n", + __func__, subtype); + return -EINVAL; + } + + /* generate a dummy random clear key */ + get_random_bytes(clrkey, keysize); + + /* convert it to a dummy protected key */ + rc = pckmo_clr2protkey(keytype, clrkey, keysize, + protkey, protkeylen, protkeytype); + if (rc) + goto out; + + /* replace the key part of the protected key with random bytes */ + get_random_bytes(protkey, keysize); + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +/* + * Verify a protected key token blob. + * Currently only AES protected keys are supported. + */ +static int pckmo_verify_key(const u8 *key, u32 keylen) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + int rc = -EINVAL; + + if (keylen < sizeof(*hdr)) + return -EINVAL; + if (hdr->type != TOKTYPE_NON_CCA) + return -EINVAL; + + switch (hdr->version) { + case TOKVER_PROTECTED_KEY: { + struct protaeskeytoken *t; + + if (keylen != sizeof(struct protaeskeytoken)) + goto out; + t = (struct protaeskeytoken *)key; + rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); + break; + } + default: + PKEY_DBF_ERR("%s unknown non-CCA token version %d\n", + __func__, hdr->version); + break; + } + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +/* + * Wrapper functions used for the pkey handler struct + */ + +static int pkey_pckmo_key2protkey(const struct pkey_apqn *_apqns, + size_t _nr_apqns, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *keyinfo) +{ + return pckmo_key2protkey(key, keylen, + protkey, protkeylen, keyinfo); +} + +static int pkey_pckmo_gen_key(const struct pkey_apqn *_apqns, size_t _nr_apqns, + u32 keytype, u32 keysubtype, + u32 _keybitsize, u32 _flags, + u8 *keybuf, u32 *keybuflen, u32 *keyinfo) +{ + return pckmo_gen_protkey(keytype, keysubtype, + keybuf, keybuflen, keyinfo); +} + +static int pkey_pckmo_verifykey(const u8 *key, u32 keylen, + u16 *_card, u16 *_dom, + u32 *_keytype, u32 *_keybitsize, u32 *_flags) +{ + return pckmo_verify_key(key, keylen); +} + +static struct pkey_handler pckmo_handler = { + .module = THIS_MODULE, + .name = "PKEY PCKMO handler", + .is_supported_key = is_pckmo_key, + .is_supported_keytype = is_pckmo_keytype, + .key_to_protkey = pkey_pckmo_key2protkey, + .gen_key = pkey_pckmo_gen_key, + .verify_key = pkey_pckmo_verifykey, +}; + +/* + * Module init + */ +static int __init pkey_pckmo_init(void) +{ + cpacf_mask_t func_mask; + + /* + * The pckmo instruction should be available - even if we don't + * actually invoke it. This instruction comes with MSA 3 which + * is also the minimum level for the kmc instructions which + * are able to work with protected keys. + */ + if (!cpacf_query(CPACF_PCKMO, &func_mask)) + return -ENODEV; + + /* register this module as pkey handler for all the pckmo stuff */ + return pkey_handler_register(&pckmo_handler); +} + +/* + * Module exit + */ +static void __exit pkey_pckmo_exit(void) +{ + /* unregister this module as pkey handler */ + pkey_handler_unregister(&pckmo_handler); +} + +module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_pckmo_init); +module_exit(pkey_pckmo_exit); diff --git a/drivers/s390/crypto/pkey_sysfs.c b/drivers/s390/crypto/pkey_sysfs.c index 684f87d6e9f1..242eb6b1a158 100644 --- a/drivers/s390/crypto/pkey_sysfs.c +++ b/drivers/s390/crypto/pkey_sysfs.c @@ -8,7 +8,6 @@ #define KMSG_COMPONENT "pkey" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include <asm/pkey.h> #include <linux/sysfs.h> #include "zcrypt_api.h" @@ -42,10 +41,10 @@ static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf, protkeytoken.keytype = keytype; protkey.len = sizeof(protkey.protkey); - rc = pkey_pckmo_gen_key(0, 0, - protkeytoken.keytype, 0, 0, 0, - protkey.protkey, &protkey.len, - &protkey.type); + rc = pkey_handler_gen_key(NULL, 0, keytype, + PKEY_TYPE_PROTKEY, 0, 0, + protkey.protkey, &protkey.len, + &protkey.type); if (rc) return rc; @@ -57,10 +56,10 @@ static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf, if (is_xts) { /* xts needs a second protected key, reuse protkey struct */ protkey.len = sizeof(protkey.protkey); - rc = pkey_pckmo_gen_key(0, 0, - protkeytoken.keytype, 0, 0, 0, - protkey.protkey, &protkey.len, - &protkey.type); + rc = pkey_handler_gen_key(NULL, 0, keytype, + PKEY_TYPE_PROTKEY, 0, 0, + protkey.protkey, &protkey.len, + &protkey.type); if (rc) return rc; @@ -166,18 +165,18 @@ static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, return -EINVAL; buflen = sizeof(seckey->seckey); - rc = pkey_cca_gen_key(-1, -1, keytype, - PKEY_TYPE_CCA_DATA, 0, 0, - seckey->seckey, &buflen, NULL); + rc = pkey_handler_gen_key(NULL, 0, keytype, + PKEY_TYPE_CCA_DATA, 0, 0, + seckey->seckey, &buflen, NULL); if (rc) return rc; if (is_xts) { seckey++; buflen = sizeof(seckey->seckey); - rc = pkey_cca_gen_key(-1, -1, keytype, - PKEY_TYPE_CCA_DATA, 0, 0, - seckey->seckey, &buflen, NULL); + rc = pkey_handler_gen_key(NULL, 0, keytype, + PKEY_TYPE_CCA_DATA, 0, 0, + seckey->seckey, &buflen, NULL); if (rc) return rc; @@ -270,9 +269,7 @@ static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits, size_t count) { u32 keysize = CCACIPHERTOKENSIZE; - struct pkey_apqn *apqns = NULL; - int i, rc, card, dom; - size_t nr_apqns; + int rc; if (off != 0 || count < CCACIPHERTOKENSIZE) return -EINVAL; @@ -280,51 +277,27 @@ static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits, if (count < 2 * CCACIPHERTOKENSIZE) return -EINVAL; - nr_apqns = MAXAPQNSINLIST; - apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL); - if (!apqns) - return -ENOMEM; - - /* build a list of apqns able to generate an cipher key */ - rc = pkey_cca_apqns4type(PKEY_TYPE_CCA_CIPHER, - NULL, NULL, 0, - apqns, &nr_apqns); - if (rc) { - kfree(apqns); - return rc; - } - memset(buf, 0, is_xts ? 2 * keysize : keysize); - /* simple try all apqns from the list */ - for (i = 0, rc = -ENODEV; rc && i < nr_apqns; i++) { - card = apqns[i].card; - dom = apqns[i].domain; - rc = pkey_cca_gen_key(card, dom, - pkey_aes_bitsize_to_keytype(keybits), - PKEY_TYPE_CCA_CIPHER, keybits, 0, - buf, &keysize, NULL); - } - if (rc) { - kfree(apqns); + rc = pkey_handler_gen_key(NULL, 0, + pkey_aes_bitsize_to_keytype(keybits), + PKEY_TYPE_CCA_CIPHER, keybits, 0, + buf, &keysize, NULL); + if (rc) return rc; - } if (is_xts) { keysize = CCACIPHERTOKENSIZE; buf += CCACIPHERTOKENSIZE; - rc = pkey_cca_gen_key(card, dom, - pkey_aes_bitsize_to_keytype(keybits), - PKEY_TYPE_CCA_CIPHER, keybits, 0, - buf, &keysize, NULL); - kfree(apqns); + rc = pkey_handler_gen_key(NULL, 0, + pkey_aes_bitsize_to_keytype(keybits), + PKEY_TYPE_CCA_CIPHER, keybits, 0, + buf, &keysize, NULL); if (rc) return rc; return 2 * CCACIPHERTOKENSIZE; } - kfree(apqns); - return CCACIPHERTOKENSIZE; } @@ -412,9 +385,7 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits, size_t count) { u32 keysize = MAXEP11AESKEYBLOBSIZE; - struct pkey_apqn *apqns = NULL; - int i, rc, card, dom; - size_t nr_apqns; + int rc; if (off != 0 || count < MAXEP11AESKEYBLOBSIZE) return -EINVAL; @@ -422,51 +393,27 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits, if (count < 2 * MAXEP11AESKEYBLOBSIZE) return -EINVAL; - nr_apqns = MAXAPQNSINLIST; - apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL); - if (!apqns) - return -ENOMEM; - - /* build a list of apqns able to generate an EP11 AES key */ - rc = pkey_ep11_apqns4type(PKEY_TYPE_EP11_AES, - NULL, NULL, 0, - apqns, &nr_apqns); - if (rc) { - kfree(apqns); - return rc; - } - memset(buf, 0, is_xts ? 2 * keysize : keysize); - /* simple try all apqns from the list */ - for (i = 0, rc = -ENODEV; rc && i < nr_apqns; i++) { - card = apqns[i].card; - dom = apqns[i].domain; - rc = pkey_ep11_gen_key(card, dom, - pkey_aes_bitsize_to_keytype(keybits), - PKEY_TYPE_EP11_AES, keybits, 0, - buf, &keysize, NULL); - } - if (rc) { - kfree(apqns); + rc = pkey_handler_gen_key(NULL, 0, + pkey_aes_bitsize_to_keytype(keybits), + PKEY_TYPE_EP11_AES, keybits, 0, + buf, &keysize, NULL); + if (rc) return rc; - } if (is_xts) { keysize = MAXEP11AESKEYBLOBSIZE; buf += MAXEP11AESKEYBLOBSIZE; - rc = pkey_ep11_gen_key(card, dom, - pkey_aes_bitsize_to_keytype(keybits), - PKEY_TYPE_EP11_AES, keybits, 0, - buf, &keysize, NULL); - kfree(apqns); + rc = pkey_handler_gen_key(NULL, 0, + pkey_aes_bitsize_to_keytype(keybits), + PKEY_TYPE_EP11_AES, keybits, 0, + buf, &keysize, NULL); if (rc) return rc; return 2 * MAXEP11AESKEYBLOBSIZE; } - kfree(apqns); - return MAXEP11AESKEYBLOBSIZE; } |