summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Franzki <ifranzki@linux.ibm.com>2018-08-23 17:49:38 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2018-10-10 07:37:18 +0200
commitcb26b9ff7187ea79698f5e872d713f30affcc0a3 (patch)
tree8efa20448fa9ac8480880510a35d75795cc9186e
parentaf504452d10ece7c6d68bc9f90f478ebecd7ce76 (diff)
downloadlwn-cb26b9ff7187ea79698f5e872d713f30affcc0a3.tar.gz
lwn-cb26b9ff7187ea79698f5e872d713f30affcc0a3.zip
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 <ifranzki@linux.ibm.com> Reviewed-by: Harald Freudenberger <freude@linux.ibm.com> Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/pkey.h8
-rw-r--r--arch/s390/include/uapi/asm/pkey.h9
-rw-r--r--drivers/s390/crypto/pkey_api.c67
3 files changed, 83 insertions, 1 deletions
diff --git a/arch/s390/include/asm/pkey.h b/arch/s390/include/asm/pkey.h
index c931818b9921..2833d6324979 100644
--- a/arch/s390/include/asm/pkey.h
+++ b/arch/s390/include/asm/pkey.h
@@ -117,4 +117,12 @@ int pkey_verifykey(const struct pkey_seckey *seckey,
*/
int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey);
+/*
+ * In-kernel API: Verify an (AES) protected key.
+ * @param protkey pointer to buffer containing the protected key to verify
+ * @return 0 on success, negative errno value on failure. In case the protected
+ * key is not valid -EKEYREJECTED is returned
+ */
+int pkey_verifyprotkey(const struct pkey_protkey *protkey);
+
#endif /* _KAPI_PKEY_H */
diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h
index 10a7bc7c5fa9..fef08dbd2e8d 100644
--- a/arch/s390/include/uapi/asm/pkey.h
+++ b/arch/s390/include/uapi/asm/pkey.h
@@ -139,4 +139,13 @@ struct pkey_genprotk {
#define PKEY_GENPROTK _IOWR(PKEY_IOCTL_MAGIC, 0x08, struct pkey_genprotk)
+/*
+ * Verify an (AES) protected key.
+ */
+struct pkey_verifyprotk {
+ struct pkey_protkey protkey; /* in: the protected key to verify */
+};
+
+#define PKEY_VERIFYPROTK _IOW(PKEY_IOCTL_MAGIC, 0x09, struct pkey_verifyprotk)
+
#endif /* _UAPI_PKEY_H */
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 <asm/zcrypt.h>
#include <asm/cpacf.h>
#include <asm/pkey.h>
+#include <crypto/aes.h>
#include "zcrypt_api.h"
@@ -1114,6 +1115,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, &param, 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);