From cb26b9ff7187ea79698f5e872d713f30affcc0a3 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Thu, 23 Aug 2018 17:49:38 +0200 Subject: s390/pkey: Introduce new API for random protected key verification Introduce a new ioctl API and in-kernel API to verify if a random protected key is still valid. A protected key is invalid when its wrapping key verification pattern does not match the verification pattern of the LPAR. Each time an LPAR is activated, a new LPAR wrapping key is generated and the wrapping key verification pattern is updated. 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: Ingo Franzki Reviewed-by: Harald Freudenberger Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/pkey_api.c | 67 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'drivers/s390/crypto/pkey_api.c') diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index d0160a18081a..c592270b906a 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "zcrypt_api.h" @@ -1113,6 +1114,52 @@ int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey) } EXPORT_SYMBOL(pkey_genprotkey); +/* + * Verify if a protected key is still valid + */ +int pkey_verifyprotkey(const struct pkey_protkey *protkey) +{ + unsigned long fc; + 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; + + switch (protkey->type) { + case PKEY_KEYTYPE_AES_128: + fc = CPACF_KMC_PAES_128; + break; + case PKEY_KEYTYPE_AES_192: + fc = CPACF_KMC_PAES_192; + break; + case PKEY_KEYTYPE_AES_256: + fc = CPACF_KMC_PAES_256; + break; + default: + DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__, + protkey->type); + return -EINVAL; + } + + memset(null_msg, 0, sizeof(null_msg)); + + memset(param.iv, 0, sizeof(param.iv)); + memcpy(param.key, protkey->protkey, sizeof(param.key)); + + k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf, + sizeof(null_msg)); + if (k != sizeof(null_msg)) { + DEBUG_ERR("%s protected key is not valid\n", __func__); + return -EKEYREJECTED; + } + + return 0; +} +EXPORT_SYMBOL(pkey_verifyprotkey); + /* * File io functions */ @@ -1243,6 +1290,16 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; break; } + case PKEY_VERIFYPROTK: { + struct pkey_verifyprotk __user *uvp = (void __user *) arg; + struct pkey_verifyprotk kvp; + + if (copy_from_user(&kvp, uvp, sizeof(kvp))) + return -EFAULT; + rc = pkey_verifyprotkey(&kvp.protkey); + DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc); + break; + } default: /* unknown/unsupported ioctl cmd */ return -ENOTTY; @@ -1504,7 +1561,7 @@ static struct miscdevice pkey_dev = { */ static int __init pkey_init(void) { - cpacf_mask_t pckmo_functions; + cpacf_mask_t pckmo_functions, kmc_functions; /* check for pckmo instructions available */ if (!cpacf_query(CPACF_PCKMO, &pckmo_functions)) @@ -1514,6 +1571,14 @@ static int __init pkey_init(void) !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_256_KEY)) return -EOPNOTSUPP; + /* check for kmc instructions available */ + if (!cpacf_query(CPACF_KMC, &kmc_functions)) + return -EOPNOTSUPP; + if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) || + !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) || + !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) + return -EOPNOTSUPP; + pkey_debug_init(); return misc_register(&pkey_dev); -- cgit v1.2.3-59-g8ed1b