s390/pkey: Add AES xts and HMAC clear key token support
authorHarald Freudenberger <freude@linux.ibm.com>
Mon, 2 Sep 2024 13:19:44 +0000 (15:19 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Thu, 5 Sep 2024 13:17:23 +0000 (15:17 +0200)
Add support for deriving protected keys from clear key token for
AES xts and HMAC keys via PCKMO instruction. Add support for
protected key generation and unwrap of protected key tokens for
these key types. Furthermore 4 new sysfs attributes are introduced:

- /sys/devices/virtual/misc/pkey/protkey/protkey_aes_xts_128
- /sys/devices/virtual/misc/pkey/protkey/protkey_aes_xts_256
- /sys/devices/virtual/misc/pkey/protkey/protkey_hmac_512
- /sys/devices/virtual/misc/pkey/protkey/protkey_hmac_1024

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/uapi/asm/pkey.h
drivers/s390/crypto/pkey_base.h
drivers/s390/crypto/pkey_pckmo.c
drivers/s390/crypto/pkey_sysfs.c

index 0418308..60431d0 100644 (file)
 #define PKEY_KEYTYPE_ECC_P521          7
 #define PKEY_KEYTYPE_ECC_ED25519       8
 #define PKEY_KEYTYPE_ECC_ED448         9
+#define PKEY_KEYTYPE_AES_XTS_128       10
+#define PKEY_KEYTYPE_AES_XTS_256       11
+#define PKEY_KEYTYPE_HMAC_512          12
+#define PKEY_KEYTYPE_HMAC_1024         13
 
 /* the newer ioctls use a pkey_key_type enum for type information */
 enum pkey_key_type {
index fd15190..7a1a5ce 100644 (file)
@@ -33,11 +33,22 @@ extern debug_info_t *pkey_dbf_info;
 #define MAXAPQNSINLIST 64      /* max 64 apqns within a apqn list */
 #define AES_WK_VP_SIZE 32      /* Size of WK VP block appended to a prot key */
 
-/* inside view of a protected key token (only type 0x00 version 0x01) */
+/* inside view of a generic protected key token */
+struct protkeytoken {
+       u8  type;     /* 0x00 for PAES specific key tokens */
+       u8  res0[3];
+       u8  version;  /* should be 0x01 for protected key token */
+       u8  res1[3];
+       u32 keytype;  /* key type, one of the PKEY_KEYTYPE values */
+       u32 len;      /* bytes actually stored in protkey[] */
+       u8  protkey[]; /* the protected key blob */
+} __packed;
+
+/* inside view of a protected AES key token */
 struct protaeskeytoken {
        u8  type;     /* 0x00 for PAES specific key tokens */
        u8  res0[3];
-       u8  version;  /* should be 0x01 for protected AES key token */
+       u8  version;  /* should be 0x01 for protected key token */
        u8  res1[3];
        u32 keytype;  /* key type, one of the PKEY_KEYTYPE values */
        u32 len;      /* bytes actually stored in protkey[] */
index 0667e55..98079b1 100644 (file)
@@ -47,6 +47,10 @@ static bool is_pckmo_key(const u8 *key, u32 keylen)
                        case PKEY_KEYTYPE_ECC_P521:
                        case PKEY_KEYTYPE_ECC_ED25519:
                        case PKEY_KEYTYPE_ECC_ED448:
+                       case PKEY_KEYTYPE_AES_XTS_128:
+                       case PKEY_KEYTYPE_AES_XTS_256:
+                       case PKEY_KEYTYPE_HMAC_512:
+                       case PKEY_KEYTYPE_HMAC_1024:
                                return true;
                        default:
                                return false;
@@ -81,7 +85,7 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen,
        static cpacf_mask_t pckmo_functions;
 
        int keysize, rc = -EINVAL;
-       u8 paramblock[112];
+       u8 paramblock[160];
        u32 pkeytype;
        long fc;
 
@@ -134,6 +138,30 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen,
                pkeytype = PKEY_KEYTYPE_ECC;
                fc = CPACF_PCKMO_ENC_ECC_ED448_KEY;
                break;
+       case PKEY_KEYTYPE_AES_XTS_128:
+               /* 2x16 byte keys, 32 byte aes wkvp, total 64 bytes */
+               keysize = 32;
+               pkeytype = PKEY_KEYTYPE_AES_XTS_128;
+               fc = CPACF_PCKMO_ENC_AES_XTS_128_DOUBLE_KEY;
+               break;
+       case PKEY_KEYTYPE_AES_XTS_256:
+               /* 2x32 byte keys, 32 byte aes wkvp, total 96 bytes */
+               keysize = 64;
+               pkeytype = PKEY_KEYTYPE_AES_XTS_256;
+               fc = CPACF_PCKMO_ENC_AES_XTS_256_DOUBLE_KEY;
+               break;
+       case PKEY_KEYTYPE_HMAC_512:
+               /* 64 byte key, 32 byte aes wkvp, total 96 bytes */
+               keysize = 64;
+               pkeytype = PKEY_KEYTYPE_HMAC_512;
+               fc = CPACF_PCKMO_ENC_HMAC_512_KEY;
+               break;
+       case PKEY_KEYTYPE_HMAC_1024:
+               /* 128 byte key, 32 byte aes wkvp, total 160 bytes */
+               keysize = 128;
+               pkeytype = PKEY_KEYTYPE_HMAC_1024;
+               fc = CPACF_PCKMO_ENC_HMAC_1024_KEY;
+               break;
        default:
                PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
                             __func__, keytype);
@@ -260,14 +288,39 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen,
 
        switch (hdr->version) {
        case TOKVER_PROTECTED_KEY: {
-               struct protaeskeytoken *t;
+               struct protkeytoken *t = (struct protkeytoken *)key;
 
-               if (keylen != sizeof(struct protaeskeytoken))
+               if (keylen < sizeof(*t))
                        goto out;
-               t = (struct protaeskeytoken *)key;
-               rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype);
-               if (rc)
+               switch (t->keytype) {
+               case PKEY_KEYTYPE_AES_128:
+               case PKEY_KEYTYPE_AES_192:
+               case PKEY_KEYTYPE_AES_256:
+                       if (keylen != sizeof(struct protaeskeytoken))
+                               goto out;
+                       rc = pckmo_verify_protkey(t->protkey, t->len,
+                                                 t->keytype);
+                       if (rc)
+                               goto out;
+                       break;
+               case PKEY_KEYTYPE_AES_XTS_128:
+                       if (t->len != 64 || keylen != sizeof(*t) + t->len)
+                               goto out;
+                       break;
+               case PKEY_KEYTYPE_AES_XTS_256:
+               case PKEY_KEYTYPE_HMAC_512:
+                       if (t->len != 96 || keylen != sizeof(*t) + t->len)
+                               goto out;
+                       break;
+               case PKEY_KEYTYPE_HMAC_1024:
+                       if (t->len != 160 || keylen != sizeof(*t) + t->len)
+                               goto out;
+                       break;
+               default:
+                       PKEY_DBF_ERR("%s protected key token: unknown keytype %u\n",
+                                    __func__, t->keytype);
                        goto out;
+               }
                memcpy(protkey, t->protkey, t->len);
                *protkeylen = t->len;
                *protkeytype = t->keytype;
@@ -301,6 +354,18 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen,
                case PKEY_KEYTYPE_ECC_ED448:
                        keysize = 64;
                        break;
+               case PKEY_KEYTYPE_AES_XTS_128:
+                       keysize = 32;
+                       break;
+               case PKEY_KEYTYPE_AES_XTS_256:
+                       keysize = 64;
+                       break;
+               case PKEY_KEYTYPE_HMAC_512:
+                       keysize = 64;
+                       break;
+               case PKEY_KEYTYPE_HMAC_1024:
+                       keysize = 128;
+                       break;
                default:
                        break;
                }
@@ -337,14 +402,29 @@ out:
 static int pckmo_gen_protkey(u32 keytype, u32 subtype,
                             u8 *protkey, u32 *protkeylen, u32 *protkeytype)
 {
-       u8 clrkey[32];
+       u8 clrkey[128];
        int keysize;
        int rc;
 
-       keysize = pkey_keytype_aes_to_size(keytype);
-       if (!keysize) {
-               PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", __func__,
-                            keytype);
+       switch (keytype) {
+       case PKEY_KEYTYPE_AES_128:
+       case PKEY_KEYTYPE_AES_192:
+       case PKEY_KEYTYPE_AES_256:
+               keysize = pkey_keytype_aes_to_size(keytype);
+               break;
+       case PKEY_KEYTYPE_AES_XTS_128:
+               keysize = 32;
+               break;
+       case PKEY_KEYTYPE_AES_XTS_256:
+       case PKEY_KEYTYPE_HMAC_512:
+               keysize = 64;
+               break;
+       case PKEY_KEYTYPE_HMAC_1024:
+               keysize = 128;
+               break;
+       default:
+               PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",
+                            __func__, keytype);
                return -EINVAL;
        }
        if (subtype != PKEY_TYPE_PROTKEY) {
index 56205f5..cc0fc1e 100644 (file)
@@ -99,6 +99,90 @@ static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf,
        return sizeof(protkeytoken);
 }
 
+/*
+ * Sysfs attribute read function for the AES XTS prot key binary attributes.
+ * The implementation can not deal with partial reads, because a new random
+ * protected key blob is generated with each read. In case of partial reads
+ * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
+ */
+static ssize_t pkey_protkey_aes_xts_attr_read(u32 keytype, char *buf,
+                                             loff_t off, size_t count)
+{
+       struct protkeytoken *t = (struct protkeytoken *)buf;
+       u32 protlen, prottype;
+       int rc;
+
+       switch (keytype) {
+       case PKEY_KEYTYPE_AES_XTS_128:
+               protlen = 64;
+               break;
+       case PKEY_KEYTYPE_AES_XTS_256:
+               protlen = 96;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (off != 0 || count < sizeof(*t) + protlen)
+               return -EINVAL;
+
+       memset(t, 0, sizeof(*t) + protlen);
+       t->type = TOKTYPE_NON_CCA;
+       t->version = TOKVER_PROTECTED_KEY;
+       t->keytype = keytype;
+
+       rc = sys_pkey_handler_gen_key(keytype, PKEY_TYPE_PROTKEY, 0, 0,
+                                     t->protkey, &protlen, &prottype);
+       if (rc)
+               return rc;
+
+       t->len = protlen;
+
+       return sizeof(*t) + protlen;
+}
+
+/*
+ * Sysfs attribute read function for the HMAC prot key binary attributes.
+ * The implementation can not deal with partial reads, because a new random
+ * protected key blob is generated with each read. In case of partial reads
+ * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
+ */
+static ssize_t pkey_protkey_hmac_attr_read(u32 keytype, char *buf,
+                                          loff_t off, size_t count)
+{
+       struct protkeytoken *t = (struct protkeytoken *)buf;
+       u32 protlen, prottype;
+       int rc;
+
+       switch (keytype) {
+       case PKEY_KEYTYPE_HMAC_512:
+               protlen = 96;
+               break;
+       case PKEY_KEYTYPE_HMAC_1024:
+               protlen = 160;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (off != 0 || count < sizeof(*t) + protlen)
+               return -EINVAL;
+
+       memset(t, 0, sizeof(*t) + protlen);
+       t->type = TOKTYPE_NON_CCA;
+       t->version = TOKVER_PROTECTED_KEY;
+       t->keytype = keytype;
+
+       rc = sys_pkey_handler_gen_key(keytype, PKEY_TYPE_PROTKEY, 0, 0,
+                                     t->protkey, &protlen, &prottype);
+       if (rc)
+               return rc;
+
+       t->len = protlen;
+
+       return sizeof(*t) + protlen;
+}
+
 static ssize_t protkey_aes_128_read(struct file *filp,
                                    struct kobject *kobj,
                                    struct bin_attribute *attr,
@@ -149,11 +233,55 @@ static ssize_t protkey_aes_256_xts_read(struct file *filp,
                                          off, count);
 }
 
+static ssize_t protkey_aes_xts_128_read(struct file *filp,
+                                       struct kobject *kobj,
+                                       struct bin_attribute *attr,
+                                       char *buf, loff_t off,
+                                       size_t count)
+{
+       return pkey_protkey_aes_xts_attr_read(PKEY_KEYTYPE_AES_XTS_128,
+                                             buf, off, count);
+}
+
+static ssize_t protkey_aes_xts_256_read(struct file *filp,
+                                       struct kobject *kobj,
+                                       struct bin_attribute *attr,
+                                       char *buf, loff_t off,
+                                       size_t count)
+{
+       return pkey_protkey_aes_xts_attr_read(PKEY_KEYTYPE_AES_XTS_256,
+                                             buf, off, count);
+}
+
+static ssize_t protkey_hmac_512_read(struct file *filp,
+                                    struct kobject *kobj,
+                                    struct bin_attribute *attr,
+                                    char *buf, loff_t off,
+                                    size_t count)
+{
+       return pkey_protkey_hmac_attr_read(PKEY_KEYTYPE_HMAC_512,
+                                          buf, off, count);
+}
+
+static ssize_t protkey_hmac_1024_read(struct file *filp,
+                                     struct kobject *kobj,
+                                     struct bin_attribute *attr,
+                                     char *buf, loff_t off,
+                                     size_t count)
+{
+       return pkey_protkey_hmac_attr_read(PKEY_KEYTYPE_HMAC_1024,
+                                          buf, off, count);
+}
+
 static BIN_ATTR_RO(protkey_aes_128, sizeof(struct protaeskeytoken));
 static BIN_ATTR_RO(protkey_aes_192, sizeof(struct protaeskeytoken));
 static BIN_ATTR_RO(protkey_aes_256, sizeof(struct protaeskeytoken));
 static BIN_ATTR_RO(protkey_aes_128_xts, 2 * sizeof(struct protaeskeytoken));
 static BIN_ATTR_RO(protkey_aes_256_xts, 2 * sizeof(struct protaeskeytoken));
+static BIN_ATTR_RO(protkey_aes_xts_128, sizeof(struct protkeytoken) + 64);
+static BIN_ATTR_RO(protkey_aes_xts_256, sizeof(struct protkeytoken) + 96);
+static BIN_ATTR_RO(protkey_hmac_512, sizeof(struct protkeytoken) + 96);
+static BIN_ATTR_RO(protkey_hmac_1024, sizeof(struct protkeytoken) + 160);
 
 static struct bin_attribute *protkey_attrs[] = {
        &bin_attr_protkey_aes_128,
@@ -161,6 +289,10 @@ static struct bin_attribute *protkey_attrs[] = {
        &bin_attr_protkey_aes_256,
        &bin_attr_protkey_aes_128_xts,
        &bin_attr_protkey_aes_256_xts,
+       &bin_attr_protkey_aes_xts_128,
+       &bin_attr_protkey_aes_xts_256,
+       &bin_attr_protkey_hmac_512,
+       &bin_attr_protkey_hmac_1024,
        NULL
 };