Support the subfuctions PCKMO-Encrypt-AES-128-Key, PCKMO-Encrypt-AES-192-Key and PCKMO-Encrypt-AES-256-Key.
These subfunctions derive a protected key from an AES clear key by encrypting it with an internal AES wrapping key. More details can be found in the "z/Architecture Prinziples of Operation" document. The qemu version provided here is only a fake indented to make protected key available for developing and testing purpose: * The protected key is 'derived' from the clear key by xoring the fixed pattern 0xAAAA... onto the key value. * The AES Wrapping Key Verification Pattern is a fixed value of 32 bytes 0xFACEFACE... Signed-off-by: Harald Freudenberger <[email protected]> --- target/s390x/gen-features.c | 3 ++ target/s390x/tcg/cpacf.h | 2 + target/s390x/tcg/cpacf_aes.c | 65 ++++++++++++++++++++++++++++++++ target/s390x/tcg/crypto_helper.c | 20 ++++++++++ 4 files changed, 90 insertions(+) diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index f9b1a40c7c..d3e69aaca6 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -934,6 +934,9 @@ static uint16_t qemu_MAX[] = { S390_FEAT_KMCTR_AES_256, S390_FEAT_PCC_XTS_AES_128, S390_FEAT_PCC_XTS_AES_256, + S390_FEAT_PCKMO_AES_128, + S390_FEAT_PCKMO_AES_192, + S390_FEAT_PCKMO_AES_256, }; /****** END FEATURE DEFS ******/ diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h index 8c1dbee67f..2617cbed80 100644 --- a/target/s390x/tcg/cpacf.h +++ b/target/s390x/tcg/cpacf.h @@ -31,5 +31,7 @@ int cpacf_aes_pcc(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, int cpacf_aes_xts(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, uint64_t *dst_ptr, uint64_t *src_ptr, uint64_t *src_len, uint32_t type, uint8_t fc, uint8_t mod); +int cpacf_aes_pckmo(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, + uint8_t fc); #endif diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c index f067939f25..a53ef93635 100644 --- a/target/s390x/tcg/cpacf_aes.c +++ b/target/s390x/tcg/cpacf_aes.c @@ -449,3 +449,68 @@ int cpacf_aes_xts(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, return !len ? 0 : 3; } + +/* + * Hard coded pattern xored with the AES clear key + * to 'produce' the protected key. + */ +static const uint8_t protkey_xor_pattern[32] = { + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }; + +/* + * Hard coded wkvp ("Wrapping Key Verification Pattern") + */ +static const uint8_t protkey_wkvp[32] = { + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E, + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E, + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E, + 0x0F, 0x0A, 0x0C, 0x0E, 0x0F, 0x0A, 0x0C, 0x0E }; + +int cpacf_aes_pckmo(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, + uint8_t fc) +{ + uint8_t key[32]; + int keysize, i; + uint64_t addr; + + switch (fc) { + case 0x12: /* CPACF_PCKMO_ENC_AES_128_KEY */ + keysize = 16; + break; + case 0x13: /* CPACF_PCKMO_ENC_AES_192_KEY */ + keysize = 24; + break; + case 0x14: /* CPACF_PCKMO_ENC_AES_256_KEY */ + keysize = 32; + break; + default: + g_assert_not_reached(); + } + + /* fetch key from param block */ + for (i = 0; i < keysize; i++) { + addr = wrap_address(env, param_addr + i); + key[i] = cpu_ldub_data_ra(env, addr, ra); + } + + /* 'derive' the protected key */ + for (i = 0; i < keysize; i++) { + key[i] ^= protkey_xor_pattern[i]; + } + + /* store the protected key into param block */ + for (i = 0; i < keysize; i++) { + addr = wrap_address(env, param_addr + i); + cpu_stb_data_ra(env, addr, key[i], ra); + } + /* followed by the fake wkvp */ + for (i = 0; i < sizeof(protkey_wkvp); i++) { + addr = wrap_address(env, param_addr + keysize + i); + cpu_stb_data_ra(env, addr, protkey_wkvp[i], ra); + } + + return 0; +} diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 7129b38703..8d1070ec89 100644 --- a/target/s390x/tcg/crypto_helper.c +++ b/target/s390x/tcg/crypto_helper.c @@ -187,6 +187,23 @@ static int cpacf_pcc(CPUS390XState *env, uintptr_t ra, uint8_t fc) return rc; } +static int cpacf_pckmo(CPUS390XState *env, uintptr_t ra, uint8_t fc) +{ + int rc = 0; + + switch (fc) { + case 0x12: /* CPACF_PCKMO_ENC_AES_128_KEY */ + case 0x13: /* CPACF_PCKMO_ENC_AES_192_KEY */ + case 0x14: /* CPACF_PCKMO_ENC_AES_256_KEY */ + rc = cpacf_aes_pckmo(env, ra, env->regs[1], fc); + break; + default: + g_assert_not_reached(); + } + + return rc; +} + uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, uint32_t type) { @@ -246,6 +263,9 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, case S390_FEAT_TYPE_PCC: rc = cpacf_pcc(env, ra, fc); break; + case S390_FEAT_TYPE_PCKMO: + rc = cpacf_pckmo(env, ra, fc); + break; default: g_assert_not_reached(); } -- 2.43.0
