s390/pkey: Introduce new API for transforming key blobs
authorIngo Franzki <ifranzki@linux.ibm.com>
Fri, 24 Aug 2018 09:29:15 +0000 (11:29 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 10 Oct 2018 05:37:19 +0000 (07:37 +0200)
Introduce a new ioctl API and in-kernel API to transform
a variable length key blob of any supported type into a
protected key.

Transforming a secure key blob uses the already existing
function pkey_sec2protk().
Transforming a protected key blob also verifies if the
protected key is still valid. If not, -ENODEV is returned.

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 2833d63..9b6e790 100644 (file)
@@ -125,4 +125,14 @@ int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey);
  */
 int pkey_verifyprotkey(const struct pkey_protkey *protkey);
 
+/*
+ * In-kernel API: Transform an key blob (of any type) into a protected key.
+ * @param key pointer to a buffer containing the key blob
+ * @param keylen size of the key blob in bytes
+ * @param protkey pointer to buffer receiving the protected key
+ * @return 0 on success, negative errno value on failure
+ */
+int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
+                     struct pkey_protkey *protkey);
+
 #endif /* _KAPI_PKEY_H */
index fef08db..c0e86ce 100644 (file)
 #define PKEY_IOCTL_MAGIC 'p'
 
 #define SECKEYBLOBSIZE 64     /* secure key blob size is always 64 bytes */
+#define PROTKEYBLOBSIZE 80  /* protected key blob size is always 80 bytes */
 #define MAXPROTKEYSIZE 64  /* a protected key blob may be up to 64 bytes */
 #define MAXCLRKEYSIZE  32     /* a clear key value may be up to 32 bytes */
 
+#define MINKEYBLOBSIZE SECKEYBLOBSIZE      /* Minimum size of a key blob */
+#define MAXKEYBLOBSIZE PROTKEYBLOBSIZE     /* Maximum size of a key blob */
+
 /* defines for the type field within the pkey_protkey struct */
 #define PKEY_KEYTYPE_AES_128  1
 #define PKEY_KEYTYPE_AES_192  2
@@ -148,4 +152,15 @@ struct pkey_verifyprotk {
 
 #define PKEY_VERIFYPROTK _IOW(PKEY_IOCTL_MAGIC, 0x09, struct pkey_verifyprotk)
 
+/*
+ * Transform an key blob (of any type) into a protected key
+ */
+struct pkey_kblob2pkey {
+       __u8 __user *key;               /* in: the key blob        */
+       __u32 keylen;                   /* in: the key blob length */
+       struct pkey_protkey protkey;    /* out: the protected key  */
+};
+
+#define PKEY_KBLOB2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x0A, struct pkey_kblob2pkey)
+
 #endif /* _UAPI_PKEY_H */
index c592270..683ff72 100644 (file)
@@ -67,6 +67,14 @@ static void __exit pkey_debug_exit(void)
 /* For TOKTYPE_CCA_INTERNAL: */
 #define TOKVER_CCA_AES         0x04 /* CCA AES key token */
 
+/* header part of a key token */
+struct keytoken_header {
+       u8  type;     /* one of the TOKTYPE values */
+       u8  res0[3];
+       u8  version;  /* one of the TOKVER values */
+       u8  res1[3];
+} __packed;
+
 /* inside view of a secure key token (only type 0x01 version 0x04) */
 struct secaeskeytoken {
        u8  type;     /* 0x01 for internal key token */
@@ -1161,6 +1169,80 @@ int pkey_verifyprotkey(const struct pkey_protkey *protkey)
 EXPORT_SYMBOL(pkey_verifyprotkey);
 
 /*
+ * Transform a non-CCA key token into a protected key
+ */
+static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen,
+                              struct pkey_protkey *protkey)
+{
+       struct keytoken_header *hdr = (struct keytoken_header *)key;
+       struct protaeskeytoken *t;
+
+       switch (hdr->version) {
+       case TOKVER_PROTECTED_KEY:
+               if (keylen != sizeof(struct protaeskeytoken))
+                       return -EINVAL;
+
+               t = (struct protaeskeytoken *)key;
+               protkey->len = t->len;
+               protkey->type = t->keytype;
+               memcpy(protkey->protkey, t->protkey,
+                      sizeof(protkey->protkey));
+
+               return pkey_verifyprotkey(protkey);
+       default:
+               DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
+                         __func__, hdr->version);
+               return -EINVAL;
+       }
+}
+
+/*
+ * Transform a CCA internal key token into a protected key
+ */
+static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen,
+                              struct pkey_protkey *protkey)
+{
+       struct keytoken_header *hdr = (struct keytoken_header *)key;
+
+       switch (hdr->version) {
+       case TOKVER_CCA_AES:
+               if (keylen != sizeof(struct secaeskeytoken))
+                       return -EINVAL;
+
+               return pkey_skey2pkey((struct pkey_seckey *)key,
+                                     protkey);
+       default:
+               DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
+                         __func__, hdr->version);
+               return -EINVAL;
+       }
+}
+
+/*
+ * Transform a key blob (of any type) into a protected key
+ */
+int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
+                     struct pkey_protkey *protkey)
+{
+       struct keytoken_header *hdr = (struct keytoken_header *)key;
+
+       if (keylen < sizeof(struct keytoken_header))
+               return -EINVAL;
+
+       switch (hdr->type) {
+       case TOKTYPE_NON_CCA:
+               return pkey_nonccatok2pkey(key, keylen, protkey);
+       case TOKTYPE_CCA_INTERNAL:
+               return pkey_ccainttok2pkey(key, keylen, protkey);
+       default:
+               DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__,
+                         hdr->type);
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(pkey_keyblob2pkey);
+
+/*
  * File io functions
  */
 
@@ -1300,6 +1382,34 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
                break;
        }
+       case PKEY_KBLOB2PROTK: {
+               struct pkey_kblob2pkey __user *utp = (void __user *) arg;
+               struct pkey_kblob2pkey ktp;
+               __u8 __user *ukey;
+               __u8 *kkey;
+
+               if (copy_from_user(&ktp, utp, sizeof(ktp)))
+                       return -EFAULT;
+               if (ktp.keylen < MINKEYBLOBSIZE ||
+                   ktp.keylen > MAXKEYBLOBSIZE)
+                       return -EINVAL;
+               ukey = ktp.key;
+               kkey = kmalloc(ktp.keylen, GFP_KERNEL);
+               if (kkey == NULL)
+                       return -ENOMEM;
+               if (copy_from_user(kkey, ukey, ktp.keylen)) {
+                       kfree(kkey);
+                       return -EFAULT;
+               }
+               rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey);
+               DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
+               kfree(kkey);
+               if (rc)
+                       break;
+               if (copy_to_user(utp, &ktp, sizeof(ktp)))
+                       return -EFAULT;
+               break;
+       }
        default:
                /* unknown/unsupported ioctl cmd */
                return -ENOTTY;