Commit fa6999e3 authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Vasily Gorbik

s390/pkey: support CCA and EP11 secure ECC private keys

This patch extends the pkey kernel module to support CCA
and EP11 secure ECC (private) keys as source for deriving
ECC protected (private) keys.

There is yet another new ioctl to support this: PKEY_KBLOB2PROTK3
can handle all the old keys plus CCA and EP11 secure ECC keys.
For details see ioctl description in pkey.h.

The CPACF unit currently only supports a subset of 5
different ECC curves (P-256, P-384, P-521, ED25519, ED448) and
so only keys of this curve type can be transformed into
protected keys. However, the pkey and the cca/ep11 low level
functions do not check this but simple pass-through the key
blob to the firmware onto the crypto cards. So most likely
the failure will be a response carrying an error code
resulting in user space errno value EIO instead of EINVAL.

Deriving a protected key from an EP11 ECC secure key
requires a CEX7 in EP11 mode. Deriving a protected key from
an CCA ECC secure key requires a CEX7 in CCA mode.

Together with this new ioctl the ioctls for querying lists
of apqns (PKEY_APQNS4K and PKEY_APQNS4KT) have been extended
to support EP11 and CCA ECC secure key type and key blobs.

Together with this ioctl there comes a new struct ep11kblob_header
which is to be prepended onto the EP11 key blob. See details
in pkey.h for the fields in there. The older EP11 AES key blob
with some info stored in the (unused) session field is also
supported with this new ioctl.
Signed-off-by: default avatarHarald Freudenberger <freude@linux.ibm.com>
Reviewed-by: default avatarIngo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 32ca04bb
......@@ -35,12 +35,16 @@
#define PKEY_KEYTYPE_AES_128 1
#define PKEY_KEYTYPE_AES_192 2
#define PKEY_KEYTYPE_AES_256 3
#define PKEY_KEYTYPE_ECC 4
/* the newer ioctls use a pkey_key_type enum for type information */
enum pkey_key_type {
PKEY_TYPE_CCA_DATA = (__u32) 1,
PKEY_TYPE_CCA_CIPHER = (__u32) 2,
PKEY_TYPE_EP11 = (__u32) 3,
PKEY_TYPE_CCA_ECC = (__u32) 0x1f,
PKEY_TYPE_EP11_AES = (__u32) 6,
PKEY_TYPE_EP11_ECC = (__u32) 7,
};
/* the newer ioctls use a pkey_key_size enum for key size information */
......@@ -88,6 +92,20 @@ struct pkey_clrkey {
__u8 clrkey[MAXCLRKEYSIZE]; /* 16, 24, or 32 byte clear key value */
};
/*
* EP11 key blobs of type PKEY_TYPE_EP11_AES and PKEY_TYPE_EP11_ECC
* are ep11 blobs prepended by this header:
*/
struct ep11kblob_header {
__u8 type; /* always 0x00 */
__u8 hver; /* header version, currently needs to be 0x00 */
__u16 len; /* total length in bytes (including this header) */
__u8 version; /* PKEY_TYPE_EP11_AES or PKEY_TYPE_EP11_ECC */
__u8 res0; /* unused */
__u16 bitlen; /* clear key bit len, 0 for unknown */
__u8 res1[8]; /* unused */
} __packed;
/*
* Generate CCA AES secure key.
*/
......@@ -304,7 +322,7 @@ struct pkey_verifykey2 {
#define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2)
/*
* Transform a key blob (of any type) into a protected key, version 2.
* Transform a key blob into a protected key, version 2.
* 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
......@@ -313,6 +331,8 @@ struct pkey_verifykey2 {
* list is tried until success (return 0) or the end of the list is reached
* (return -1 with errno ENODEV). You may use the PKEY_APQNS4K ioctl to
* generate a list of apqns based on the key.
* Deriving ECC protected keys from ECC secure keys is not supported with
* this ioctl, use PKEY_KBLOB2PROTK3 for this purpose.
*/
struct pkey_kblob2pkey2 {
__u8 __user *key; /* in: pointer to key blob */
......@@ -326,17 +346,17 @@ 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, 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.
* key, CCA AES cipher key, CCA ECC private key, EP11 AES key, EP11 ECC private
* 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.
......@@ -365,9 +385,10 @@ struct pkey_apqns4key {
* restrict the list by given master key verification patterns.
* For different key types there may be different ways to match the
* master key verification patterns. For CCA keys (CCA data key and CCA
* cipher key) the first 8 bytes of cur_mkvp refer to the current mkvp value
* of the apqn and the first 8 bytes of the alt_mkvp refer to the old mkvp.
* The flags argument controls if the apqns current and/or alternate mkvp
* cipher key) the first 8 bytes of cur_mkvp refer to the current AES mkvp value
* of the apqn and the first 8 bytes of the alt_mkvp refer to the old AES mkvp.
* For CCA ECC keys it is similar but the match is against the APKA current/old
* mkvp. The flags argument controls if the apqns current and/or alternate mkvp
* should match. 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
......@@ -397,4 +418,30 @@ struct pkey_apqns4keytype {
};
#define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype)
/*
* Transform a key blob into a protected key, version 3.
* The difference to version 2 of this ioctl is that the protected key
* buffer is now explicitly and not within a struct pkey_protkey any more.
* So this ioctl is also able to handle EP11 and CCA ECC secure keys and
* provide ECC protected keys.
* 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
* tries to send the request to each apqn without any further checking (like
* card type or online state). If the apqn fails, simple the next one in the
* list is tried until success (return 0) or the end of the list is reached
* (return -1 with errno ENODEV). You may use the PKEY_APQNS4K ioctl to
* generate a list of apqns based on the key.
*/
struct pkey_kblob2pkey3 {
__u8 __user *key; /* in: pointer to key blob */
__u32 keylen; /* in: key blob size */
struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */
__u32 apqn_entries; /* in: # of apqn target list entries */
__u32 pkeytype; /* out: prot key type (enum pkey_key_type) */
__u32 pkeylen; /* in/out: size of pkey buffer/actual len of pkey */
__u8 __user *pkey; /* in: pkey blob buffer space ptr */
};
#define PKEY_KBLOB2PROTK3 _IOWR(PKEY_IOCTL_MAGIC, 0x1D, struct pkey_kblob2pkey3)
#endif /* _UAPI_PKEY_H */
This diff is collapsed.
......@@ -172,6 +172,49 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
}
EXPORT_SYMBOL(cca_check_secaescipherkey);
/*
* Simple check if the token is a valid CCA secure ECC private
* key token. Returns 0 on success or errno value on failure.
*/
int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
const u8 *token, size_t keysize,
int checkcpacfexport)
{
struct eccprivkeytoken *t = (struct eccprivkeytoken *) token;
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
if (t->type != TOKTYPE_CCA_INTERNAL_PKA) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
__func__, (int) t->type, TOKTYPE_CCA_INTERNAL_PKA);
return -EINVAL;
}
if (t->len > keysize) {
if (dbg)
DBF("%s token check failed, len %d > keysize %zu\n",
__func__, (int) t->len, keysize);
return -EINVAL;
}
if (t->secid != 0x20) {
if (dbg)
DBF("%s token check failed, secid 0x%02x != 0x20\n",
__func__, (int) t->secid);
return -EINVAL;
}
if (checkcpacfexport && !(t->kutc & 0x01)) {
if (dbg)
DBF("%s token check failed, XPRTCPAC bit is 0\n",
__func__);
return -EINVAL;
}
#undef DBF
return 0;
}
EXPORT_SYMBOL(cca_check_sececckeytoken);
/*
* Allocate consecutive memory for request CPRB, request param
* block, reply CPRB and reply param block and fill in values
......@@ -1297,6 +1340,156 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
}
EXPORT_SYMBOL(cca_cipher2protkey);
/*
* Derive protected key from CCA ECC secure private key.
*/
int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
int rc;
u8 *mem, *ptr;
struct CPRBX *preqcblk, *prepcblk;
struct ica_xcRB xcrb;
struct aureqparm {
u8 subfunc_code[2];
u16 rule_array_len;
u8 rule_array[8];
struct {
u16 len;
u16 tk_blob_len;
u16 tk_blob_tag;
u8 tk_blob[66];
} vud;
struct {
u16 len;
u16 cca_key_token_len;
u16 cca_key_token_flags;
u8 cca_key_token[0];
} kb;
} __packed * preqparm;
struct aurepparm {
u8 subfunc_code[2];
u16 rule_array_len;
struct {
u16 len;
u16 sublen;
u16 tag;
struct cpacfkeyblock {
u8 version; /* version of this struct */
u8 flags[2];
u8 algo;
u8 form;
u8 pad1[3];
u16 keylen;
u8 key[0]; /* the key (keylen bytes) */
u16 keyattrlen;
u8 keyattr[32];
u8 pad2[1];
u8 vptype;
u8 vp[32]; /* verification pattern */
} ckb;
} vud;
struct {
u16 len;
} kb;
} __packed * prepparm;
int keylen = ((struct eccprivkeytoken *)key)->len;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
if (rc)
return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* fill request cprb param block with AU request */
preqparm = (struct aureqparm __force *) preqcblk->req_parmb;
memcpy(preqparm->subfunc_code, "AU", 2);
preqparm->rule_array_len =
sizeof(preqparm->rule_array_len)
+ sizeof(preqparm->rule_array);
memcpy(preqparm->rule_array, "EXPT-SK ", 8);
/* vud, tk blob */
preqparm->vud.len = sizeof(preqparm->vud);
preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob)
+ 2 * sizeof(uint16_t);
preqparm->vud.tk_blob_tag = 0x00C2;
/* kb, cca token */
preqparm->kb.len = keylen + 3 * sizeof(uint16_t);
preqparm->kb.cca_key_token_len = keylen + 2 * sizeof(uint16_t);
memcpy(preqparm->kb.cca_key_token, key, keylen);
/* now fill length of param block into cprb */
preqcblk->req_parml = sizeof(struct aureqparm) + keylen;
/* fill xcrb struct */
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = zcrypt_send_cprb(&xcrb);
if (rc) {
DEBUG_ERR(
"%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int) cardnr, (int) domain, rc);
goto out;
}
/* check response returncode and reasoncode */
if (prepcblk->ccp_rtcode != 0) {
DEBUG_ERR(
"%s unwrap secure key failure, card response %d/%d\n",
__func__,
(int) prepcblk->ccp_rtcode,
(int) prepcblk->ccp_rscode);
rc = -EIO;
goto out;
}
if (prepcblk->ccp_rscode != 0) {
DEBUG_WARN(
"%s unwrap secure key warning, card response %d/%d\n",
__func__,
(int) prepcblk->ccp_rtcode,
(int) prepcblk->ccp_rscode);
}
/* process response cprb param block */
ptr = ((u8 *) prepcblk) + sizeof(struct CPRBX);
prepcblk->rpl_parmb = (u8 __user *) ptr;
prepparm = (struct aurepparm *) ptr;
/* check the returned keyblock */
if (prepparm->vud.ckb.version != 0x02) {
DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x != 0x02\n",
__func__, (int) prepparm->vud.ckb.version);
rc = -EIO;
goto out;
}
if (prepparm->vud.ckb.algo != 0x81) {
DEBUG_ERR(
"%s reply param keyblock algo mismatch 0x%02x != 0x81\n",
__func__, (int) prepparm->vud.ckb.algo);
rc = -EIO;
goto out;
}
/* copy the translated protected key */
if (prepparm->vud.ckb.keylen > *protkeylen) {
DEBUG_ERR("%s prot keylen mismatch %d > buffersize %u\n",
__func__, prepparm->vud.ckb.keylen, *protkeylen);
rc = -EIO;
goto out;
}
memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen);
*protkeylen = prepparm->vud.ckb.keylen;
if (protkeytype)
*protkeytype = PKEY_KEYTYPE_ECC;
out:
free_cprbmem(mem, PARMBSIZE, 0);
return rc;
}
EXPORT_SYMBOL(cca_ecc2protkey);
/*
* query cryptographic facility from CCA adapter
*/
......
......@@ -14,8 +14,9 @@
#include <asm/pkey.h>
/* Key token types */
#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */
#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */
#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */
#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal sym key token */
#define TOKTYPE_CCA_INTERNAL_PKA 0x1f /* CCA internal asym key token */
/* For TOKTYPE_NON_CCA: */
#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */
......@@ -93,6 +94,31 @@ struct cipherkeytoken {
u8 vdata[]; /* variable part data follows */
} __packed;
/* inside view of an CCA secure ECC private key */
struct eccprivkeytoken {
u8 type; /* 0x1f for internal asym key token */
u8 version; /* should be 0x00 */
u16 len; /* total key token length in bytes */
u8 res1[4];
u8 secid; /* 0x20 for ECC priv key section marker */
u8 secver; /* section version */
u16 seclen; /* section length */
u8 wtype; /* wrapping method, 0x00 clear, 0x01 AES */
u8 htype; /* hash method, 0x02 for SHA-256 */
u8 res2[2];
u8 kutc; /* key usage and translation control */
u8 ctype; /* curve type */
u8 kfs; /* key format and security */
u8 ksrc; /* key source */
u16 pbitlen; /* length of prime p in bits */
u16 ibmadlen; /* IBM associated data length in bytes */
u64 mkvp; /* master key verification pattern */
u8 opk[48]; /* encrypted object protection key data */
u16 adatalen; /* associated data length in bytes */
u16 fseclen; /* formated section length in bytes */
u8 more_data[]; /* more data follows */
} __packed;
/* Some defines for the CCA AES cipherkeytoken kmf1 field */
#define KMF1_XPRT_SYM 0x8000
#define KMF1_XPRT_UASY 0x4000
......@@ -122,6 +148,14 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
const u8 *token, int keybitsize,
int checkcpacfexport);
/*
* Simple check if the token is a valid CCA secure ECC private
* key token. Returns 0 on success or errno value on failure.
*/
int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
const u8 *token, size_t keysize,
int checkcpacfexport);
/*
* Generate (random) CCA AES DATA secure key.
*/
......@@ -158,6 +192,12 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
int cca_clr2cipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
const u8 *clrkey, u8 *keybuf, size_t *keybufsize);
/*
* Derive proteced key from CCA ECC secure private key.
*/
int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
/*
* Query cryptographic facility from CCA adapter
*/
......
This diff is collapsed.
......@@ -12,22 +12,28 @@
#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
#define EP11_BLOB_PKEY_EXTRACTABLE 0x00200000
/*
* Internal used values for the version field of the key header.
* Should match to the enum pkey_key_type in pkey.h.
*/
#define TOKVER_EP11_AES 0x03 /* EP11 AES key blob (old style) */
#define TOKVER_EP11_AES_WITH_HEADER 0x06 /* EP11 AES key blob with header */
#define TOKVER_EP11_ECC_WITH_HEADER 0x07 /* EP11 ECC key blob with header */
/* inside view of an EP11 secure key blob */
struct ep11keyblob {
union {
u8 session[32];
/* only used for PKEY_TYPE_EP11: */
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 version; /* 0x03 (TOKVER_EP11_AES) */
u8 res1; /* unused */
u16 keybitlen; /* clear key bit len, 0 for unknown */
} head;
......@@ -41,16 +47,41 @@ struct ep11keyblob {
u8 mac[32];
} __packed;
/* check ep11 key magic to find out if this is an ep11 key blob */
static inline bool is_ep11_keyblob(const u8 *key)
{
struct ep11keyblob *kb = (struct ep11keyblob *) key;
return (kb->version == EP11_STRUCT_MAGIC);
}
/*
* Simple check if the key blob is a valid EP11 AES key blob with header.
* 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_aes_key_with_hdr(debug_info_t *dbg, int dbflvl,
const u8 *key, size_t keylen, int checkcpacfexp);
/*
* 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.
* Simple check if the key blob is a valid EP11 ECC key blob with header.
* 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);
int ep11_check_ecc_key_with_hdr(debug_info_t *dbg, int dbflvl,
const u8 *key, size_t keylen, int checkcpacfexp);
/*
* Simple check if the key blob is a valid EP11 AES key blob with
* the header in the session field (old style EP11 AES key).
* 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_aes_key(debug_info_t *dbg, int dbflvl,
const u8 *key, size_t keylen, int checkcpacfexp);
/* EP11 card info struct */
struct ep11_card_info {
......@@ -91,12 +122,6 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
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
......@@ -119,6 +144,12 @@ int ep11_key2protkey(u16 cardnr, u16 domain, const u8 *key, size_t keylen,
int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
int minhwtype, int minapi, const u8 *wkvp);
/*
* Derive proteced key from EP11 key blob (AES and ECC keys).
*/
int ep11_kblob2protkey(u16 card, u16 dom, const u8 *key, size_t keylen,
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
void zcrypt_ep11misc_exit(void);
#endif /* _ZCRYPT_EP11MISC_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment