diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-18 17:45:41 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-18 17:45:41 -0800 |
commit | 0338cd9c22d1bce7dc4a6641d4215a50f476f429 (patch) | |
tree | 22d500d5d8bd2c04fe6ae2be3d6cd7e12a755f09 /drivers/s390/crypto | |
parent | 5591fd5e034819a89ac93c0ccc6be2a930042f71 (diff) | |
parent | e200565d434b66e5b2bfc3b143b66b8ca29666ad (diff) | |
download | linux-0338cd9c22d1bce7dc4a6641d4215a50f476f429.tar.gz linux-0338cd9c22d1bce7dc4a6641d4215a50f476f429.tar.bz2 linux-0338cd9c22d1bce7dc4a6641d4215a50f476f429.zip |
Merge tag 's390-6.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Heiko Carstens:
- Add firmware sysfs interface which allows user space to retrieve the
dump area size of the machine
- Add 'measurement_chars_full' CHPID sysfs attribute to make the
complete associated Channel-Measurements Characteristics Block
available
- Add virtio-mem support
- Move gmap aka KVM page fault handling from the main fault handler to
KVM code. This is the first step to make s390 KVM page fault handling
similar to other architectures. With this first step the main fault
handler does not have any special handling anymore, and therefore
convert it to support LOCK_MM_AND_FIND_VMA
- With gcc 14 s390 support for flag output operand support for inline
assemblies was added. This allows for several optimizations:
- Provide a cmpxchg inline assembly which makes use of this, and
provide all variants of arch_try_cmpxchg() so that the compiler
can generate slightly better code
- Convert a few cmpxchg() loops to try_cmpxchg() loops
- Similar to x86 add a CC_OUT() helper macro (and other macros),
and convert all inline assemblies to make use of them, so that
depending on compiler version better code can be generated
- List installed host-key hashes in sysfs if the machine supports the
Query Ultravisor Keys UVC
- Add 'Retrieve Secret' ioctl which allows user space in protected
execution guests to retrieve previously stored secrets from the
Ultravisor
- Add pkey-uv module which supports the conversion of Ultravisor
retrievable secrets to protected keys
- Extend the existing paes cipher to exploit the full AES-XTS hardware
acceleration introduced with message-security assist extension 10
- Convert hopefully all sysfs show functions to use sysfs_emit() so
that the constant flow of such patches stop
- For PCI devices make use of the newly added Topology ID attribute to
enable whole card multi-function support despite the change to PCHID
per port. Additionally improve the overall robustness and usability
of the multifunction support
- Various other small improvements, fixes, and cleanups
* tag 's390-6.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (133 commits)
s390/cio/ioasm: Convert to use flag output macros
s390/cio/qdio: Convert to use flag output macros
s390/sclp: Convert to use flag output macros
s390/dasd: Convert to use flag output macros
s390/boot/physmem: Convert to use flag output macros
s390/pci: Convert to use flag output macros
s390/kvm: Convert to use flag output macros
s390/extmem: Convert to use flag output macros
s390/string: Convert to use flag output macros
s390/diag: Convert to use flag output macros
s390/irq: Convert to use flag output macros
s390/smp: Convert to use flag output macros
s390/uv: Convert to use flag output macros
s390/pai: Convert to use flag output macros
s390/mm: Convert to use flag output macros
s390/cpu_mf: Convert to use flag output macros
s390/cpcmd: Convert to use flag output macros
s390/topology: Convert to use flag output macros
s390/time: Convert to use flag output macros
s390/pageattr: Convert to use flag output macros
...
Diffstat (limited to 'drivers/s390/crypto')
-rw-r--r-- | drivers/s390/crypto/Makefile | 4 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_base.c | 14 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_base.h | 36 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_cca.c | 5 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_ep11.c | 1 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_pckmo.c | 239 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_sysfs.c | 1 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_uv.c | 284 | ||||
-rw-r--r-- | drivers/s390/crypto/vfio_ap_ops.c | 45 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_ccamisc.h | 1 |
10 files changed, 428 insertions, 202 deletions
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index c88b6e071847..e83c6603c858 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -29,6 +29,10 @@ obj-$(CONFIG_PKEY_EP11) += pkey-ep11.o pkey-pckmo-objs := pkey_pckmo.o obj-$(CONFIG_PKEY_PCKMO) += pkey-pckmo.o +# pkey uv handler module +pkey-uv-objs := pkey_uv.o +obj-$(CONFIG_PKEY_UV) += pkey-uv.o + # adjunct processor matrix vfio_ap-objs := vfio_ap_drv.o vfio_ap_ops.o obj-$(CONFIG_VFIO_AP) += vfio_ap.o diff --git a/drivers/s390/crypto/pkey_base.c b/drivers/s390/crypto/pkey_base.c index fea243322838..64a376501d26 100644 --- a/drivers/s390/crypto/pkey_base.c +++ b/drivers/s390/crypto/pkey_base.c @@ -304,7 +304,19 @@ void pkey_handler_request_modules(void) { #ifdef CONFIG_MODULES static const char * const pkey_handler_modules[] = { - "pkey_cca", "pkey_ep11", "pkey_pckmo" }; +#if IS_MODULE(CONFIG_PKEY_CCA) + "pkey_cca", +#endif +#if IS_MODULE(CONFIG_PKEY_EP11) + "pkey_ep11", +#endif +#if IS_MODULE(CONFIG_PKEY_PCKMO) + "pkey_pckmo", +#endif +#if IS_MODULE(CONFIG_PKEY_UV) + "pkey_uv", +#endif + }; int i; for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) { diff --git a/drivers/s390/crypto/pkey_base.h b/drivers/s390/crypto/pkey_base.h index 7a1a5ce192d8..7347647dfaa7 100644 --- a/drivers/s390/crypto/pkey_base.h +++ b/drivers/s390/crypto/pkey_base.h @@ -97,6 +97,42 @@ static inline u32 pkey_aes_bitsize_to_keytype(u32 keybitsize) } /* + * helper function which translates the PKEY_KEYTYPE_* + * to the protected key size minus the WK VP length + */ +static inline u32 pkey_keytype_to_size(u32 keytype) +{ + switch (keytype) { + case PKEY_KEYTYPE_AES_128: + return 16; + case PKEY_KEYTYPE_AES_192: + return 24; + case PKEY_KEYTYPE_AES_256: + return 32; + case PKEY_KEYTYPE_ECC_P256: + return 32; + case PKEY_KEYTYPE_ECC_P384: + return 48; + case PKEY_KEYTYPE_ECC_P521: + return 80; + case PKEY_KEYTYPE_ECC_ED25519: + return 32; + case PKEY_KEYTYPE_ECC_ED448: + return 54; + case PKEY_KEYTYPE_AES_XTS_128: + return 32; + case PKEY_KEYTYPE_AES_XTS_256: + return 64; + case PKEY_KEYTYPE_HMAC_512: + return 64; + case PKEY_KEYTYPE_HMAC_1024: + return 128; + default: + return 0; + } +} + +/* * pkey_api.c: */ int __init pkey_api_init(void); diff --git a/drivers/s390/crypto/pkey_cca.c b/drivers/s390/crypto/pkey_cca.c index 937051381720..cda22db31f6c 100644 --- a/drivers/s390/crypto/pkey_cca.c +++ b/drivers/s390/crypto/pkey_cca.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/cpufeature.h> -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "pkey_base.h" @@ -225,14 +224,14 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_AES) { /* CCA AES data key */ - if (keylen != sizeof(struct secaeskeytoken)) + if (keylen < sizeof(struct secaeskeytoken)) return -EINVAL; if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0)) return -EINVAL; } else if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_VLSC) { /* CCA AES cipher key */ - if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + if (keylen < hdr->len) return -EINVAL; if (cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1)) diff --git a/drivers/s390/crypto/pkey_ep11.c b/drivers/s390/crypto/pkey_ep11.c index f42d397a9cb6..5b033ca3e828 100644 --- a/drivers/s390/crypto/pkey_ep11.c +++ b/drivers/s390/crypto/pkey_ep11.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/cpufeature.h> -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "zcrypt_ep11misc.h" #include "pkey_base.h" diff --git a/drivers/s390/crypto/pkey_pckmo.c b/drivers/s390/crypto/pkey_pckmo.c index beeca8827c46..835d59f4fbc5 100644 --- a/drivers/s390/crypto/pkey_pckmo.c +++ b/drivers/s390/crypto/pkey_pckmo.c @@ -15,7 +15,6 @@ #include <crypto/aes.h> #include <linux/random.h> -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "pkey_base.h" @@ -38,23 +37,9 @@ static bool is_pckmo_key(const u8 *key, u32 keylen) case TOKTYPE_NON_CCA: switch (hdr->version) { case TOKVER_CLEAR_KEY: - switch (t->keytype) { - case PKEY_KEYTYPE_AES_128: - case PKEY_KEYTYPE_AES_192: - case PKEY_KEYTYPE_AES_256: - case PKEY_KEYTYPE_ECC_P256: - case PKEY_KEYTYPE_ECC_P384: - 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: + if (pkey_keytype_to_size(t->keytype)) return true; - default: - return false; - } + return false; case TOKVER_PROTECTED_KEY: return true; default: @@ -86,80 +71,49 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, int keysize, rc = -EINVAL; u8 paramblock[160]; - u32 pkeytype; - long fc; + u32 pkeytype = 0; + unsigned int fc; switch (keytype) { case PKEY_KEYTYPE_AES_128: - /* 16 byte key, 32 byte aes wkvp, total 48 bytes */ - keysize = 16; - pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_128_KEY; break; case PKEY_KEYTYPE_AES_192: - /* 24 byte key, 32 byte aes wkvp, total 56 bytes */ - keysize = 24; - pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_192_KEY; break; case PKEY_KEYTYPE_AES_256: - /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; - pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_256_KEY; break; case PKEY_KEYTYPE_ECC_P256: - /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_P256_KEY; break; case PKEY_KEYTYPE_ECC_P384: - /* 48 byte key, 32 byte aes wkvp, total 80 bytes */ - keysize = 48; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_P384_KEY; break; case PKEY_KEYTYPE_ECC_P521: - /* 80 byte key, 32 byte aes wkvp, total 112 bytes */ - keysize = 80; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_P521_KEY; break; case PKEY_KEYTYPE_ECC_ED25519: - /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_ED25519_KEY; break; case PKEY_KEYTYPE_ECC_ED448: - /* 64 byte key, 32 byte aes wkvp, total 96 bytes */ - keysize = 64; 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: @@ -168,6 +122,9 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, goto out; } + keysize = pkey_keytype_to_size(keytype); + pkeytype = pkeytype ?: keytype; + if (clrkeylen && clrkeylen < keysize) { PKEY_DBF_ERR("%s clear key size too small: %u < %d\n", __func__, clrkeylen, keysize); @@ -190,7 +147,8 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, } /* check for the pckmo subfunction we need now */ if (!cpacf_test_func(&pckmo_functions, fc)) { - PKEY_DBF_ERR("%s pckmo functions not available\n", __func__); + PKEY_DBF_ERR("%s pckmo fc 0x%02x not available\n", + __func__, fc); rc = -ENODEV; goto out; } @@ -216,60 +174,42 @@ out: /* * Verify a raw protected key blob. - * Currently only AES protected keys are supported. */ static int pckmo_verify_protkey(const u8 *protkey, u32 protkeylen, u32 protkeytype) { - 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, pkeylen; - unsigned long fc; - int rc = -EINVAL; + u8 clrkey[16] = { 0 }, tmpkeybuf[16 + AES_WK_VP_SIZE]; + u32 tmpkeybuflen, tmpkeytype; + int keysize, rc = -EINVAL; + u8 *wkvp; - switch (protkeytype) { - case PKEY_KEYTYPE_AES_128: - pkeylen = 16 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_128; - break; - case PKEY_KEYTYPE_AES_192: - pkeylen = 24 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_192; - break; - case PKEY_KEYTYPE_AES_256: - pkeylen = 32 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_256; - break; - default: + /* check protkey type and size */ + keysize = pkey_keytype_to_size(protkeytype); + if (!keysize) { PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", __func__, protkeytype); goto out; } - if (protkeylen != pkeylen) { - PKEY_DBF_ERR("%s invalid protected key size %u for keytype %u\n", - __func__, protkeylen, protkeytype); + if (protkeylen < keysize + AES_WK_VP_SIZE) goto out; - } - - memset(null_msg, 0, sizeof(null_msg)); - memset(param.iv, 0, sizeof(param.iv)); - memcpy(param.key, protkey, protkeylen); + /* generate a dummy AES 128 protected key */ + tmpkeybuflen = sizeof(tmpkeybuf); + rc = pckmo_clr2protkey(PKEY_KEYTYPE_AES_128, + clrkey, sizeof(clrkey), + tmpkeybuf, &tmpkeybuflen, &tmpkeytype); + if (rc) + goto out; + memzero_explicit(tmpkeybuf, 16); + wkvp = tmpkeybuf + 16; - k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf, - sizeof(null_msg)); - if (k != sizeof(null_msg)) { - PKEY_DBF_ERR("%s protected key is not valid\n", __func__); + /* compare WK VP from the temp key with that of the given prot key */ + if (memcmp(wkvp, protkey + keysize, AES_WK_VP_SIZE)) { + PKEY_DBF_ERR("%s protected key WK VP mismatch\n", __func__); rc = -EKEYREJECTED; goto out; } - rc = 0; - out: pr_debug("rc=%d\n", rc); return rc; @@ -289,37 +229,33 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen, switch (hdr->version) { case TOKVER_PROTECTED_KEY: { struct protkeytoken *t = (struct protkeytoken *)key; + u32 keysize; if (keylen < sizeof(*t)) goto out; + keysize = pkey_keytype_to_size(t->keytype); + if (!keysize) { + PKEY_DBF_ERR("%s protected key token: unknown keytype %u\n", + __func__, t->keytype); + goto out; + } switch (t->keytype) { case PKEY_KEYTYPE_AES_128: case PKEY_KEYTYPE_AES_192: case PKEY_KEYTYPE_AES_256: - if (keylen != sizeof(struct protaeskeytoken)) + if (t->len != keysize + AES_WK_VP_SIZE || + 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) + default: + if (t->len != keysize + AES_WK_VP_SIZE || + keylen < sizeof(*t) + keysize + AES_WK_VP_SIZE) 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; @@ -329,47 +265,12 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen, } case TOKVER_CLEAR_KEY: { struct clearkeytoken *t = (struct clearkeytoken *)key; - u32 keysize = 0; + u32 keysize; - if (keylen < sizeof(struct clearkeytoken) || - keylen != sizeof(*t) + t->len) + if (keylen < sizeof(*t) || + keylen < sizeof(*t) + t->len) goto out; - switch (t->keytype) { - case PKEY_KEYTYPE_AES_128: - case PKEY_KEYTYPE_AES_192: - case PKEY_KEYTYPE_AES_256: - keysize = pkey_keytype_aes_to_size(t->keytype); - break; - case PKEY_KEYTYPE_ECC_P256: - keysize = 32; - break; - case PKEY_KEYTYPE_ECC_P384: - keysize = 48; - break; - case PKEY_KEYTYPE_ECC_P521: - keysize = 80; - break; - case PKEY_KEYTYPE_ECC_ED25519: - keysize = 32; - break; - 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; - } + keysize = pkey_keytype_to_size(t->keytype); if (!keysize) { PKEY_DBF_ERR("%s clear key token: unknown keytype %u\n", __func__, t->keytype); @@ -397,8 +298,6 @@ out: /* * Generate a random protected key. - * Currently only the generation of AES protected keys - * is supported. */ static int pckmo_gen_protkey(u32 keytype, u32 subtype, u8 *protkey, u32 *protkeylen, u32 *protkeytype) @@ -407,32 +306,32 @@ static int pckmo_gen_protkey(u32 keytype, u32 subtype, int keysize; int rc; + keysize = pkey_keytype_to_size(keytype); + if (!keysize) { + PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", + __func__, keytype); + return -EINVAL; + } + if (subtype != PKEY_TYPE_PROTKEY) { + PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n", + __func__, subtype); + return -EINVAL; + } + 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", + PKEY_DBF_ERR("%s unsupported keytype %d\n", __func__, keytype); return -EINVAL; } - if (subtype != PKEY_TYPE_PROTKEY) { - PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n", - __func__, subtype); - return -EINVAL; - } /* generate a dummy random clear key */ get_random_bytes(clrkey, keysize); @@ -453,7 +352,6 @@ out: /* * Verify a protected key token blob. - * Currently only AES protected keys are supported. */ static int pckmo_verify_key(const u8 *key, u32 keylen) { @@ -467,11 +365,26 @@ static int pckmo_verify_key(const u8 *key, u32 keylen) switch (hdr->version) { case TOKVER_PROTECTED_KEY: { - struct protaeskeytoken *t; + struct protkeytoken *t = (struct protkeytoken *)key; + u32 keysize; - if (keylen != sizeof(struct protaeskeytoken)) + if (keylen < sizeof(*t)) + goto out; + keysize = pkey_keytype_to_size(t->keytype); + if (!keysize || t->len != keysize + AES_WK_VP_SIZE) goto out; - t = (struct protaeskeytoken *)key; + 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; + break; + default: + if (keylen < sizeof(*t) + keysize + AES_WK_VP_SIZE) + goto out; + break; + } rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); break; } diff --git a/drivers/s390/crypto/pkey_sysfs.c b/drivers/s390/crypto/pkey_sysfs.c index cc0fc1e264bd..a4eb45803f5e 100644 --- a/drivers/s390/crypto/pkey_sysfs.c +++ b/drivers/s390/crypto/pkey_sysfs.c @@ -10,7 +10,6 @@ #include <linux/sysfs.h> -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "zcrypt_ep11misc.h" diff --git a/drivers/s390/crypto/pkey_uv.c b/drivers/s390/crypto/pkey_uv.c new file mode 100644 index 000000000000..805817b14354 --- /dev/null +++ b/drivers/s390/crypto/pkey_uv.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pkey uv specific code + * + * Copyright IBM Corp. 2024 + */ + +#define KMSG_COMPONENT "pkey" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/cpufeature.h> +#include <linux/init.h> +#include <linux/module.h> +#include <asm/uv.h> + +#include "zcrypt_ccamisc.h" +#include "pkey_base.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("s390 protected key UV handler"); + +/* + * UV secret token struct and defines. + */ + +#define TOKVER_UV_SECRET 0x09 + +struct uvsecrettoken { + u8 type; /* 0x00 = TOKTYPE_NON_CCA */ + u8 res0[3]; + u8 version; /* 0x09 = TOKVER_UV_SECRET */ + u8 res1[3]; + u16 secret_type; /* one of enum uv_secret_types from uv.h */ + u16 secret_len; /* length in bytes of the secret */ + u8 secret_id[UV_SECRET_ID_LEN]; /* the secret id for this secret */ +} __packed; + +/* + * Check key blob for known and supported UV key. + */ +static bool is_uv_key(const u8 *key, u32 keylen) +{ + struct uvsecrettoken *t = (struct uvsecrettoken *)key; + + if (keylen < sizeof(*t)) + return false; + + switch (t->type) { + case TOKTYPE_NON_CCA: + switch (t->version) { + case TOKVER_UV_SECRET: + switch (t->secret_type) { + case UV_SECRET_AES_128: + case UV_SECRET_AES_192: + case UV_SECRET_AES_256: + case UV_SECRET_AES_XTS_128: + case UV_SECRET_AES_XTS_256: + case UV_SECRET_HMAC_SHA_256: + case UV_SECRET_HMAC_SHA_512: + case UV_SECRET_ECDSA_P256: + case UV_SECRET_ECDSA_P384: + case UV_SECRET_ECDSA_P521: + case UV_SECRET_ECDSA_ED25519: + case UV_SECRET_ECDSA_ED448: + return true; + default: + return false; + } + default: + return false; + } + default: + return false; + } +} + +static bool is_uv_keytype(enum pkey_key_type keytype) +{ + switch (keytype) { + case PKEY_TYPE_UVSECRET: + return true; + default: + return false; + } +} + +static int retrieve_secret(const u8 secret_id[UV_SECRET_ID_LEN], + u16 *secret_type, u8 *buf, u32 *buflen) +{ + struct uv_secret_list_item_hdr secret_meta_data; + int rc; + + rc = uv_get_secret_metadata(secret_id, &secret_meta_data); + if (rc) + return rc; + + if (*buflen < secret_meta_data.length) + return -EINVAL; + + rc = uv_retrieve_secret(secret_meta_data.index, + buf, secret_meta_data.length); + if (rc) + return rc; + + *secret_type = secret_meta_data.type; + *buflen = secret_meta_data.length; + + return 0; +} + +static int uv_get_size_and_type(u16 secret_type, u32 *pkeysize, u32 *pkeytype) +{ + int rc = 0; + + switch (secret_type) { + case UV_SECRET_AES_128: + *pkeysize = 16 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_128; + break; + case UV_SECRET_AES_192: + *pkeysize = 24 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_192; + break; + case UV_SECRET_AES_256: + *pkeysize = 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_256; + break; + case UV_SECRET_AES_XTS_128: + *pkeysize = 16 + 16 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_XTS_128; + break; + case UV_SECRET_AES_XTS_256: + *pkeysize = 32 + 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_XTS_256; + break; + case UV_SECRET_HMAC_SHA_256: + *pkeysize = 64 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_HMAC_512; + break; + case UV_SECRET_HMAC_SHA_512: + *pkeysize = 128 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_HMAC_1024; + break; + case UV_SECRET_ECDSA_P256: + *pkeysize = 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_P256; + break; + case UV_SECRET_ECDSA_P384: + *pkeysize = 48 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_P384; + break; + case UV_SECRET_ECDSA_P521: + *pkeysize = 80 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_P521; + break; + case UV_SECRET_ECDSA_ED25519: + *pkeysize = 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_ED25519; + break; + case UV_SECRET_ECDSA_ED448: + *pkeysize = 64 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_ED448; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static int uv_key2protkey(const struct pkey_apqn *_apqns __always_unused, + size_t _nr_apqns __always_unused, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *keyinfo) +{ + struct uvsecrettoken *t = (struct uvsecrettoken *)key; + u32 pkeysize, pkeytype; + u16 secret_type; + int rc; + + rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype); + if (rc) + goto out; + + if (*protkeylen < pkeysize) { + PKEY_DBF_ERR("%s prot key buffer size too small: %u < %u\n", + __func__, *protkeylen, pkeysize); + rc = -EINVAL; + goto out; + } + + rc = retrieve_secret(t->secret_id, &secret_type, protkey, protkeylen); + if (rc) { + PKEY_DBF_ERR("%s retrieve_secret() failed with %d\n", + __func__, rc); + goto out; + } + if (secret_type != t->secret_type) { + PKEY_DBF_ERR("%s retrieved secret type %u != expected type %u\n", + __func__, secret_type, t->secret_type); + rc = -EINVAL; + goto out; + } + + if (keyinfo) + *keyinfo = pkeytype; + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +static int uv_verifykey(const u8 *key, u32 keylen, + u16 *_card __always_unused, + u16 *_dom __always_unused, + u32 *keytype, u32 *keybitsize, u32 *flags) +{ + struct uvsecrettoken *t = (struct uvsecrettoken *)key; + struct uv_secret_list_item_hdr secret_meta_data; + u32 pkeysize, pkeytype, bitsize; + int rc; + + rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype); + if (rc) + goto out; + + rc = uv_get_secret_metadata(t->secret_id, &secret_meta_data); + if (rc) + goto out; + + if (secret_meta_data.type != t->secret_type) { + rc = -EINVAL; + goto out; + } + + /* set keytype; keybitsize and flags are not supported */ + if (keytype) + *keytype = PKEY_TYPE_UVSECRET; + if (keybitsize) { + bitsize = 8 * pkey_keytype_to_size(pkeytype); + *keybitsize = bitsize ?: PKEY_SIZE_UNKNOWN; + } + if (flags) + *flags = pkeytype; + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +static struct pkey_handler uv_handler = { + .module = THIS_MODULE, + .name = "PKEY UV handler", + .is_supported_key = is_uv_key, + .is_supported_keytype = is_uv_keytype, + .key_to_protkey = uv_key2protkey, + .verify_key = uv_verifykey, +}; + +/* + * Module init + */ +static int __init pkey_uv_init(void) +{ + if (!is_prot_virt_guest()) + return -ENODEV; + + if (!test_bit_inv(BIT_UVC_CMD_RETR_SECRET, uv_info.inst_calls_list)) + return -ENODEV; + + return pkey_handler_register(&uv_handler); +} + +/* + * Module exit + */ +static void __exit pkey_uv_exit(void) +{ + pkey_handler_unregister(&uv_handler); +} + +module_cpu_feature_match(S390_CPU_FEATURE_UV, pkey_uv_init); +module_exit(pkey_uv_exit); diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 9f76f2d7b66e..8c0b40d8eb39 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -1521,18 +1521,13 @@ static ssize_t control_domains_show(struct device *dev, char *buf) { unsigned long id; - int nchars = 0; - int n; - char *bufpos = buf; struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev); unsigned long max_domid = matrix_mdev->matrix.adm_max; + int nchars = 0; mutex_lock(&matrix_dev->mdevs_lock); - for_each_set_bit_inv(id, matrix_mdev->matrix.adm, max_domid + 1) { - n = sprintf(bufpos, "%04lx\n", id); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(id, matrix_mdev->matrix.adm, max_domid + 1) + nchars += sysfs_emit_at(buf, nchars, "%04lx\n", id); mutex_unlock(&matrix_dev->mdevs_lock); return nchars; @@ -1541,7 +1536,6 @@ static DEVICE_ATTR_RO(control_domains); static ssize_t vfio_ap_mdev_matrix_show(struct ap_matrix *matrix, char *buf) { - char *bufpos = buf; unsigned long apid; unsigned long apqi; unsigned long apid1; @@ -1549,33 +1543,21 @@ static ssize_t vfio_ap_mdev_matrix_show(struct ap_matrix *matrix, char *buf) unsigned long napm_bits = matrix->apm_max + 1; unsigned long naqm_bits = matrix->aqm_max + 1; int nchars = 0; - int n; apid1 = find_first_bit_inv(matrix->apm, napm_bits); apqi1 = find_first_bit_inv(matrix->aqm, naqm_bits); if ((apid1 < napm_bits) && (apqi1 < naqm_bits)) { for_each_set_bit_inv(apid, matrix->apm, napm_bits) { - for_each_set_bit_inv(apqi, matrix->aqm, - naqm_bits) { - n = sprintf(bufpos, "%02lx.%04lx\n", apid, - apqi); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(apqi, matrix->aqm, naqm_bits) + nchars += sysfs_emit_at(buf, nchars, "%02lx.%04lx\n", apid, apqi); } } else if (apid1 < napm_bits) { - for_each_set_bit_inv(apid, matrix->apm, napm_bits) { - n = sprintf(bufpos, "%02lx.\n", apid); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(apid, matrix->apm, napm_bits) + nchars += sysfs_emit_at(buf, nchars, "%02lx.\n", apid); } else if (apqi1 < naqm_bits) { - for_each_set_bit_inv(apqi, matrix->aqm, naqm_bits) { - n = sprintf(bufpos, ".%04lx\n", apqi); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(apqi, matrix->aqm, naqm_bits) + nchars += sysfs_emit_at(buf, nchars, ".%04lx\n", apqi); } return nchars; @@ -2263,14 +2245,11 @@ static ssize_t status_show(struct device *dev, if (matrix_mdev->kvm && test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) && test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) - nchars = scnprintf(buf, PAGE_SIZE, "%s\n", - AP_QUEUE_IN_USE); + nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_IN_USE); else - nchars = scnprintf(buf, PAGE_SIZE, "%s\n", - AP_QUEUE_ASSIGNED); + nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_ASSIGNED); } else { - nchars = scnprintf(buf, PAGE_SIZE, "%s\n", - AP_QUEUE_UNASSIGNED); + nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_UNASSIGNED); } mutex_unlock(&matrix_dev->mdevs_lock); diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index aed7e8384542..26bdca702523 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -12,6 +12,7 @@ #include <asm/zcrypt.h> #include <asm/pkey.h> +#include "zcrypt_api.h" /* Key token types */ #define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */ |