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 <freude@linux.ibm.com>
---
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