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, ¶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
*/
@@ -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);