From e61a6134e7a547939a0b7056bcf6b12d75b6d355 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 15 Mar 2017 11:08:27 +0100 Subject: [PATCH] s390/pkey: Introduce new API for secure key verification User space needs some information about the secure key(s) before actually invoking the pkey and/or paes funcionality. This patch introduces a new ioctl API and in kernel API to verify the the secure key blob and give back some information about the key (type, bitsize, old MKVP). Both APIs are described in detail in the header files arch/s390/include/asm/pkey.h and arch/s390/include/uapi/asm/pkey.h. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/pkey.h | 21 ++++++++++ arch/s390/include/uapi/asm/pkey.h | 19 +++++++++ drivers/s390/crypto/pkey_api.c | 64 ++++++++++++++++++++++++++++++- 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/pkey.h b/arch/s390/include/asm/pkey.h index b48aef4188f6..4c484590d858 100644 --- a/arch/s390/include/asm/pkey.h +++ b/arch/s390/include/asm/pkey.h @@ -87,4 +87,25 @@ int pkey_findcard(const struct pkey_seckey *seckey, int pkey_skey2pkey(const struct pkey_seckey *seckey, struct pkey_protkey *protkey); +/* + * Verify the given secure key for being able to be useable with + * the pkey module. Check for correct key type and check for having at + * least one crypto card being able to handle this key (master key + * or old master key verification pattern matches). + * Return some info about the key: keysize in bits, keytype (currently + * only AES), flag if key is wrapped with an old MKVP. + * @param seckey pointer to buffer with the input secure key + * @param pcardnr pointer to cardnr, receives the card number on success + * @param pdomain pointer to domain, receives the domain number on success + * @param pkeysize pointer to keysize, receives the bitsize of the key + * @param pattributes pointer to attributes, receives additional info + * PKEY_VERIFY_ATTR_AES if the key is an AES key + * PKEY_VERIFY_ATTR_OLD_MKVP if key has old mkvp stored in + * @return 0 on success, negative errno value on failure. If no card could + * be found which is able to handle this key, -ENODEV is returned. + */ +int pkey_verifykey(const struct pkey_seckey *seckey, + u16 *pcardnr, u16 *pdomain, + u16 *pkeysize, u32 *pattributes); + #endif /* _KAPI_PKEY_H */ diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h index ed7f19c27ce5..e6c04faf8a6c 100644 --- a/arch/s390/include/uapi/asm/pkey.h +++ b/arch/s390/include/uapi/asm/pkey.h @@ -109,4 +109,23 @@ struct pkey_skey2pkey { }; #define PKEY_SKEY2PKEY _IOWR(PKEY_IOCTL_MAGIC, 0x06, struct pkey_skey2pkey) +/* + * Verify the given secure key for being able to be useable with + * the pkey module. Check for correct key type and check for having at + * least one crypto card being able to handle this key (master key + * or old master key verification pattern matches). + * Return some info about the key: keysize in bits, keytype (currently + * only AES), flag if key is wrapped with an old MKVP. + */ +struct pkey_verifykey { + struct pkey_seckey seckey; /* in: the secure key blob */ + __u16 cardnr; /* out: card number */ + __u16 domain; /* out: domain number */ + __u16 keysize; /* out: key size in bits */ + __u32 attributes; /* out: attribute bits */ +}; +#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey) +#define PKEY_VERIFY_ATTR_AES 0x00000001 /* key is an AES key */ +#define PKEY_VERIFY_ATTR_OLD_MKVP 0x00000100 /* key has old MKVP value */ + #endif /* _UAPI_PKEY_H */ diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 058db724b5a2..ea86da8c75f9 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -80,7 +80,7 @@ struct secaeskeytoken { * token. If keybitsize is given, the bitsize of the key is * also checked. Returns 0 on success or errno value on failure. */ -static int check_secaeskeytoken(u8 *token, int keybitsize) +static int check_secaeskeytoken(const u8 *token, int keybitsize) { struct secaeskeytoken *t = (struct secaeskeytoken *) token; @@ -1003,6 +1003,53 @@ int pkey_skey2pkey(const struct pkey_seckey *seckey, } EXPORT_SYMBOL(pkey_skey2pkey); +/* + * Verify key and give back some info about the key. + */ +int pkey_verifykey(const struct pkey_seckey *seckey, + u16 *pcardnr, u16 *pdomain, + u16 *pkeysize, u32 *pattributes) +{ + struct secaeskeytoken *t = (struct secaeskeytoken *) seckey; + u16 cardnr, domain; + u64 mkvp[2]; + int rc; + + /* check the secure key for valid AES secure key */ + rc = check_secaeskeytoken((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 = pkey_findcard(seckey, &cardnr, &domain, 1); + if (rc) + goto out; + + /* check mkvp for old mkvp match */ + rc = mkvp_cache_fetch(cardnr, domain, mkvp); + if (rc) + goto out; + if (t->mkvp == mkvp[1]) { + DEBUG_DBG("pkey_verifykey secure key has old mkvp\n"); + if (pattributes) + *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP; + } + + if (pcardnr) + *pcardnr = cardnr; + if (pdomain) + *pdomain = domain; + +out: + DEBUG_DBG("pkey_verifykey rc=%d\n", rc); + return rc; +} +EXPORT_SYMBOL(pkey_verifykey); + /* * File io functions */ @@ -1104,6 +1151,21 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; break; } + case PKEY_VERIFYKEY: { + struct pkey_verifykey __user *uvk = (void __user *) arg; + struct pkey_verifykey kvk; + + if (copy_from_user(&kvk, uvk, sizeof(kvk))) + return -EFAULT; + rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain, + &kvk.keysize, &kvk.attributes); + DEBUG_DBG("pkey_ioctl pkey_verifykey()=%d\n", rc); + if (rc) + break; + if (copy_to_user(uvk, &kvk, sizeof(kvk))) + return -EFAULT; + break; + } default: /* unknown/unsupported ioctl cmd */ return -ENOTTY;