diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h index 04183080cdbb..60431d00e6bd 100644 --- a/arch/s390/include/uapi/asm/pkey.h +++ b/arch/s390/include/uapi/asm/pkey.h @@ -41,6 +41,10 @@ #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 { diff --git a/drivers/s390/crypto/pkey_base.h b/drivers/s390/crypto/pkey_base.h index fd151903fd06..7a1a5ce192d8 100644 --- a/drivers/s390/crypto/pkey_base.h +++ b/drivers/s390/crypto/pkey_base.h @@ -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[] */ diff --git a/drivers/s390/crypto/pkey_pckmo.c b/drivers/s390/crypto/pkey_pckmo.c index 0667e5510671..98079b1ed6db 100644 --- a/drivers/s390/crypto/pkey_pckmo.c +++ b/drivers/s390/crypto/pkey_pckmo.c @@ -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) { diff --git a/drivers/s390/crypto/pkey_sysfs.c b/drivers/s390/crypto/pkey_sysfs.c index 56205f53f77b..cc0fc1e264bd 100644 --- a/drivers/s390/crypto/pkey_sysfs.c +++ b/drivers/s390/crypto/pkey_sysfs.c @@ -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 };