forked from Minki/linux
s390/pkey/zcrypt: Support EP11 AES secure keys
Extend the low level ep11 misc functions implementation by several functions to support EP11 key objects for paes and pkey: - EP11 AES secure key generation - EP11 AES secure key generation from given clear key value - EP11 AES secure key blob check - findcard function returns list of apqns based on given criterias - EP11 AES secure key derive to CPACF protected key Extend the pkey module to be able to generate and handle EP11 secure keys and also use them as base for deriving protected keys for CPACF usage. These ioctls are extended to support EP11 keys: PKEY_GENSECK2, PKEY_CLR2SECK2, PKEY_VERIFYKEY2, PKEY_APQNS4K, PKEY_APQNS4KT, PKEY_KBLOB2PROTK2. Additionally the 'clear key' token to protected key now uses an EP11 card if the other ways (via PCKMO, via CCA) fail. The PAES cipher implementation needed a new upper limit for the max key size, but is now also working with EP11 keys. Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
a17becc112
commit
55d0a513a0
@ -34,7 +34,7 @@
|
||||
* and padding is also possible, the limits need to be generous.
|
||||
*/
|
||||
#define PAES_MIN_KEYSIZE 16
|
||||
#define PAES_MAX_KEYSIZE 256
|
||||
#define PAES_MAX_KEYSIZE 320
|
||||
|
||||
static u8 *ctrblk;
|
||||
static DEFINE_MUTEX(ctrblk_lock);
|
||||
|
@ -25,10 +25,11 @@
|
||||
#define MAXPROTKEYSIZE 64 /* a protected key blob may be up to 64 bytes */
|
||||
#define MAXCLRKEYSIZE 32 /* a clear key value may be up to 32 bytes */
|
||||
#define MAXAESCIPHERKEYSIZE 136 /* our aes cipher keys have always 136 bytes */
|
||||
#define MINEP11AESKEYBLOBSIZE 256 /* min EP11 AES key blob size */
|
||||
#define MAXEP11AESKEYBLOBSIZE 320 /* max EP11 AES key blob size */
|
||||
|
||||
/* Minimum and maximum size of a key blob */
|
||||
/* Minimum size of a key blob */
|
||||
#define MINKEYBLOBSIZE SECKEYBLOBSIZE
|
||||
#define MAXKEYBLOBSIZE MAXAESCIPHERKEYSIZE
|
||||
|
||||
/* defines for the type field within the pkey_protkey struct */
|
||||
#define PKEY_KEYTYPE_AES_128 1
|
||||
@ -39,6 +40,7 @@
|
||||
enum pkey_key_type {
|
||||
PKEY_TYPE_CCA_DATA = (__u32) 1,
|
||||
PKEY_TYPE_CCA_CIPHER = (__u32) 2,
|
||||
PKEY_TYPE_EP11 = (__u32) 3,
|
||||
};
|
||||
|
||||
/* the newer ioctls use a pkey_key_size enum for key size information */
|
||||
@ -200,7 +202,7 @@ struct pkey_kblob2pkey {
|
||||
|
||||
/*
|
||||
* Generate secure key, version 2.
|
||||
* Generate either a CCA AES secure key or a CCA AES cipher key.
|
||||
* Generate CCA AES secure key, CCA AES cipher key or EP11 AES secure key.
|
||||
* There needs to be a list of apqns given with at least one entry in there.
|
||||
* All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain
|
||||
* is not supported. The implementation walks through the list of apqns and
|
||||
@ -210,10 +212,13 @@ struct pkey_kblob2pkey {
|
||||
* (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to
|
||||
* generate a list of apqns based on the key type to generate.
|
||||
* The keygenflags argument is passed to the low level generation functions
|
||||
* individual for the key type and has a key type specific meaning. Currently
|
||||
* only CCA AES cipher keys react to this parameter: Use one or more of the
|
||||
* PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher
|
||||
* key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
|
||||
* individual for the key type and has a key type specific meaning. When
|
||||
* generating CCA cipher keys you can use one or more of the PKEY_KEYGEN_*
|
||||
* flags to widen the export possibilities. By default a cipher key is
|
||||
* only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
|
||||
* The keygenflag argument for generating an EP11 AES key should either be 0
|
||||
* to use the defaults which are XCP_BLOB_ENCRYPT, XCP_BLOB_DECRYPT and
|
||||
* XCP_BLOB_PROTKEY_EXTRACTABLE or a valid combination of XCP_BLOB_* flags.
|
||||
*/
|
||||
struct pkey_genseck2 {
|
||||
struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets*/
|
||||
@ -229,8 +234,8 @@ struct pkey_genseck2 {
|
||||
|
||||
/*
|
||||
* Generate secure key from clear key value, version 2.
|
||||
* Construct a CCA AES secure key or CCA AES cipher key from a given clear key
|
||||
* value.
|
||||
* Construct an CCA AES secure key, CCA AES cipher key or EP11 AES secure
|
||||
* key from a given clear key value.
|
||||
* There needs to be a list of apqns given with at least one entry in there.
|
||||
* All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain
|
||||
* is not supported. The implementation walks through the list of apqns and
|
||||
@ -240,10 +245,13 @@ struct pkey_genseck2 {
|
||||
* (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to
|
||||
* generate a list of apqns based on the key type to generate.
|
||||
* The keygenflags argument is passed to the low level generation functions
|
||||
* individual for the key type and has a key type specific meaning. Currently
|
||||
* only CCA AES cipher keys react to this parameter: Use one or more of the
|
||||
* PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher
|
||||
* key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
|
||||
* individual for the key type and has a key type specific meaning. When
|
||||
* generating CCA cipher keys you can use one or more of the PKEY_KEYGEN_*
|
||||
* flags to widen the export possibilities. By default a cipher key is
|
||||
* only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC).
|
||||
* The keygenflag argument for generating an EP11 AES key should either be 0
|
||||
* to use the defaults which are XCP_BLOB_ENCRYPT, XCP_BLOB_DECRYPT and
|
||||
* XCP_BLOB_PROTKEY_EXTRACTABLE or a valid combination of XCP_BLOB_* flags.
|
||||
*/
|
||||
struct pkey_clr2seck2 {
|
||||
struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */
|
||||
@ -266,14 +274,19 @@ struct pkey_clr2seck2 {
|
||||
* with one apqn able to handle this key.
|
||||
* The function also checks for the master key verification patterns
|
||||
* of the key matching to the current or alternate mkvp of the apqn.
|
||||
* Currently CCA AES secure keys and CCA AES cipher keys are supported.
|
||||
* The flags field is updated with some additional info about the apqn mkvp
|
||||
* For CCA AES secure keys and CCA AES cipher keys this means to check
|
||||
* the key's mkvp against the current or old mkvp of the apqns. The flags
|
||||
* field is updated with some additional info about the apqn mkvp
|
||||
* match: If the current mkvp matches to the key's mkvp then the
|
||||
* PKEY_FLAGS_MATCH_CUR_MKVP bit is set, if the alternate mkvp matches to
|
||||
* the key's mkvp the PKEY_FLAGS_MATCH_ALT_MKVP is set. For CCA keys the
|
||||
* alternate mkvp is the old master key verification pattern.
|
||||
* CCA AES secure keys are also checked to have the CPACF export allowed
|
||||
* bit enabled (XPRTCPAC) in the kmf1 field.
|
||||
* EP11 keys are also supported and the wkvp of the key is checked against
|
||||
* the current wkvp of the apqns. There is no alternate for this type of
|
||||
* key and so on a match the flag PKEY_FLAGS_MATCH_CUR_MKVP always is set.
|
||||
* EP11 keys are also checked to have XCP_BLOB_PROTKEY_EXTRACTABLE set.
|
||||
* The ioctl returns 0 as long as the given or found apqn matches to
|
||||
* matches with the current or alternate mkvp to the key's mkvp. If the given
|
||||
* apqn does not match or there is no such apqn found, -1 with errno
|
||||
@ -313,16 +326,20 @@ struct pkey_kblob2pkey2 {
|
||||
/*
|
||||
* Build a list of APQNs based on a key blob given.
|
||||
* Is able to find out which type of secure key is given (CCA AES secure
|
||||
* key or CCA AES cipher key) and tries to find all matching crypto cards
|
||||
* based on the MKVP and maybe other criterias (like CCA AES cipher keys
|
||||
* need a CEX5C or higher). The list of APQNs is further filtered by the key's
|
||||
* mkvp which needs to match to either the current mkvp or the alternate mkvp
|
||||
* (which is the old mkvp on CCA adapters) of the apqns. The flags argument may
|
||||
* be used to limit the matching apqns. If the PKEY_FLAGS_MATCH_CUR_MKVP is
|
||||
* given, only the current mkvp of each apqn is compared. Likewise with the
|
||||
* PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it is assumed to
|
||||
* return apqns where either the current or the alternate mkvp
|
||||
* key, CCA AES cipher key or EP11 AES key) and tries to find all matching
|
||||
* crypto cards based on the MKVP and maybe other criterias (like CCA AES
|
||||
* cipher keys need a CEX5C or higher, EP11 keys with BLOB_PKEY_EXTRACTABLE
|
||||
* need a CEX7 and EP11 api version 4). The list of APQNs is further filtered
|
||||
* by the key's mkvp which needs to match to either the current mkvp (CCA and
|
||||
* EP11) or the alternate mkvp (old mkvp, CCA adapters only) of the apqns. The
|
||||
* flags argument may be used to limit the matching apqns. If the
|
||||
* PKEY_FLAGS_MATCH_CUR_MKVP is given, only the current mkvp of each apqn is
|
||||
* compared. Likewise with the PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it
|
||||
* is assumed to return apqns where either the current or the alternate mkvp
|
||||
* matches. At least one of the matching flags needs to be given.
|
||||
* The flags argument for EP11 keys has no further action and is currently
|
||||
* ignored (but needs to be given as PKEY_FLAGS_MATCH_CUR_MKVP) as there is only
|
||||
* the wkvp from the key to match against the apqn's wkvp.
|
||||
* The list of matching apqns is stored into the space given by the apqns
|
||||
* argument and the number of stored entries goes into apqn_entries. If the list
|
||||
* is empty (apqn_entries is 0) the apqn_entries field is updated to the number
|
||||
@ -356,6 +373,10 @@ struct pkey_apqns4key {
|
||||
* If both are given, it is assumed to return apqns where either the
|
||||
* current or the alternate mkvp matches. If no match flag is given
|
||||
* (flags is 0) the mkvp values are ignored for the match process.
|
||||
* For EP11 keys there is only the current wkvp. So if the apqns should also
|
||||
* match to a given wkvp, then the PKEY_FLAGS_MATCH_CUR_MKVP flag should be
|
||||
* set. The wkvp value is 32 bytes but only the leftmost 16 bytes are compared
|
||||
* against the leftmost 16 byte of the wkvp of the apqn.
|
||||
* The list of matching apqns is stored into the space given by the apqns
|
||||
* argument and the number of stored entries goes into apqn_entries. If the list
|
||||
* is empty (apqn_entries is 0) the apqn_entries field is updated to the number
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "zcrypt_api.h"
|
||||
#include "zcrypt_ccamisc.h"
|
||||
#include "zcrypt_ep11misc.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
@ -183,6 +184,72 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct EP11 key with given clear key value.
|
||||
*/
|
||||
static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
|
||||
u8 *keybuf, size_t *keybuflen)
|
||||
{
|
||||
int i, rc;
|
||||
u16 card, dom;
|
||||
u32 nr_apqns, *apqns = NULL;
|
||||
|
||||
/* build a list of apqns suitable for ep11 keys with cpacf support */
|
||||
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, EP11_API_V, 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);
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(apqns);
|
||||
if (rc)
|
||||
DEBUG_DBG("%s failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find card and transform EP11 secure key into protected key.
|
||||
*/
|
||||
static int pkey_ep11key2pkey(const u8 *key, struct pkey_protkey *pkey)
|
||||
{
|
||||
int i, rc;
|
||||
u16 card, dom;
|
||||
u32 nr_apqns, *apqns = NULL;
|
||||
struct ep11keyblob *kb = (struct ep11keyblob *) key;
|
||||
|
||||
/* build a list of apqns suitable for this key */
|
||||
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* go through the list of apqns and try to derive an pkey */
|
||||
for (rc = -ENODEV, i = 0; i < nr_apqns; i++) {
|
||||
card = apqns[i] >> 16;
|
||||
dom = apqns[i] & 0xFFFF;
|
||||
rc = ep11_key2protkey(card, dom, key, kb->head.len,
|
||||
pkey->protkey, &pkey->len, &pkey->type);
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(apqns);
|
||||
if (rc)
|
||||
DEBUG_DBG("%s failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify key and give back some info about the key.
|
||||
*/
|
||||
@ -317,6 +384,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
|
||||
struct pkey_protkey *protkey)
|
||||
{
|
||||
int rc = -EINVAL;
|
||||
u8 *tmpbuf = NULL;
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
|
||||
switch (hdr->version) {
|
||||
@ -336,7 +404,11 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
|
||||
case TOKVER_CLEAR_KEY: {
|
||||
struct clearaeskeytoken *t;
|
||||
struct pkey_clrkey ckey;
|
||||
struct pkey_seckey skey;
|
||||
union u_tmpbuf {
|
||||
u8 skey[SECKEYBLOBSIZE];
|
||||
u8 ep11key[MAXEP11AESKEYBLOBSIZE];
|
||||
};
|
||||
size_t tmpbuflen = sizeof(union u_tmpbuf);
|
||||
|
||||
if (keylen < sizeof(struct clearaeskeytoken))
|
||||
goto out;
|
||||
@ -349,22 +421,43 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
|
||||
memcpy(ckey.clrkey, t->clearkey, t->len);
|
||||
else
|
||||
goto out;
|
||||
/* alloc temp key buffer space */
|
||||
tmpbuf = kmalloc(tmpbuflen, GFP_ATOMIC);
|
||||
if (!tmpbuf) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
/* try direct way with the PCKMO instruction */
|
||||
rc = pkey_clr2protkey(t->keytype, &ckey, protkey);
|
||||
if (rc == 0)
|
||||
break;
|
||||
/* PCKMO failed, so try the CCA secure key way */
|
||||
rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype,
|
||||
ckey.clrkey, skey.seckey);
|
||||
ckey.clrkey, tmpbuf);
|
||||
if (rc == 0)
|
||||
rc = pkey_skey2pkey(skey.seckey, protkey);
|
||||
/* now we should really have an protected key */
|
||||
rc = pkey_skey2pkey(tmpbuf, protkey);
|
||||
if (rc == 0)
|
||||
break;
|
||||
/* if the CCA way also failed, let's try via EP11 */
|
||||
rc = pkey_clr2ep11key(ckey.clrkey, t->len,
|
||||
tmpbuf, &tmpbuflen);
|
||||
if (rc == 0)
|
||||
rc = pkey_ep11key2pkey(tmpbuf, protkey);
|
||||
/* now we should really have an protected key */
|
||||
DEBUG_ERR("%s unable to build protected key from clear",
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
case TOKVER_EP11_AES: {
|
||||
if (keylen < MINEP11AESKEYBLOBSIZE)
|
||||
goto out;
|
||||
/* check ep11 key for exportable as protected key */
|
||||
rc = ep11_check_aeskeyblob(debug_info, 3, key, 0, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = pkey_ep11key2pkey(key, protkey);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
|
||||
__func__, hdr->version);
|
||||
@ -372,6 +465,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(tmpbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -451,6 +545,10 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
if (*keybufsize < SECKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case PKEY_TYPE_EP11:
|
||||
if (*keybufsize < MINEP11AESKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -467,7 +565,10 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
|
||||
card = apqns[i].card;
|
||||
dom = apqns[i].domain;
|
||||
if (ktype == PKEY_TYPE_CCA_DATA) {
|
||||
if (ktype == PKEY_TYPE_EP11) {
|
||||
rc = ep11_genaeskey(card, dom, ksize, kflags,
|
||||
keybuf, keybufsize);
|
||||
} else if (ktype == PKEY_TYPE_CCA_DATA) {
|
||||
rc = cca_genseckey(card, dom, ksize, keybuf);
|
||||
*keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
|
||||
} else /* TOKVER_CCA_VLSC */
|
||||
@ -498,6 +599,10 @@ static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
if (*keybufsize < SECKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case PKEY_TYPE_EP11:
|
||||
if (*keybufsize < MINEP11AESKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -514,7 +619,10 @@ static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
|
||||
card = apqns[i].card;
|
||||
dom = apqns[i].domain;
|
||||
if (ktype == PKEY_TYPE_CCA_DATA) {
|
||||
if (ktype == PKEY_TYPE_EP11) {
|
||||
rc = ep11_clr2keyblob(card, dom, ksize, kflags,
|
||||
clrkey, keybuf, keybufsize);
|
||||
} else if (ktype == PKEY_TYPE_CCA_DATA) {
|
||||
rc = cca_clr2seckey(card, dom, ksize,
|
||||
clrkey, keybuf);
|
||||
*keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
|
||||
@ -537,11 +645,11 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
|
||||
u32 _nr_apqns, *_apqns = NULL;
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
|
||||
if (keylen < sizeof(struct keytoken_header) ||
|
||||
hdr->type != TOKTYPE_CCA_INTERNAL)
|
||||
if (keylen < sizeof(struct keytoken_header))
|
||||
return -EINVAL;
|
||||
|
||||
if (hdr->version == TOKVER_CCA_AES) {
|
||||
if (hdr->type == TOKTYPE_CCA_INTERNAL
|
||||
&& hdr->version == TOKVER_CCA_AES) {
|
||||
struct secaeskeytoken *t = (struct secaeskeytoken *)key;
|
||||
|
||||
rc = cca_check_secaeskeytoken(debug_info, 3, key, 0);
|
||||
@ -569,7 +677,8 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
|
||||
*cardnr = ((struct pkey_apqn *)_apqns)->card;
|
||||
*domain = ((struct pkey_apqn *)_apqns)->domain;
|
||||
|
||||
} else if (hdr->version == TOKVER_CCA_VLSC) {
|
||||
} else if (hdr->type == TOKTYPE_CCA_INTERNAL
|
||||
&& hdr->version == TOKVER_CCA_VLSC) {
|
||||
struct cipherkeytoken *t = (struct cipherkeytoken *)key;
|
||||
|
||||
rc = cca_check_secaescipherkey(debug_info, 3, key, 0, 1);
|
||||
@ -604,6 +713,29 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
|
||||
*cardnr = ((struct pkey_apqn *)_apqns)->card;
|
||||
*domain = ((struct pkey_apqn *)_apqns)->domain;
|
||||
|
||||
} else if (hdr->type == TOKTYPE_NON_CCA
|
||||
&& hdr->version == TOKVER_EP11_AES) {
|
||||
struct ep11keyblob *kb = (struct ep11keyblob *)key;
|
||||
|
||||
rc = ep11_check_aeskeyblob(debug_info, 3, key, 0, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
if (ktype)
|
||||
*ktype = PKEY_TYPE_EP11;
|
||||
if (ksize)
|
||||
*ksize = kb->head.keybitlen;
|
||||
|
||||
rc = ep11_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
|
||||
ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (flags)
|
||||
*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
|
||||
|
||||
*cardnr = ((struct pkey_apqn *)_apqns)->card;
|
||||
*domain = ((struct pkey_apqn *)_apqns)->domain;
|
||||
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
|
||||
@ -626,30 +758,32 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
if (keylen < sizeof(struct keytoken_header))
|
||||
return -EINVAL;
|
||||
|
||||
switch (hdr->type) {
|
||||
case TOKTYPE_NON_CCA:
|
||||
return pkey_nonccatok2pkey(key, keylen, pkey);
|
||||
case TOKTYPE_CCA_INTERNAL:
|
||||
switch (hdr->version) {
|
||||
case TOKVER_CCA_AES:
|
||||
if (hdr->type == TOKTYPE_CCA_INTERNAL) {
|
||||
if (hdr->version == TOKVER_CCA_AES) {
|
||||
if (keylen != sizeof(struct secaeskeytoken))
|
||||
return -EINVAL;
|
||||
if (cca_check_secaeskeytoken(debug_info, 3, key, 0))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case TOKVER_CCA_VLSC:
|
||||
} else if (hdr->version == TOKVER_CCA_VLSC) {
|
||||
if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
|
||||
return -EINVAL;
|
||||
if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
DEBUG_ERR("%s unknown CCA internal token version %d\n",
|
||||
__func__, hdr->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
} else if (hdr->type == TOKTYPE_NON_CCA) {
|
||||
if (hdr->version == TOKVER_EP11_AES) {
|
||||
if (keylen < sizeof(struct ep11keyblob))
|
||||
return -EINVAL;
|
||||
if (ep11_check_aeskeyblob(debug_info, 3, key, 0, 1))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return pkey_nonccatok2pkey(key, keylen, pkey);
|
||||
}
|
||||
} else {
|
||||
DEBUG_ERR("%s unknown/unsupported blob type %d\n",
|
||||
__func__, hdr->type);
|
||||
return -EINVAL;
|
||||
@ -659,12 +793,21 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
|
||||
card = apqns[i].card;
|
||||
dom = apqns[i].domain;
|
||||
if (hdr->version == TOKVER_CCA_AES)
|
||||
if (hdr->type == TOKTYPE_CCA_INTERNAL
|
||||
&& hdr->version == TOKVER_CCA_AES)
|
||||
rc = cca_sec2protkey(card, dom, key, pkey->protkey,
|
||||
&pkey->len, &pkey->type);
|
||||
else /* TOKVER_CCA_VLSC */
|
||||
else if (hdr->type == TOKTYPE_CCA_INTERNAL
|
||||
&& hdr->version == TOKVER_CCA_VLSC)
|
||||
rc = cca_cipher2protkey(card, dom, key, pkey->protkey,
|
||||
&pkey->len, &pkey->type);
|
||||
else { /* EP11 AES secure key blob */
|
||||
struct ep11keyblob *kb = (struct ep11keyblob *) key;
|
||||
|
||||
rc = ep11_key2protkey(card, dom, key, kb->head.len,
|
||||
pkey->protkey, &pkey->len,
|
||||
&pkey->type);
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
@ -679,12 +822,24 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
|
||||
u32 _nr_apqns, *_apqns = NULL;
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
|
||||
if (keylen < sizeof(struct keytoken_header) ||
|
||||
hdr->type != TOKTYPE_CCA_INTERNAL ||
|
||||
flags == 0)
|
||||
if (keylen < sizeof(struct keytoken_header) || flags == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (hdr->version == TOKVER_CCA_AES || hdr->version == TOKVER_CCA_VLSC) {
|
||||
if (hdr->type == TOKTYPE_NON_CCA && hdr->version == TOKVER_EP11_AES) {
|
||||
int minhwtype = 0, api = 0;
|
||||
struct ep11keyblob *kb = (struct ep11keyblob *) key;
|
||||
|
||||
if (flags != PKEY_FLAGS_MATCH_CUR_MKVP)
|
||||
return -EINVAL;
|
||||
if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) {
|
||||
minhwtype = ZCRYPT_CEX7;
|
||||
api = EP11_API_V;
|
||||
}
|
||||
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, api, kb->wkvp);
|
||||
if (rc)
|
||||
goto out;
|
||||
} else if (hdr->type == TOKTYPE_CCA_INTERNAL) {
|
||||
int minhwtype = ZCRYPT_CEX3C;
|
||||
u64 cur_mkvp = 0, old_mkvp = 0;
|
||||
|
||||
@ -695,7 +850,7 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
|
||||
cur_mkvp = t->mkvp;
|
||||
if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
|
||||
old_mkvp = t->mkvp;
|
||||
} else {
|
||||
} else if (hdr->version == TOKVER_CCA_VLSC) {
|
||||
struct cipherkeytoken *t = (struct cipherkeytoken *)key;
|
||||
|
||||
minhwtype = ZCRYPT_CEX6;
|
||||
@ -703,19 +858,24 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
|
||||
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, cur_mkvp, old_mkvp, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
if (apqns) {
|
||||
if (*nr_apqns < _nr_apqns)
|
||||
rc = -ENOSPC;
|
||||
else
|
||||
memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
|
||||
}
|
||||
*nr_apqns = _nr_apqns;
|
||||
} else
|
||||
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);
|
||||
@ -743,14 +903,26 @@ static int pkey_apqns4keytype(enum pkey_key_type ktype,
|
||||
minhwtype, cur_mkvp, old_mkvp, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
if (apqns) {
|
||||
if (*nr_apqns < _nr_apqns)
|
||||
rc = -ENOSPC;
|
||||
else
|
||||
memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
|
||||
}
|
||||
*nr_apqns = _nr_apqns;
|
||||
} else if (ktype == PKEY_TYPE_EP11) {
|
||||
u8 *wkvp = NULL;
|
||||
|
||||
if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
|
||||
wkvp = cur_mkvp;
|
||||
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, EP11_API_V, wkvp);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
} else
|
||||
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);
|
||||
@ -1405,8 +1577,9 @@ static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits,
|
||||
bool is_xts, char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
size_t keysize;
|
||||
int rc;
|
||||
int i, rc, card, dom;
|
||||
u32 nr_apqns, *apqns = NULL;
|
||||
size_t keysize = CCACIPHERTOKENSIZE;
|
||||
|
||||
if (off != 0 || count < CCACIPHERTOKENSIZE)
|
||||
return -EINVAL;
|
||||
@ -1414,22 +1587,31 @@ static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits,
|
||||
if (count < 2 * CCACIPHERTOKENSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
keysize = CCACIPHERTOKENSIZE;
|
||||
rc = cca_gencipherkey(-1, -1, keybits, 0, buf, &keysize);
|
||||
/* build a list of apqns able to generate an cipher key */
|
||||
rc = cca_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX6, 0, 0, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
memset(buf + keysize, 0, CCACIPHERTOKENSIZE - keysize);
|
||||
|
||||
memset(buf, 0, is_xts ? 2 * keysize : keysize);
|
||||
|
||||
/* simple try all apqns from the list */
|
||||
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
|
||||
card = apqns[i] >> 16;
|
||||
dom = apqns[i] & 0xFFFF;
|
||||
rc = cca_gencipherkey(card, dom, keybits, 0, buf, &keysize);
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (is_xts) {
|
||||
keysize = CCACIPHERTOKENSIZE;
|
||||
rc = cca_gencipherkey(-1, -1, keybits, 0,
|
||||
buf + CCACIPHERTOKENSIZE, &keysize);
|
||||
if (rc)
|
||||
return rc;
|
||||
memset(buf + CCACIPHERTOKENSIZE + keysize, 0,
|
||||
CCACIPHERTOKENSIZE - keysize);
|
||||
|
||||
return 2 * CCACIPHERTOKENSIZE;
|
||||
buf += CCACIPHERTOKENSIZE;
|
||||
rc = cca_gencipherkey(card, dom, keybits, 0, buf, &keysize);
|
||||
if (rc == 0)
|
||||
return 2 * CCACIPHERTOKENSIZE;
|
||||
}
|
||||
|
||||
return CCACIPHERTOKENSIZE;
|
||||
@ -1505,10 +1687,134 @@ static struct attribute_group ccacipher_attr_group = {
|
||||
.bin_attrs = ccacipher_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Sysfs attribute read function for all ep11 aes key binary attributes.
|
||||
* The implementation can not deal with partial reads, because a new random
|
||||
* secure key blob is generated with each read. In case of partial reads
|
||||
* (i.e. off != 0 or count < key blob size) -EINVAL is returned.
|
||||
* This function and the sysfs attributes using it provide EP11 key blobs
|
||||
* padded to the upper limit of MAXEP11AESKEYBLOBSIZE which is currently
|
||||
* 320 bytes.
|
||||
*/
|
||||
static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
|
||||
bool is_xts, char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
int i, rc, card, dom;
|
||||
u32 nr_apqns, *apqns = NULL;
|
||||
size_t keysize = MAXEP11AESKEYBLOBSIZE;
|
||||
|
||||
if (off != 0 || count < MAXEP11AESKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
if (is_xts)
|
||||
if (count < 2 * MAXEP11AESKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/* build a list of apqns able to generate an cipher key */
|
||||
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, EP11_API_V, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
memset(buf, 0, is_xts ? 2 * keysize : keysize);
|
||||
|
||||
/* simple try all apqns from the list */
|
||||
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
|
||||
card = apqns[i] >> 16;
|
||||
dom = apqns[i] & 0xFFFF;
|
||||
rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize);
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (is_xts) {
|
||||
keysize = MAXEP11AESKEYBLOBSIZE;
|
||||
buf += MAXEP11AESKEYBLOBSIZE;
|
||||
rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize);
|
||||
if (rc == 0)
|
||||
return 2 * MAXEP11AESKEYBLOBSIZE;
|
||||
}
|
||||
|
||||
return MAXEP11AESKEYBLOBSIZE;
|
||||
}
|
||||
|
||||
static ssize_t ep11_aes_128_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ep11_aes_attr_read(PKEY_SIZE_AES_128, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ep11_aes_192_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ep11_aes_attr_read(PKEY_SIZE_AES_192, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ep11_aes_256_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ep11_aes_attr_read(PKEY_SIZE_AES_256, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ep11_aes_128_xts_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ep11_aes_attr_read(PKEY_SIZE_AES_128, true, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ep11_aes_256_xts_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ep11_aes_attr_read(PKEY_SIZE_AES_256, true, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static BIN_ATTR_RO(ep11_aes_128, MAXEP11AESKEYBLOBSIZE);
|
||||
static BIN_ATTR_RO(ep11_aes_192, MAXEP11AESKEYBLOBSIZE);
|
||||
static BIN_ATTR_RO(ep11_aes_256, MAXEP11AESKEYBLOBSIZE);
|
||||
static BIN_ATTR_RO(ep11_aes_128_xts, 2 * MAXEP11AESKEYBLOBSIZE);
|
||||
static BIN_ATTR_RO(ep11_aes_256_xts, 2 * MAXEP11AESKEYBLOBSIZE);
|
||||
|
||||
static struct bin_attribute *ep11_attrs[] = {
|
||||
&bin_attr_ep11_aes_128,
|
||||
&bin_attr_ep11_aes_192,
|
||||
&bin_attr_ep11_aes_256,
|
||||
&bin_attr_ep11_aes_128_xts,
|
||||
&bin_attr_ep11_aes_256_xts,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group ep11_attr_group = {
|
||||
.name = "ep11",
|
||||
.bin_attrs = ep11_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *pkey_attr_groups[] = {
|
||||
&protkey_attr_group,
|
||||
&ccadata_attr_group,
|
||||
&ccacipher_attr_group,
|
||||
&ep11_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,46 @@
|
||||
#include <asm/zcrypt.h>
|
||||
#include <asm/pkey.h>
|
||||
|
||||
#define TOKVER_EP11_AES 0x03 /* EP11 AES key blob */
|
||||
|
||||
#define EP11_API_V 4 /* highest known and supported EP11 API version */
|
||||
|
||||
#define EP11_STRUCT_MAGIC 0x1234
|
||||
#define EP11_BLOB_PKEY_EXTRACTABLE 0x200000
|
||||
|
||||
/* inside view of an EP11 secure key blob */
|
||||
struct ep11keyblob {
|
||||
union {
|
||||
u8 session[32];
|
||||
struct {
|
||||
u8 type; /* 0x00 (TOKTYPE_NON_CCA) */
|
||||
u8 res0; /* unused */
|
||||
u16 len; /* total length in bytes of this blob */
|
||||
u8 version; /* 0x06 (TOKVER_EP11_AES) */
|
||||
u8 res1; /* unused */
|
||||
u16 keybitlen; /* clear key bit len, 0 for unknown */
|
||||
} head;
|
||||
};
|
||||
u8 wkvp[16]; /* wrapping key verification pattern */
|
||||
u64 attr; /* boolean key attributes */
|
||||
u64 mode; /* mode bits */
|
||||
u16 version; /* 0x1234, EP11_STRUCT_MAGIC */
|
||||
u8 iv[14];
|
||||
u8 encrypted_key_data[144];
|
||||
u8 mac[32];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Simple check if the key blob is a valid EP11 secure AES key.
|
||||
* If keybitsize is given, the bitsize of the key is also checked.
|
||||
* If checkcpacfexport is enabled, the key is also checked for the
|
||||
* attributes needed to export this key for CPACF use.
|
||||
* Returns 0 on success or errno value on failure.
|
||||
*/
|
||||
int ep11_check_aeskeyblob(debug_info_t *dbg, int dbflvl,
|
||||
const u8 *key, int keybitsize,
|
||||
int checkcpacfexport);
|
||||
|
||||
/* EP11 card info struct */
|
||||
struct ep11_card_info {
|
||||
u32 API_ord_nr; /* API ordinal number */
|
||||
@ -39,6 +79,46 @@ int ep11_get_card_info(u16 card, struct ep11_card_info *info, int verify);
|
||||
*/
|
||||
int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info);
|
||||
|
||||
/*
|
||||
* Generate (random) EP11 AES secure key.
|
||||
*/
|
||||
int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, size_t *keybufsize);
|
||||
|
||||
/*
|
||||
* Generate EP11 AES secure key with given clear key value.
|
||||
*/
|
||||
int ep11_clr2keyblob(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
const u8 *clrkey, u8 *keybuf, size_t *keybufsize);
|
||||
|
||||
/*
|
||||
* Derive proteced key from EP11 AES secure key blob.
|
||||
*/
|
||||
int ep11_key2protkey(u16 cardnr, u16 domain, const u8 *key, size_t keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
|
||||
/*
|
||||
* Build a list of ep11 apqns meeting the following constrains:
|
||||
* - apqn is online and is in fact an EP11 apqn
|
||||
* - if cardnr is not FFFF only apqns with this cardnr
|
||||
* - if domain is not FFFF only apqns with this domainnr
|
||||
* - if minhwtype > 0 only apqns with hwtype >= minhwtype
|
||||
* - if minapi > 0 only apqns with API_ord_nr >= minapi
|
||||
* - if wkvp != NULL only apqns where the wkvp (EP11_WKVPLEN bytes) matches
|
||||
* to the first EP11_WKVPLEN bytes of the wkvp of the current wrapping
|
||||
* key for this domain. When a wkvp is given there will aways be a re-fetch
|
||||
* of the domain info for the potential apqn - so this triggers an request
|
||||
* reply to each apqn eligible.
|
||||
* The array of apqn entries is allocated with kmalloc and returned in *apqns;
|
||||
* the number of apqns stored into the list is returned in *nr_apqns. One apqn
|
||||
* entry is simple a 32 bit value with 16 bit cardnr and 16 bit domain nr and
|
||||
* may be casted to struct pkey_apqn. The return value is either 0 for success
|
||||
* or a negative errno value. If no apqn meeting the criterias is found,
|
||||
* -ENODEV is returned.
|
||||
*/
|
||||
int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int minapi, const u8 *wkvp);
|
||||
|
||||
void zcrypt_ep11misc_exit(void);
|
||||
|
||||
#endif /* _ZCRYPT_EP11MISC_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user