s390/pkey: Introduce new API for secure key verification
authorHarald Freudenberger <freude@linux.vnet.ibm.com>
Wed, 15 Mar 2017 10:08:27 +0000 (11:08 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 22 Mar 2017 07:29:13 +0000 (08:29 +0100)
User space needs some information about the secure key(s)
before actually invoking the pkey and/or paes funcionality.
This patch introduces a new ioctl API and in kernel API to
verify the the secure key blob and give back some
information about the key (type, bitsize, old MKVP).
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: Harald Freudenberger <freude@linux.vnet.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 b48aef4..4c48459 100644 (file)
@@ -87,4 +87,25 @@ int pkey_findcard(const struct pkey_seckey *seckey,
 int pkey_skey2pkey(const struct pkey_seckey *seckey,
                   struct pkey_protkey *protkey);
 
+/*
+ * Verify the given secure key for being able to be useable with
+ * the pkey module. Check for correct key type and check for having at
+ * least one crypto card being able to handle this key (master key
+ * or old master key verification pattern matches).
+ * Return some info about the key: keysize in bits, keytype (currently
+ * only AES), flag if key is wrapped with an old MKVP.
+ * @param seckey pointer to buffer with the input secure key
+ * @param pcardnr pointer to cardnr, receives the card number on success
+ * @param pdomain pointer to domain, receives the domain number on success
+ * @param pkeysize pointer to keysize, receives the bitsize of the key
+ * @param pattributes pointer to attributes, receives additional info
+ *       PKEY_VERIFY_ATTR_AES if the key is an AES key
+ *       PKEY_VERIFY_ATTR_OLD_MKVP if key has old mkvp stored in
+ * @return 0 on success, negative errno value on failure. If no card could
+ *        be found which is able to handle this key, -ENODEV is returned.
+ */
+int pkey_verifykey(const struct pkey_seckey *seckey,
+                  u16 *pcardnr, u16 *pdomain,
+                  u16 *pkeysize, u32 *pattributes);
+
 #endif /* _KAPI_PKEY_H */
index ed7f19c..e6c04fa 100644 (file)
@@ -109,4 +109,23 @@ struct pkey_skey2pkey {
 };
 #define PKEY_SKEY2PKEY _IOWR(PKEY_IOCTL_MAGIC, 0x06, struct pkey_skey2pkey)
 
+/*
+ * Verify the given secure key for being able to be useable with
+ * the pkey module. Check for correct key type and check for having at
+ * least one crypto card being able to handle this key (master key
+ * or old master key verification pattern matches).
+ * Return some info about the key: keysize in bits, keytype (currently
+ * only AES), flag if key is wrapped with an old MKVP.
+ */
+struct pkey_verifykey {
+       struct pkey_seckey seckey;             /* in: the secure key blob */
+       __u16  cardnr;                         /* out: card number        */
+       __u16  domain;                         /* out: domain number      */
+       __u16  keysize;                        /* out: key size in bits   */
+       __u32  attributes;                     /* out: attribute bits     */
+};
+#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
+#define PKEY_VERIFY_ATTR_AES      0x00000001  /* key is an AES key */
+#define PKEY_VERIFY_ATTR_OLD_MKVP  0x00000100  /* key has old MKVP value */
+
 #endif /* _UAPI_PKEY_H */
index 058db72..ea86da8 100644 (file)
@@ -80,7 +80,7 @@ struct secaeskeytoken {
  * token. If keybitsize is given, the bitsize of the key is
  * also checked. Returns 0 on success or errno value on failure.
  */
-static int check_secaeskeytoken(u8 *token, int keybitsize)
+static int check_secaeskeytoken(const u8 *token, int keybitsize)
 {
        struct secaeskeytoken *t = (struct secaeskeytoken *) token;
 
@@ -1004,6 +1004,53 @@ int pkey_skey2pkey(const struct pkey_seckey *seckey,
 EXPORT_SYMBOL(pkey_skey2pkey);
 
 /*
+ * Verify key and give back some info about the key.
+ */
+int pkey_verifykey(const struct pkey_seckey *seckey,
+                  u16 *pcardnr, u16 *pdomain,
+                  u16 *pkeysize, u32 *pattributes)
+{
+       struct secaeskeytoken *t = (struct secaeskeytoken *) seckey;
+       u16 cardnr, domain;
+       u64 mkvp[2];
+       int rc;
+
+       /* check the secure key for valid AES secure key */
+       rc = check_secaeskeytoken((u8 *) seckey, 0);
+       if (rc)
+               goto out;
+       if (pattributes)
+               *pattributes = PKEY_VERIFY_ATTR_AES;
+       if (pkeysize)
+               *pkeysize = t->bitsize;
+
+       /* try to find a card which can handle this key */
+       rc = pkey_findcard(seckey, &cardnr, &domain, 1);
+       if (rc)
+               goto out;
+
+       /* check mkvp for old mkvp match */
+       rc = mkvp_cache_fetch(cardnr, domain, mkvp);
+       if (rc)
+               goto out;
+       if (t->mkvp == mkvp[1]) {
+               DEBUG_DBG("pkey_verifykey secure key has old mkvp\n");
+               if (pattributes)
+                       *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP;
+       }
+
+       if (pcardnr)
+               *pcardnr = cardnr;
+       if (pdomain)
+               *pdomain = domain;
+
+out:
+       DEBUG_DBG("pkey_verifykey rc=%d\n", rc);
+       return rc;
+}
+EXPORT_SYMBOL(pkey_verifykey);
+
+/*
  * File io functions
  */
 
@@ -1104,6 +1151,21 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
                        return -EFAULT;
                break;
        }
+       case PKEY_VERIFYKEY: {
+               struct pkey_verifykey __user *uvk = (void __user *) arg;
+               struct pkey_verifykey kvk;
+
+               if (copy_from_user(&kvk, uvk, sizeof(kvk)))
+                       return -EFAULT;
+               rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain,
+                                   &kvk.keysize, &kvk.attributes);
+               DEBUG_DBG("pkey_ioctl pkey_verifykey()=%d\n", rc);
+               if (rc)
+                       break;
+               if (copy_to_user(uvk, &kvk, sizeof(kvk)))
+                       return -EFAULT;
+               break;
+       }
        default:
                /* unknown/unsupported ioctl cmd */
                return -ENOTTY;