s390/pkey: Introduce new API for random protected key verification
authorIngo Franzki <ifranzki@linux.ibm.com>
Thu, 23 Aug 2018 15:49:38 +0000 (17:49 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 10 Oct 2018 05:37:18 +0000 (07:37 +0200)
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>
arch/s390/include/asm/pkey.h
arch/s390/include/uapi/asm/pkey.h
drivers/s390/crypto/pkey_api.c

index c931818b99213603941d82f214723ad410fc480d..2833d63249793a2fad1f7a26fb32bfd356cee423 100644 (file)
@@ -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 */
index 10a7bc7c5fa9bd9a03498936582343a02edc5c6c..fef08dbd2e8d3ed3a1704ee64ef88c00374cf713 100644 (file)
@@ -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 */
index d0160a18081abfaaaba9dacec2cb29b7c8d10683..c592270b906a8c3abffa333f22988e0467221206 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/zcrypt.h>
 #include <asm/cpacf.h>
 #include <asm/pkey.h>
+#include <crypto/aes.h>
 
 #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, &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);