Blob Blame History Raw
From: Ingo Franzki <ifranzki@linux.ibm.com>
Subject: s390/pkey: Introduce new API for random protected key verification
Git-commit: cb26b9ff7187ea79698f5e872d713f30affcc0a3
Patch-mainline: v4.20-rc1
References: FATE#326366, LTC#169192, bsc#1113523

Summary:     crypto: Add support for randomly generated protected keys
Description: This feature enhances the paes_s390 and the pkey kernel modules
             to allow using randomly generated protected keys. Such randomly
             generated protected keys do not require an CryptoExpress adapter.
             This is mainly useful for encrypted swap disks, or any other
             cases where the keys are ephemeral, that their life time does not
             extend over different boot, machine migrations or suspend/resume.

Upstream-Description:

             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>

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 arch/s390/include/asm/pkey.h      |    8 ++++
 arch/s390/include/uapi/asm/pkey.h |    9 +++++
 drivers/s390/crypto/pkey_api.c    |   67 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 83 insertions(+), 1 deletion(-)

--- a/arch/s390/include/asm/pkey.h
+++ b/arch/s390/include/asm/pkey.h
@@ -116,4 +116,12 @@ int pkey_verifykey(const struct pkey_sec
  */
 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 */
--- a/arch/s390/include/uapi/asm/pkey.h
+++ b/arch/s390/include/uapi/asm/pkey.h
@@ -138,4 +138,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 */
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -24,6 +24,7 @@
 #include <asm/zcrypt.h>
 #include <asm/cpacf.h>
 #include <asm/pkey.h>
+#include <crypto/aes.h>
 
 #include "zcrypt_api.h"
 
@@ -1119,6 +1120,52 @@ int pkey_genprotkey(__u32 keytype, struc
 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
  */
 
@@ -1248,6 +1295,16 @@ static long pkey_unlocked_ioctl(struct f
 			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;
@@ -1509,7 +1566,7 @@ static struct miscdevice pkey_dev = {
  */
 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))
@@ -1519,6 +1576,14 @@ 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);