summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/s390/configs/debug_defconfig3
-rw-r--r--arch/s390/configs/defconfig3
-rw-r--r--arch/s390/include/uapi/asm/pkey.h1
-rw-r--r--drivers/crypto/Kconfig75
-rw-r--r--drivers/s390/crypto/Makefile16
-rw-r--r--drivers/s390/crypto/pkey_api.c690
-rw-r--r--drivers/s390/crypto/pkey_base.c293
-rw-r--r--drivers/s390/crypto/pkey_base.h130
-rw-r--r--drivers/s390/crypto/pkey_cca.c489
-rw-r--r--drivers/s390/crypto/pkey_ep11.c418
-rw-r--r--drivers/s390/crypto/pkey_pckmo.c412
-rw-r--r--drivers/s390/crypto/pkey_sysfs.c121
12 files changed, 1508 insertions, 1143 deletions
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 6c57f024acae..7ec1b8cd0de9 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -797,6 +797,9 @@ CONFIG_CRYPTO_CHACHA_S390=m
CONFIG_CRYPTO_HMAC_S390=m
CONFIG_ZCRYPT=m
CONFIG_PKEY=m
+CONFIG_PKEY_CCA=m
+CONFIG_PKEY_EP11=m
+CONFIG_PKEY_PCKMO=m
CONFIG_CRYPTO_PAES_S390=m
CONFIG_CRYPTO_DEV_VIRTIO=m
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index c75e375570fa..df4addd1834a 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -784,6 +784,9 @@ CONFIG_CRYPTO_CHACHA_S390=m
CONFIG_CRYPTO_HMAC_S390=m
CONFIG_ZCRYPT=m
CONFIG_PKEY=m
+CONFIG_PKEY_CCA=m
+CONFIG_PKEY_EP11=m
+CONFIG_PKEY_PCKMO=m
CONFIG_CRYPTO_PAES_S390=m
CONFIG_CRYPTO_DEV_VIRTIO=m
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h
index 5ad76471e73f..04183080cdbb 100644
--- a/arch/s390/include/uapi/asm/pkey.h
+++ b/arch/s390/include/uapi/asm/pkey.h
@@ -50,6 +50,7 @@ enum pkey_key_type {
PKEY_TYPE_CCA_ECC = (__u32) 0x1f,
PKEY_TYPE_EP11_AES = (__u32) 6,
PKEY_TYPE_EP11_ECC = (__u32) 7,
+ PKEY_TYPE_PROTKEY = (__u32) 8,
};
/* the newer ioctls use a pkey_key_size enum for key size information */
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 94f23c6fc93b..08b1238bcd7b 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -21,7 +21,7 @@ config CRYPTO_DEV_PADLOCK
(so called VIA PadLock ACE, Advanced Cryptography Engine)
that provides instructions for very fast cryptographic
operations with supported algorithms.
-
+
The instructions are used only when the CPU supports them.
Otherwise software encryption is used.
@@ -78,18 +78,79 @@ config ZCRYPT
config PKEY
tristate "Kernel API for protected key handling"
depends on S390
- depends on ZCRYPT
help
- With this option enabled the pkey kernel module provides an API
+ With this option enabled the pkey kernel modules provide an API
for creation and handling of protected keys. Other parts of the
kernel or userspace applications may use these functions.
+ The protected key support is distributed into:
+ - A pkey base and API kernel module (pkey.ko) which offers the
+ infrastructure for the pkey handler kernel modules, the ioctl
+ and the sysfs API and the in-kernel API to the crypto cipher
+ implementations using protected key.
+ - A pkey pckmo kernel module (pkey-pckmo.ko) which is automatically
+ loaded when pckmo support (that is generation of protected keys
+ from clear key values) is available.
+ - A pkey CCA kernel module (pkey-cca.ko) which is automatically
+ loaded when a CEX crypto card is available.
+ - A pkey EP11 kernel module (pkey-ep11.ko) which is automatically
+ loaded when a CEX crypto card is available.
+
Select this option if you want to enable the kernel and userspace
- API for proteced key handling.
+ API for protected key handling.
+
+config PKEY_CCA
+ tristate "PKEY CCA support handler"
+ depends on PKEY
+ depends on ZCRYPT
+ help
+ This is the CCA support handler for deriving protected keys
+ from CCA (secure) keys. Also this handler provides an alternate
+ way to make protected keys from clear key values.
+
+ The PKEY CCA support handler needs a Crypto Express card (CEX)
+ in CCA mode.
+
+ If you have selected the PKEY option then you should also enable
+ this option unless you are sure you never need to derive protected
+ keys from CCA key material.
+
+config PKEY_EP11
+ tristate "PKEY EP11 support handler"
+ depends on PKEY
+ depends on ZCRYPT
+ help
+ This is the EP11 support handler for deriving protected keys
+ from EP11 (secure) keys. Also this handler provides an alternate
+ way to make protected keys from clear key values.
+
+ The PKEY EP11 support handler needs a Crypto Express card (CEX)
+ in EP11 mode.
+
+ If you have selected the PKEY option then you should also enable
+ this option unless you are sure you never need to derive protected
+ keys from EP11 key material.
+
+config PKEY_PCKMO
+ tristate "PKEY PCKMO support handler"
+ depends on PKEY
+ help
+ This is the PCKMO support handler for deriving protected keys
+ from clear key values via invoking the PCKMO instruction.
+
+ The PCKMO instruction can be enabled and disabled in the crypto
+ settings at the LPAR profile. This handler checks for availability
+ during initialization and if build as a kernel module unloads
+ itself if PCKMO is disabled.
+
+ The PCKMO way of deriving protected keys from clear key material
+ is especially used during self test of protected key ciphers like
+ PAES but the CCA and EP11 handler provide alternate ways to
+ generate protected keys from clear key values.
- Please note that creation of protected keys from secure keys
- requires to have at least one CEX card in coprocessor mode
- available at runtime.
+ If you have selected the PKEY option then you should also enable
+ this option unless you are sure you never need to derive protected
+ keys from clear key values directly via PCKMO.
config CRYPTO_PAES_S390
tristate "PAES cipher algorithms"
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;
}