summaryrefslogtreecommitdiff
path: root/drivers/s390/crypto/pkey_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto/pkey_api.c')
-rw-r--r--drivers/s390/crypto/pkey_api.c2657
1 files changed, 560 insertions, 2097 deletions
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index ffc0b5db55c2..c20251e00cf9 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -10,1338 +10,698 @@
#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/random.h>
-#include <linux/cpufeature.h>
-#include <asm/zcrypt.h>
-#include <asm/cpacf.h>
-#include <asm/pkey.h>
-#include <crypto/aes.h>
#include "zcrypt_api.h"
#include "zcrypt_ccamisc.h"
-#include "zcrypt_ep11misc.h"
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("s390 protected key interface");
-
-#define KEYBLOBBUFSIZE 8192 /* key buffer size used for internal processing */
-#define MINKEYBLOBBUFSIZE (sizeof(struct keytoken_header))
-#define PROTKEYBLOBBUFSIZE 256 /* protected key buffer size used internal */
-#define MAXAPQNSINLIST 64 /* max 64 apqns within a apqn list */
-#define AES_WK_VP_SIZE 32 /* Size of WK VP block appended to a prot key */
+#include "pkey_base.h"
/*
- * debug feature data and functions
+ * Helper functions
*/
-
-static debug_info_t *pkey_dbf_info;
-
-#define PKEY_DBF_INFO(...) debug_sprintf_event(pkey_dbf_info, 5, ##__VA_ARGS__)
-#define PKEY_DBF_WARN(...) debug_sprintf_event(pkey_dbf_info, 4, ##__VA_ARGS__)
-#define PKEY_DBF_ERR(...) debug_sprintf_event(pkey_dbf_info, 3, ##__VA_ARGS__)
-
-static void __init pkey_debug_init(void)
+static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
+ const u8 *key, size_t keylen,
+ u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- /* 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);
-}
+ int rc;
-/* inside view of a protected key token (only type 0x00 version 0x01) */
-struct protaeskeytoken {
- u8 type; /* 0x00 for PAES specific key tokens */
- u8 res0[3];
- u8 version; /* should be 0x01 for protected AES key token */
- u8 res1[3];
- u32 keytype; /* key type, one of the PKEY_KEYTYPE values */
- u32 len; /* bytes actually stored in protkey[] */
- u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */
-} __packed;
-
-/* inside view of a clear key token (type 0x00 version 0x02) */
-struct clearkeytoken {
- u8 type; /* 0x00 for PAES specific key tokens */
- u8 res0[3];
- u8 version; /* 0x02 for clear key token */
- u8 res1[3];
- u32 keytype; /* key type, one of the PKEY_KEYTYPE_* values */
- u32 len; /* bytes actually stored in clearkey[] */
- u8 clearkey[]; /* clear key value */
-} __packed;
-
-/* helper function which translates the PKEY_KEYTYPE_AES_* to their keysize */
-static inline u32 pkey_keytype_aes_to_size(u32 keytype)
-{
- switch (keytype) {
- case PKEY_KEYTYPE_AES_128:
- return 16;
- case PKEY_KEYTYPE_AES_192:
- return 24;
- case PKEY_KEYTYPE_AES_256:
- return 32;
- default:
- return 0;
+ /* try the direct way */
+ rc = pkey_handler_key_to_protkey(apqns, nr_apqns,
+ key, keylen,
+ protkey, protkeylen,
+ protkeytype);
+
+ /* if this did not work, try the slowpath way */
+ if (rc == -ENODEV) {
+ rc = pkey_handler_slowpath_key_to_protkey(apqns, nr_apqns,
+ key, keylen,
+ protkey, protkeylen,
+ protkeytype);
+ if (rc)
+ rc = -ENODEV;
}
+
+ pr_debug("rc=%d\n", rc);
+ return rc;
}
/*
- * Create a protected key from a clear key value via PCKMO instruction.
+ * In-Kernel function: Transform a key blob (of any type) into a protected key
*/
-static int pkey_clr2protkey(u32 keytype, const u8 *clrkey,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+int pkey_key2protkey(const u8 *key, u32 keylen,
+ u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- /* mask of available pckmo subfunctions */
- static cpacf_mask_t pckmo_functions;
-
- u8 paramblock[112];
- u32 pkeytype;
- int keysize;
- long fc;
-
- switch (keytype) {
- case PKEY_KEYTYPE_AES_128:
- /* 16 byte key, 32 byte aes wkvp, total 48 bytes */
- keysize = 16;
- pkeytype = keytype;
- fc = CPACF_PCKMO_ENC_AES_128_KEY;
- break;
- case PKEY_KEYTYPE_AES_192:
- /* 24 byte key, 32 byte aes wkvp, total 56 bytes */
- keysize = 24;
- pkeytype = keytype;
- fc = CPACF_PCKMO_ENC_AES_192_KEY;
- break;
- case PKEY_KEYTYPE_AES_256:
- /* 32 byte key, 32 byte aes wkvp, total 64 bytes */
- keysize = 32;
- pkeytype = keytype;
- fc = CPACF_PCKMO_ENC_AES_256_KEY;
- break;
- case PKEY_KEYTYPE_ECC_P256:
- /* 32 byte key, 32 byte aes wkvp, total 64 bytes */
- keysize = 32;
- pkeytype = PKEY_KEYTYPE_ECC;
- fc = CPACF_PCKMO_ENC_ECC_P256_KEY;
- break;
- case PKEY_KEYTYPE_ECC_P384:
- /* 48 byte key, 32 byte aes wkvp, total 80 bytes */
- keysize = 48;
- pkeytype = PKEY_KEYTYPE_ECC;
- fc = CPACF_PCKMO_ENC_ECC_P384_KEY;
- break;
- case PKEY_KEYTYPE_ECC_P521:
- /* 80 byte key, 32 byte aes wkvp, total 112 bytes */
- keysize = 80;
- pkeytype = PKEY_KEYTYPE_ECC;
- fc = CPACF_PCKMO_ENC_ECC_P521_KEY;
- break;
- case PKEY_KEYTYPE_ECC_ED25519:
- /* 32 byte key, 32 byte aes wkvp, total 64 bytes */
- keysize = 32;
- pkeytype = PKEY_KEYTYPE_ECC;
- fc = CPACF_PCKMO_ENC_ECC_ED25519_KEY;
- break;
- case PKEY_KEYTYPE_ECC_ED448:
- /* 64 byte key, 32 byte aes wkvp, total 96 bytes */
- keysize = 64;
- pkeytype = PKEY_KEYTYPE_ECC;
- fc = CPACF_PCKMO_ENC_ECC_ED448_KEY;
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
- __func__, keytype);
- return -EINVAL;
- }
-
- if (*protkeylen < keysize + AES_WK_VP_SIZE) {
- PKEY_DBF_ERR("%s prot key buffer size too small: %u < %d\n",
- __func__, *protkeylen, keysize + AES_WK_VP_SIZE);
- return -EINVAL;
- }
+ int rc;
- /* Did we already check for PCKMO ? */
- if (!pckmo_functions.bytes[0]) {
- /* no, so check now */
- if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
- return -ENODEV;
- }
- /* check for the pckmo subfunction we need now */
- if (!cpacf_test_func(&pckmo_functions, fc)) {
- PKEY_DBF_ERR("%s pckmo functions not available\n", __func__);
- return -ENODEV;
+ rc = key2protkey(NULL, 0, key, keylen,
+ protkey, protkeylen, protkeytype);
+ if (rc == -ENODEV) {
+ pkey_handler_request_modules();
+ rc = key2protkey(NULL, 0, key, keylen,
+ protkey, protkeylen, protkeytype);
}
- /* prepare param block */
- memset(paramblock, 0, sizeof(paramblock));
- memcpy(paramblock, clrkey, keysize);
-
- /* call the pckmo instruction */
- cpacf_pckmo(fc, paramblock);
-
- /* copy created protected key to key buffer including the wkvp block */
- *protkeylen = keysize + AES_WK_VP_SIZE;
- memcpy(protkey, paramblock, *protkeylen);
- *protkeytype = pkeytype;
-
- return 0;
+ return rc;
}
+EXPORT_SYMBOL(pkey_key2protkey);
/*
- * Find card and transform secure key into protected key.
+ * Ioctl functions
*/
-static int pkey_skey2pkey(const u8 *key, u8 *protkey,
- u32 *protkeylen, u32 *protkeytype)
-{
- struct keytoken_header *hdr = (struct keytoken_header *)key;
- u16 cardnr, domain;
- int rc, verify;
-
- zcrypt_wait_api_operational();
-
- /*
- * The cca_xxx2protkey call may fail when a card has been
- * addressed where the master key was changed after last fetch
- * of the mkvp into the cache. Try 3 times: First without verify
- * then with verify and last round with verify and old master
- * key verification pattern match not ignored.
- */
- for (verify = 0; verify < 3; verify++) {
- rc = cca_findcard(key, &cardnr, &domain, verify);
- if (rc < 0)
- continue;
- if (rc > 0 && verify < 2)
- continue;
- switch (hdr->version) {
- case TOKVER_CCA_AES:
- rc = cca_sec2protkey(cardnr, domain, key,
- protkey, protkeylen, protkeytype);
- break;
- case TOKVER_CCA_VLSC:
- rc = cca_cipher2protkey(cardnr, domain, key,
- protkey, protkeylen,
- protkeytype);
- break;
- default:
- return -EINVAL;
- }
- if (rc == 0)
- break;
- }
- if (rc)
- pr_debug("%s failed rc=%d\n", __func__, rc);
+static void *_copy_key_from_user(void __user *ukey, size_t keylen)
+{
+ if (!ukey || keylen < MINKEYBLOBBUFSIZE || keylen > KEYBLOBBUFSIZE)
+ return ERR_PTR(-EINVAL);
- return rc;
+ return memdup_user(ukey, keylen);
}
-/*
- * Construct EP11 key with given clear key value.
- */
-static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
- u8 *keybuf, size_t *keybuflen)
+static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns)
{
- u32 nr_apqns, *apqns = NULL;
- u16 card, dom;
- int i, rc;
-
- zcrypt_wait_api_operational();
-
- /* build a list of apqns suitable for ep11 keys with cpacf support */
- rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7,
- ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
- NULL);
- if (rc)
- goto out;
-
- /* go through the list of apqns and try to bild an ep11 key */
- for (rc = -ENODEV, i = 0; i < nr_apqns; i++) {
- card = apqns[i] >> 16;
- dom = apqns[i] & 0xFFFF;
- rc = ep11_clr2keyblob(card, dom, clrkeylen * 8,
- 0, clrkey, keybuf, keybuflen,
- PKEY_TYPE_EP11);
- if (rc == 0)
- break;
- }
+ if (!uapqns || nr_apqns == 0)
+ return NULL;
-out:
- kfree(apqns);
- if (rc)
- pr_debug("%s failed rc=%d\n", __func__, rc);
- return rc;
+ return memdup_user(uapqns, nr_apqns * sizeof(struct pkey_apqn));
}
-/*
- * Find card and transform EP11 secure key into protected key.
- */
-static int pkey_ep11key2pkey(const u8 *key, size_t keylen,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_genseck(struct pkey_genseck __user *ugs)
{
- u32 nr_apqns, *apqns = NULL;
- int i, j, rc = -ENODEV;
- u16 card, dom;
+ struct pkey_genseck kgs;
+ struct pkey_apqn apqn;
+ u32 keybuflen;
+ int rc;
- zcrypt_wait_api_operational();
+ if (copy_from_user(&kgs, ugs, sizeof(kgs)))
+ return -EFAULT;
- /* try two times in case of failure */
- for (i = 0; i < 2 && rc; i++) {
+ apqn.card = kgs.cardnr;
+ apqn.domain = kgs.domain;
+ keybuflen = sizeof(kgs.seckey.seckey);
+ 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));
- /* build a list of apqns suitable for this key */
- rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7,
- ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
- ep11_kb_wkvp(key, keylen));
- if (rc)
- continue; /* retry findcard on failure */
-
- /* go through the list of apqns and try to derive an pkey */
- for (rc = -ENODEV, j = 0; j < nr_apqns && rc; j++) {
- card = apqns[j] >> 16;
- dom = apqns[j] & 0xFFFF;
- rc = ep11_kblob2protkey(card, dom, key, keylen,
- protkey, protkeylen, protkeytype);
- }
+ return rc;
+}
- kfree(apqns);
- }
+static int pkey_ioctl_clr2seck(struct pkey_clr2seck __user *ucs)
+{
+ struct pkey_clr2seck kcs;
+ struct pkey_apqn apqn;
+ u32 keybuflen;
+ int rc;
- if (rc)
- pr_debug("%s failed rc=%d\n", __func__, 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_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));
return rc;
}
-/*
- * Verify key and give back some info about the key.
- */
-static int pkey_verifykey(const struct pkey_seckey *seckey,
- u16 *pcardnr, u16 *pdomain,
- u16 *pkeysize, u32 *pattributes)
+static int pkey_ioctl_sec2protk(struct pkey_sec2protk __user *usp)
{
- struct secaeskeytoken *t = (struct secaeskeytoken *)seckey;
- u16 cardnr, domain;
+ struct pkey_sec2protk ksp;
+ struct pkey_apqn apqn;
int rc;
- /* check the secure key for valid AES secure key */
- rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, (u8 *)seckey, 0);
- if (rc)
- goto out;
- if (pattributes)
- *pattributes = PKEY_VERIFY_ATTR_AES;
- if (pkeysize)
- *pkeysize = t->bitsize;
-
- /* try to find a card which can handle this key */
- rc = cca_findcard(seckey->seckey, &cardnr, &domain, 1);
- if (rc < 0)
- goto out;
-
- if (rc > 0) {
- /* key mkvp matches to old master key mkvp */
- pr_debug("%s secure key has old mkvp\n", __func__);
- if (pattributes)
- *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP;
- rc = 0;
- }
+ 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_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));
- if (pcardnr)
- *pcardnr = cardnr;
- if (pdomain)
- *pdomain = domain;
-
-out:
- pr_debug("%s rc=%d\n", __func__, rc);
return rc;
}
-/*
- * Generate a random protected key
- */
-static int pkey_genprotkey(u32 keytype, u8 *protkey,
- u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_clr2protk(struct pkey_clr2protk __user *ucp)
{
- u8 clrkey[32];
- int keysize;
+ struct pkey_clr2protk kcp;
+ struct clearkeytoken *t;
+ u32 keylen;
+ u8 *tmpbuf;
int rc;
- keysize = pkey_keytype_aes_to_size(keytype);
- if (!keysize) {
- PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", __func__,
- keytype);
+ 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);
- /* generate a dummy random clear key */
- get_random_bytes(clrkey, keysize);
+ rc = key2protkey(NULL, 0,
+ tmpbuf, sizeof(*t) + keylen,
+ kcp.protkey.protkey,
+ &kcp.protkey.len, &kcp.protkey.type);
+ pr_debug("key2protkey()=%d\n", rc);
- /* convert it to a dummy protected key */
- rc = pkey_clr2protkey(keytype, clrkey,
- protkey, protkeylen, protkeytype);
- if (rc)
- return rc;
+ kfree_sensitive(tmpbuf);
- /* replace the key part of the protected key with random bytes */
- get_random_bytes(protkey, keysize);
+ if (!rc && copy_to_user(ucp, &kcp, sizeof(kcp)))
+ rc = -EFAULT;
+ memzero_explicit(&kcp, sizeof(kcp));
- return 0;
+ return rc;
}
-/*
- * Verify if a protected key is still valid
- */
-static int pkey_verifyprotkey(const u8 *protkey, u32 protkeylen,
- u32 protkeytype)
+static int pkey_ioctl_findcard(struct pkey_findcard __user *ufc)
{
- struct {
- u8 iv[AES_BLOCK_SIZE];
- u8 key[MAXPROTKEYSIZE];
- } param;
- u8 null_msg[AES_BLOCK_SIZE];
- u8 dest_buf[AES_BLOCK_SIZE];
- unsigned int k, pkeylen;
- unsigned long fc;
-
- switch (protkeytype) {
- case PKEY_KEYTYPE_AES_128:
- pkeylen = 16 + AES_WK_VP_SIZE;
- fc = CPACF_KMC_PAES_128;
- break;
- case PKEY_KEYTYPE_AES_192:
- pkeylen = 24 + AES_WK_VP_SIZE;
- fc = CPACF_KMC_PAES_192;
- break;
- case PKEY_KEYTYPE_AES_256:
- pkeylen = 32 + AES_WK_VP_SIZE;
- fc = CPACF_KMC_PAES_256;
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", __func__,
- protkeytype);
- return -EINVAL;
- }
- if (protkeylen != pkeylen) {
- PKEY_DBF_ERR("%s invalid protected key size %u for keytype %u\n",
- __func__, protkeylen, protkeytype);
- return -EINVAL;
- }
+ struct pkey_findcard kfc;
+ struct pkey_apqn *apqns;
+ size_t nr_apqns;
+ int rc;
- memset(null_msg, 0, sizeof(null_msg));
+ if (copy_from_user(&kfc, ufc, sizeof(kfc)))
+ return -EFAULT;
- memset(param.iv, 0, sizeof(param.iv));
- memcpy(param.key, protkey, protkeylen);
+ nr_apqns = MAXAPQNSINLIST;
+ apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL);
+ if (!apqns)
+ return -ENOMEM;
- k = cpacf_kmc(fc | CPACF_ENCRYPT, &param, null_msg, dest_buf,
- sizeof(null_msg));
- if (k != sizeof(null_msg)) {
- PKEY_DBF_ERR("%s protected key is not valid\n", __func__);
- return -EKEYREJECTED;
+ rc = pkey_handler_apqns_for_key(kfc.seckey.seckey,
+ sizeof(kfc.seckey.seckey),
+ PKEY_FLAGS_MATCH_CUR_MKVP,
+ apqns, &nr_apqns);
+ 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;
}
+ kfc.cardnr = apqns[0].card;
+ kfc.domain = apqns[0].domain;
+ kfree(apqns);
+ if (copy_to_user(ufc, &kfc, sizeof(kfc)))
+ return -EFAULT;
return 0;
}
-/* Helper for pkey_nonccatok2pkey, handles aes clear key token */
-static int nonccatokaes2pkey(const struct clearkeytoken *t,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_skey2pkey(struct pkey_skey2pkey __user *usp)
{
- size_t tmpbuflen = max_t(size_t, SECKEYBLOBSIZE, MAXEP11AESKEYBLOBSIZE);
- u8 *tmpbuf = NULL;
- u32 keysize;
+ struct pkey_skey2pkey ksp;
int rc;
- keysize = pkey_keytype_aes_to_size(t->keytype);
- if (!keysize) {
- PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
- __func__, t->keytype);
- return -EINVAL;
- }
- if (t->len != keysize) {
- PKEY_DBF_ERR("%s non clear key aes token: invalid key len %u\n",
- __func__, t->len);
- return -EINVAL;
- }
-
- /* try direct way with the PCKMO instruction */
- rc = pkey_clr2protkey(t->keytype, t->clearkey,
- protkey, protkeylen, protkeytype);
- if (!rc)
- goto out;
+ if (copy_from_user(&ksp, usp, sizeof(ksp)))
+ return -EFAULT;
+
+ ksp.protkey.len = sizeof(ksp.protkey.protkey);
+ 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));
- /* PCKMO failed, so try the CCA secure key way */
- tmpbuf = kmalloc(tmpbuflen, GFP_ATOMIC);
- if (!tmpbuf)
- return -ENOMEM;
- zcrypt_wait_api_operational();
- rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype, t->clearkey, tmpbuf);
- if (rc)
- goto try_via_ep11;
- rc = pkey_skey2pkey(tmpbuf,
- protkey, protkeylen, protkeytype);
- if (!rc)
- goto out;
-
-try_via_ep11:
- /* if the CCA way also failed, let's try via EP11 */
- rc = pkey_clr2ep11key(t->clearkey, t->len,
- tmpbuf, &tmpbuflen);
- if (rc)
- goto failure;
- rc = pkey_ep11key2pkey(tmpbuf, tmpbuflen,
- protkey, protkeylen, protkeytype);
- if (!rc)
- goto out;
-
-failure:
- PKEY_DBF_ERR("%s unable to build protected key from clear", __func__);
-
-out:
- kfree(tmpbuf);
return rc;
}
-/* Helper for pkey_nonccatok2pkey, handles ecc clear key token */
-static int nonccatokecc2pkey(const struct clearkeytoken *t,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_verifykey(struct pkey_verifykey __user *uvk)
{
- u32 keylen;
+ u32 keytype, keybitsize, flags;
+ struct pkey_verifykey kvk;
int rc;
- switch (t->keytype) {
- case PKEY_KEYTYPE_ECC_P256:
- keylen = 32;
- break;
- case PKEY_KEYTYPE_ECC_P384:
- keylen = 48;
- break;
- case PKEY_KEYTYPE_ECC_P521:
- keylen = 80;
- break;
- case PKEY_KEYTYPE_ECC_ED25519:
- keylen = 32;
- break;
- case PKEY_KEYTYPE_ECC_ED448:
- keylen = 64;
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
- __func__, t->keytype);
- return -EINVAL;
- }
-
- if (t->len != keylen) {
- PKEY_DBF_ERR("%s non clear key ecc token: invalid key len %u\n",
- __func__, t->len);
- return -EINVAL;
- }
+ if (copy_from_user(&kvk, uvk, sizeof(kvk)))
+ return -EFAULT;
- /* only one path possible: via PCKMO instruction */
- rc = pkey_clr2protkey(t->keytype, t->clearkey,
- protkey, protkeylen, protkeytype);
- if (rc) {
- PKEY_DBF_ERR("%s unable to build protected key from clear",
- __func__);
- }
+ kvk.cardnr = 0xFFFF;
+ kvk.domain = 0xFFFF;
+ 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;
+ kvk.keysize = (u16)keybitsize;
+ if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
+ kvk.attributes |= PKEY_VERIFY_ATTR_OLD_MKVP;
+ if (!rc && copy_to_user(uvk, &kvk, sizeof(kvk)))
+ rc = -EFAULT;
+ memzero_explicit(&kvk, sizeof(kvk));
return rc;
}
-/*
- * Transform a non-CCA key token into a protected key
- */
-static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_genprotk(struct pkey_genprotk __user *ugp)
{
- struct keytoken_header *hdr = (struct keytoken_header *)key;
- int rc = -EINVAL;
+ struct pkey_genprotk kgp;
+ int rc;
- switch (hdr->version) {
- case TOKVER_PROTECTED_KEY: {
- struct protaeskeytoken *t;
+ if (copy_from_user(&kgp, ugp, sizeof(kgp)))
+ return -EFAULT;
- if (keylen != sizeof(struct protaeskeytoken))
- goto out;
- t = (struct protaeskeytoken *)key;
- rc = pkey_verifyprotkey(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;
-
- 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:
- rc = nonccatokaes2pkey(t, protkey,
- protkeylen, protkeytype);
- break;
- case PKEY_KEYTYPE_ECC_P256:
- case PKEY_KEYTYPE_ECC_P384:
- case PKEY_KEYTYPE_ECC_P521:
- case PKEY_KEYTYPE_ECC_ED25519:
- case PKEY_KEYTYPE_ECC_ED448:
- rc = nonccatokecc2pkey(t, protkey,
- protkeylen, protkeytype);
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported non cca clear key type %u\n",
- __func__, t->keytype);
- return -EINVAL;
- }
- break;
- }
- case TOKVER_EP11_AES: {
- /* check ep11 key for exportable as protected key */
- rc = ep11_check_aes_key(pkey_dbf_info, 3, key, keylen, 1);
- if (rc)
- goto out;
- rc = pkey_ep11key2pkey(key, keylen,
- protkey, protkeylen, protkeytype);
- break;
- }
- case TOKVER_EP11_AES_WITH_HEADER:
- /* check ep11 key with header for exportable as protected key */
- rc = ep11_check_aes_key_with_hdr(pkey_dbf_info,
- 3, key, keylen, 1);
- if (rc)
- goto out;
- rc = pkey_ep11key2pkey(key, keylen,
- protkey, protkeylen, protkeytype);
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported non-CCA token version %d\n",
- __func__, hdr->version);
- }
+ kgp.protkey.len = sizeof(kgp.protkey.protkey);
+ 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));
-out:
return rc;
}
-/*
- * Transform a CCA internal key token into a protected key
- */
-static int pkey_ccainttok2pkey(const u8 *key, u32 keylen,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp)
{
- struct keytoken_header *hdr = (struct keytoken_header *)key;
+ struct pkey_verifyprotk kvp;
+ struct protaeskeytoken *t;
+ u32 keytype;
+ u8 *tmpbuf;
+ int rc;
- switch (hdr->version) {
- case TOKVER_CCA_AES:
- if (keylen != sizeof(struct secaeskeytoken))
- return -EINVAL;
- break;
- case TOKVER_CCA_VLSC:
- if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
- return -EINVAL;
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported CCA internal token version %d\n",
- __func__, hdr->version);
+ if (copy_from_user(&kvp, uvp, sizeof(kvp)))
+ return -EFAULT;
+
+ 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;
}
- return pkey_skey2pkey(key, protkey, protkeylen, protkeytype);
+ /* 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;
}
-/*
- * Transform a key blob (of any type) into a protected key
- */
-int pkey_keyblob2pkey(const u8 *key, u32 keylen,
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+static int pkey_ioctl_kblob2protk(struct pkey_kblob2pkey __user *utp)
{
- struct keytoken_header *hdr = (struct keytoken_header *)key;
+ struct pkey_kblob2pkey ktp;
+ u8 *kkey;
int rc;
- if (keylen < sizeof(struct keytoken_header)) {
- PKEY_DBF_ERR("%s invalid keylen %d\n", __func__, keylen);
- return -EINVAL;
- }
+ if (copy_from_user(&ktp, utp, sizeof(ktp)))
+ return -EFAULT;
+ kkey = _copy_key_from_user(ktp.key, ktp.keylen);
+ if (IS_ERR(kkey))
+ return PTR_ERR(kkey);
+ ktp.protkey.len = sizeof(ktp.protkey.protkey);
+ rc = key2protkey(NULL, 0, kkey, ktp.keylen,
+ ktp.protkey.protkey, &ktp.protkey.len,
+ &ktp.protkey.type);
+ pr_debug("key2protkey()=%d\n", rc);
+ kfree_sensitive(kkey);
+ if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))
+ rc = -EFAULT;
+ memzero_explicit(&ktp, sizeof(ktp));
- switch (hdr->type) {
- case TOKTYPE_NON_CCA:
- rc = pkey_nonccatok2pkey(key, keylen,
- protkey, protkeylen, protkeytype);
- break;
- case TOKTYPE_CCA_INTERNAL:
- rc = pkey_ccainttok2pkey(key, keylen,
- protkey, protkeylen, protkeytype);
- break;
- default:
- PKEY_DBF_ERR("%s unknown/unsupported blob type %d\n",
- __func__, hdr->type);
- return -EINVAL;
- }
-
- pr_debug("%s rc=%d\n", __func__, rc);
return rc;
}
-EXPORT_SYMBOL(pkey_keyblob2pkey);
-static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
- enum pkey_key_type ktype, enum pkey_key_size ksize,
- u32 kflags, u8 *keybuf, size_t *keybufsize)
+static int pkey_ioctl_genseck2(struct pkey_genseck2 __user *ugs)
{
- int i, card, dom, rc;
-
- /* check for at least one apqn given */
- if (!apqns || !nr_apqns)
- return -EINVAL;
+ u32 klen = KEYBLOBBUFSIZE;
+ struct pkey_genseck2 kgs;
+ struct pkey_apqn *apqns;
+ u8 *kkey;
+ int rc;
+ u32 u;
- /* check key type and size */
- switch (ktype) {
- case PKEY_TYPE_CCA_DATA:
- case PKEY_TYPE_CCA_CIPHER:
- if (*keybufsize < SECKEYBLOBSIZE)
- return -EINVAL;
- break;
- case PKEY_TYPE_EP11:
- if (*keybufsize < MINEP11AESKEYBLOBSIZE)
- return -EINVAL;
- break;
- case PKEY_TYPE_EP11_AES:
- if (*keybufsize < (sizeof(struct ep11kblob_header) +
- MINEP11AESKEYBLOBSIZE))
- return -EINVAL;
- break;
- default:
+ 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;
}
- switch (ksize) {
- case PKEY_SIZE_AES_128:
- case PKEY_SIZE_AES_192:
- case PKEY_SIZE_AES_256:
- break;
- default:
- return -EINVAL;
+ apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries);
+ if (IS_ERR(apqns))
+ return PTR_ERR(apqns);
+ kkey = kzalloc(klen, GFP_KERNEL);
+ if (!kkey) {
+ kfree(apqns);
+ return -ENOMEM;
}
-
- /* simple try all apqns from the list */
- for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
- card = apqns[i].card;
- dom = apqns[i].domain;
- if (ktype == PKEY_TYPE_EP11 ||
- ktype == PKEY_TYPE_EP11_AES) {
- rc = ep11_genaeskey(card, dom, ksize, kflags,
- keybuf, keybufsize, ktype);
- } else if (ktype == PKEY_TYPE_CCA_DATA) {
- rc = cca_genseckey(card, dom, ksize, keybuf);
- *keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
- } else {
- /* TOKVER_CCA_VLSC */
- rc = cca_gencipherkey(card, dom, ksize, kflags,
- keybuf, keybufsize);
+ 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);
+ return rc;
+ }
+ if (kgs.key) {
+ if (kgs.keylen < klen) {
+ kfree_sensitive(kkey);
+ return -EINVAL;
+ }
+ if (copy_to_user(kgs.key, kkey, klen)) {
+ kfree_sensitive(kkey);
+ return -EFAULT;
}
- if (rc == 0)
- break;
}
+ kgs.keylen = klen;
+ if (copy_to_user(ugs, &kgs, sizeof(kgs)))
+ rc = -EFAULT;
+ kfree_sensitive(kkey);
return rc;
}
-static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
- enum pkey_key_type ktype, enum pkey_key_size ksize,
- u32 kflags, const u8 *clrkey,
- u8 *keybuf, size_t *keybufsize)
+static int pkey_ioctl_clr2seck2(struct pkey_clr2seck2 __user *ucs)
{
- int i, card, dom, rc;
-
- /* check for at least one apqn given */
- if (!apqns || !nr_apqns)
- return -EINVAL;
-
- /* check key type and size */
- switch (ktype) {
- case PKEY_TYPE_CCA_DATA:
- case PKEY_TYPE_CCA_CIPHER:
- if (*keybufsize < SECKEYBLOBSIZE)
- return -EINVAL;
- break;
- case PKEY_TYPE_EP11:
- if (*keybufsize < MINEP11AESKEYBLOBSIZE)
- return -EINVAL;
- break;
- case PKEY_TYPE_EP11_AES:
- if (*keybufsize < (sizeof(struct ep11kblob_header) +
- MINEP11AESKEYBLOBSIZE))
- return -EINVAL;
- break;
- default:
+ u32 klen = KEYBLOBBUFSIZE;
+ struct pkey_clr2seck2 kcs;
+ 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;
}
- switch (ksize) {
- case PKEY_SIZE_AES_128:
- case PKEY_SIZE_AES_192:
- case PKEY_SIZE_AES_256:
- break;
- default:
- return -EINVAL;
+ apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries);
+ if (IS_ERR(apqns)) {
+ memzero_explicit(&kcs, sizeof(kcs));
+ return PTR_ERR(apqns);
}
-
- zcrypt_wait_api_operational();
-
- /* simple try all apqns from the list */
- for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
- card = apqns[i].card;
- dom = apqns[i].domain;
- if (ktype == PKEY_TYPE_EP11 ||
- ktype == PKEY_TYPE_EP11_AES) {
- rc = ep11_clr2keyblob(card, dom, ksize, kflags,
- clrkey, keybuf, keybufsize,
- ktype);
- } else if (ktype == PKEY_TYPE_CCA_DATA) {
- rc = cca_clr2seckey(card, dom, ksize,
- clrkey, keybuf);
- *keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
- } else {
- /* TOKVER_CCA_VLSC */
- rc = cca_clr2cipherkey(card, dom, ksize, kflags,
- clrkey, keybuf, keybufsize);
+ kkey = kzalloc(klen, GFP_KERNEL);
+ if (!kkey) {
+ kfree(apqns);
+ memzero_explicit(&kcs, sizeof(kcs));
+ return -ENOMEM;
+ }
+ rc = pkey_handler_clr_to_key(apqns, kcs.apqn_entries,
+ u, kcs.type, kcs.size, kcs.keygenflags,
+ kcs.clrkey.clr