RE: [PATCH v2 02/17] tests/qtest/aspeed-hace: Test the crypto command on the AST2500
Kane Chen <[email protected]>
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <SI6PR06MB763127262D85DFD67755C7A1F7DE2@SI6PR06MB7631.apcprd06.prod.outlook.com> |
> -----Original Message----- > From: Jamin Lin <[email protected]> > Sent: Wednesday, July 15, 2026 11:33 AM > To: Daniel P. Berrangé <[email protected]>; Cédric Le Goater > <[email protected]>; Peter Maydell <[email protected]>; Steven Lee > <[email protected]>; Troy Lee <[email protected]>; Kane Chen > <[email protected]>; Andrew Jeffery > <[email protected]>; Joel Stanley <[email protected]>; Eric Blake > <[email protected]>; Markus Armbruster <[email protected]>; Fabiano > Rosas <[email protected]>; Laurent Vivier <[email protected]>; Paolo Bonzini > <[email protected]>; open list:All patches CC here > <[email protected]>; open list:ASPEED BMCs > <[email protected]> > Cc: Jamin Lin <[email protected]>; Troy Lee > <[email protected]> > Subject: [PATCH v2 02/17] tests/qtest/aspeed-hace: Test the crypto command > on the AST2500 > > Add a crypto known-answer test harness and exercise the AST2500, which uses > the crypto engine's direct access mode. Each mode (AES/DES/3DES in ECB and > CBC) is a separate test that checks the ciphertext, the plaintext round-trip and, > for CBC, the chaining IV written back to the context buffer. > > The key/IV/plaintext/ciphertext values are taken verbatim from the Linux > kernel crypto self-test templates in crypto/testmgr.h. > > Signed-off-by: Jamin Lin <[email protected]> > --- > tests/qtest/aspeed-hace-utils.h | 16 ++ tests/qtest/aspeed-hace-utils.c | > 325 ++++++++++++++++++++++++++++++++ > tests/qtest/aspeed_hace-test.c | 6 + > tests/qtest/meson.build | 6 +- > 4 files changed, 351 insertions(+), 2 deletions(-) > > diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h > index 27ab2bb975..13feaa61e4 100644 > --- a/tests/qtest/aspeed-hace-utils.h > +++ b/tests/qtest/aspeed-hace-utils.h > @@ -79,5 +79,21 @@ void aspeed_test_sha512_accum(const char *machine, > const uint32_t base, void aspeed_test_addresses(const char *machine, const > uint32_t base, > const struct AspeedMasks *expected); > > +/* > + * Cipher modes a SoC's crypto engine supports, for > aspeed_add_crypto_tests(). > + */ > +enum { > + CRYPT_MODE_ECB = 1 << 0, > + CRYPT_MODE_CBC = 1 << 1, > +}; > + > +/* > + * Register the crypto known-answer tests that @modes selects (a mask > +of > + * CRYPT_MODE_*) for the given machine. Each test is named > + * "<prefix>/hace/crypto/<mode>". > + */ > +void aspeed_add_crypto_tests(const char *prefix, const char *machine, > + uint32_t base, uint64_t dram, uint32_t > +modes); > + > #endif /* TESTS_ASPEED_HACE_UTILS_H */ > > diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c > index 25450a296b..0355dd47af 100644 > --- a/tests/qtest/aspeed-hace-utils.c > +++ b/tests/qtest/aspeed-hace-utils.c > @@ -9,6 +9,7 @@ > #include "libqtest.h" > #include "qemu/bitops.h" > #include "qemu/bswap.h" > +#include "crypto/cipher.h" > #include "aspeed-hace-utils.h" > > /* > @@ -645,3 +646,327 @@ void aspeed_test_addresses(const char *machine, > const uint32_t base, > qtest_quit(s); > } > > +/* > + * Crypto engine register layout (offsets from the HACE base). > + */ > +#define HACE_CRYPTO_SRC 0x00 > +#define HACE_CRYPTO_DEST 0x04 > +#define HACE_CRYPTO_CONTEXT 0x08 > +#define HACE_CRYPTO_DATA_LEN 0x0c > +#define HACE_CRYPTO_CMD 0x10 > + > +/* Crypto command bits */ > +#define HACE_CMD_ENCRYPT BIT(7) > +#define HACE_CMD_ISR_EN BIT(12) > +#define HACE_CMD_DES_SELECT BIT(16) > +#define HACE_CMD_TRIPLE_DES BIT(17) > +#define HACE_CMD_SRC_SG_CTRL BIT(18) > +#define HACE_CMD_DST_SG_CTRL BIT(19) > +#define HACE_CMD_OP_MODE_MASK (0x7 << 4) > +#define HACE_CMD_ECB (0x0 << 4) > +#define HACE_CMD_CBC (0x1 << 4) > +#define HACE_CMD_AES128 (0x0 << 2) > + > +/* Context buffer layout: IV (DES at +8), key at +0x10 */ > +#define HACE_CTX_KEY_OFFSET 0x10 > +#define HACE_CTX_SIZE 0x30 > + > +/* > + * Crypto known-answer test vectors, taken verbatim from the Linux > +kernel > + * crypto self-test templates in crypto/testmgr.h: > + * > + * > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/t > estmgr.h?h=v6.18 > + * > + * The originating template is noted above each block. CTR and the > +longer CBC > + * vectors are truncated to a single block (still a valid known-answer > +test as > + * the first block only depends on the IV). > + */ > + > +/* aes_tv_template[0] (FIPS-197) */ > +static const uint8_t aes128_ecb_key[16] = { > + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, > + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; static const > +uint8_t aes128_ecb_ptext[16] = { > + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, > + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; static const > +uint8_t aes128_ecb_ctext[16] = { > + 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, > + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }; > + > +/* aes_cbc_tv_template[0] (RFC 3602) */ static const uint8_t > +aes128_cbc_key[16] = { > + 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, > + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }; static const > +uint8_t aes128_cbc_iv[16] = { > + 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, > + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }; static const > +uint8_t aes128_cbc_ptext[16] = { > + 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x62, > + 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6d, 0x73, 0x67 }; static const > +uint8_t aes128_cbc_ctext[16] = { > + 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8, > + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a }; static const > +uint8_t aes128_cbc_ivout[16] = { > + 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8, > + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a }; > + > +/* des_tv_template[0] (Applied Cryptography) */ static const uint8_t > +des_ecb_key[8] = { > + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; static const > +uint8_t des_ecb_ptext[8] = { > + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7 }; static const > +uint8_t des_ecb_ctext[8] = { > + 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d }; > + > +/* des_cbc_tv_template[0] (OpenSSL), first block */ static const > +uint8_t des_cbc_key[8] = { > + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; static const > +uint8_t des_cbc_iv[8] = { > + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; static const > +uint8_t des_cbc_ptext[8] = { > + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20 }; static const > +uint8_t des_cbc_ctext[8] = { > + 0xcc, 0xd1, 0x73, 0xff, 0xab, 0x20, 0x39, 0xf4 }; > + > +/* des3_ede_tv_template[0] (OpenSSL) */ static const uint8_t > +tdes_ecb_key[24] = { > + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, > + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, > + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; static const > +uint8_t tdes_ecb_ptext[8] = { > + 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x61, 0x74, 0x61 }; static const > +uint8_t tdes_ecb_ctext[8] = { > + 0x18, 0xd7, 0x48, 0xe5, 0x63, 0x62, 0x05, 0x72 }; > + > +/* des3_ede_cbc_tv_template[0] (OpenSSL), first block */ static const > +uint8_t tdes_cbc_key[24] = { > + 0xe9, 0xc0, 0xff, 0x2e, 0x76, 0x0b, 0x64, 0x24, > + 0x44, 0x4d, 0x99, 0x5a, 0x12, 0xd6, 0x40, 0xc0, > + 0xea, 0xc2, 0x84, 0xe8, 0x14, 0x95, 0xdb, 0xe8 }; static const > +uint8_t tdes_cbc_iv[8] = { > + 0x7d, 0x33, 0x88, 0x93, 0x0f, 0x93, 0xb2, 0x42 }; static const > +uint8_t tdes_cbc_ptext[8] = { > + 0x6f, 0x54, 0x20, 0x6f, 0x61, 0x4d, 0x79, 0x6e }; static const > +uint8_t tdes_cbc_ctext[8] = { > + 0x0e, 0x2d, 0xb6, 0x97, 0x3c, 0x56, 0x33, 0xf4 }; > + > +typedef struct CryptTest { > + QCryptoCipherMode mode; > + QCryptoCipherAlgo alg; > + /* expected context IV after encrypt, or NULL */ > + const uint8_t *iv_out; > + const uint8_t *ptext; > + const uint8_t *ctext; > + const uint8_t *key; > + const uint8_t *iv; > + const char *name; > + size_t keylen; > + /* algorithm | mode | key size selection */ > + uint32_t cmd; > + size_t ivlen; > + size_t len; > +} CryptTest; > + > +static const CryptTest crypt_tests[] = { > + { > + .name = "aes128-ecb", > + .cmd = HACE_CMD_AES128 | HACE_CMD_ECB, > + .alg = QCRYPTO_CIPHER_ALGO_AES_128, > + .mode = QCRYPTO_CIPHER_MODE_ECB, > + .key = aes128_ecb_key, > + .keylen = sizeof(aes128_ecb_key), > + .ptext = aes128_ecb_ptext, > + .ctext = aes128_ecb_ctext, > + .len = sizeof(aes128_ecb_ptext), > + }, > + { > + .name = "aes128-cbc", > + .cmd = HACE_CMD_AES128 | HACE_CMD_CBC, > + .alg = QCRYPTO_CIPHER_ALGO_AES_128, > + .mode = QCRYPTO_CIPHER_MODE_CBC, > + .key = aes128_cbc_key, > + .keylen = sizeof(aes128_cbc_key), > + .iv = aes128_cbc_iv, > + .ivlen = sizeof(aes128_cbc_iv), > + .ptext = aes128_cbc_ptext, > + .ctext = aes128_cbc_ctext, > + .iv_out = aes128_cbc_ivout, > + .len = sizeof(aes128_cbc_ptext), > + }, > + { > + .name = "des-ecb", > + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_ECB, > + .alg = QCRYPTO_CIPHER_ALGO_DES, > + .mode = QCRYPTO_CIPHER_MODE_ECB, > + .key = des_ecb_key, > + .keylen = sizeof(des_ecb_key), > + .ptext = des_ecb_ptext, > + .ctext = des_ecb_ctext, > + .len = sizeof(des_ecb_ptext), > + }, > + { > + .name = "des-cbc", > + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_CBC, > + .alg = QCRYPTO_CIPHER_ALGO_DES, > + .mode = QCRYPTO_CIPHER_MODE_CBC, > + .key = des_cbc_key, > + .keylen = sizeof(des_cbc_key), > + .iv = des_cbc_iv, > + .ivlen = sizeof(des_cbc_iv), > + .ptext = des_cbc_ptext, > + .ctext = des_cbc_ctext, > + .len = sizeof(des_cbc_ptext), > + }, > + { > + .name = "des3_ede-ecb", > + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | > HACE_CMD_ECB, > + .alg = QCRYPTO_CIPHER_ALGO_3DES, > + .mode = QCRYPTO_CIPHER_MODE_ECB, > + .key = tdes_ecb_key, > + .keylen = sizeof(tdes_ecb_key), > + .ptext = tdes_ecb_ptext, > + .ctext = tdes_ecb_ctext, > + .len = sizeof(tdes_ecb_ptext), > + }, > + { > + .name = "des3_ede-cbc", > + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | > HACE_CMD_CBC, > + .alg = QCRYPTO_CIPHER_ALGO_3DES, > + .mode = QCRYPTO_CIPHER_MODE_CBC, > + .key = tdes_cbc_key, > + .keylen = sizeof(tdes_cbc_key), > + .iv = tdes_cbc_iv, > + .ivlen = sizeof(tdes_cbc_iv), > + .ptext = tdes_cbc_ptext, > + .ctext = tdes_cbc_ctext, > + .len = sizeof(tdes_cbc_ptext), > + }, > +}; > + > +/* DRAM offsets for the crypto test source, destination and context buffers. */ > +#define CRYPT_OFF_SRC 0x10000 > +#define CRYPT_OFF_DST 0x20000 > +#define CRYPT_OFF_CTX 0x30000 > + > +/* Describes one registered crypto test (qtest_add_data_func() data > +pointer). */ typedef struct AspeedCryptoTest { > + const char *machine; > + uint64_t dram; > + uint32_t base; > + int index; > +} AspeedCryptoTest; > + > +/* Map a command's operation mode (HACE10[6:4]) to a CRYPT_MODE_* > flag. > +*/ static uint32_t crypt_mode_flag(uint32_t cmd) { > + switch (cmd & HACE_CMD_OP_MODE_MASK) { > + case HACE_CMD_ECB: > + return CRYPT_MODE_ECB; > + case HACE_CMD_CBC: > + return CRYPT_MODE_CBC; > + default: > + return 0; > + } > +} > + > +static void crypt_write_ctx(QTestState *s, uint64_t ctx_addr, > + const CryptTest *t) { > + size_t iv_off = (t->cmd & HACE_CMD_DES_SELECT) ? 8 : 0; > + uint8_t ctx[HACE_CTX_SIZE] = { 0 }; > + > + if (t->iv) { > + memcpy(ctx + iv_off, t->iv, t->ivlen); > + } > + memcpy(ctx + HACE_CTX_KEY_OFFSET, t->key, t->keylen); > + qtest_memwrite(s, ctx_addr, ctx, sizeof(ctx)); } > + > +/* Run one crypto operation in direct access mode and read back the > +result. */ static void crypt_run_direct(QTestState *s, uint32_t base, uint64_t > dram, > + const CryptTest *t, bool encrypt, uint8_t > +*out) { > + const uint8_t *in = encrypt ? t->ptext : t->ctext; > + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN; > + uint64_t src = dram + CRYPT_OFF_SRC; > + uint64_t dst = dram + CRYPT_OFF_DST; > + uint64_t ctx = dram + CRYPT_OFF_CTX; > + > + if (encrypt) { > + cmd |= HACE_CMD_ENCRYPT; > + } > + > + crypt_write_ctx(s, ctx, t); > + qtest_memwrite(s, src, in, t->len); > + > + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src); > + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst); > + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx); > + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len); > + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd); > + > + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, > ==, > + HACE_CRYPTO_ISR); > + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR); > + > + qtest_memread(s, dst, out, t->len); } > + > +static void aspeed_test_crypto_direct(const void *data) { > + const AspeedCryptoTest *c = data; > + const CryptTest *t = &crypt_tests[c->index]; > + QTestState *s = qtest_init(c->machine); > + uint8_t out[64]; > + uint8_t iv[16]; > + size_t iv_off; > + > + g_assert_cmpuint(t->len, <=, sizeof(out)); > + > + /* Encrypt: ptext -> ctext */ > + crypt_run_direct(s, c->base, c->dram, t, true, out); > + g_assert_cmpmem(out, t->len, t->ctext, t->len); > + > + if (t->iv_out) { > + iv_off = (t->cmd & HACE_CMD_DES_SELECT) ? 8 : 0; > + qtest_memread(s, c->dram + CRYPT_OFF_CTX + iv_off, iv, t->ivlen); > + g_assert_cmpmem(iv, t->ivlen, t->iv_out, t->ivlen); > + } > + > + /* Decrypt: ctext -> ptext */ > + crypt_run_direct(s, c->base, c->dram, t, false, out); > + g_assert_cmpmem(out, t->len, t->ptext, t->len); > + > + qtest_quit(s); > +} > + > +void aspeed_add_crypto_tests(const char *prefix, const char *machine, > + uint32_t base, uint64_t dram, uint32_t > +modes) { > + int i; > + > + for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) { > + g_autofree char *path = NULL; > + AspeedCryptoTest *t; > + > + if (!(modes & crypt_mode_flag(crypt_tests[i].cmd))) { > + continue; > + } > + > + if (!qcrypto_cipher_supports(crypt_tests[i].alg, > + crypt_tests[i].mode)) { > + g_printerr("# skip unsupported %s\n", crypt_tests[i].name); > + continue; > + } > + > + path = g_strdup_printf("%s/hace/crypto/%s", prefix, > + crypt_tests[i].name); > + t = g_new0(AspeedCryptoTest, 1); > + t->machine = machine; > + t->base = base; > + t->dram = dram; > + t->index = i; > + qtest_add_data_func_full(path, t, aspeed_test_crypto_direct, > g_free); > + } > +} > + > diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c > index 38777020ca..4cb4c475e9 100644 > --- a/tests/qtest/aspeed_hace-test.c > +++ b/tests/qtest/aspeed_hace-test.c > @@ -229,6 +229,12 @@ int main(int argc, char **argv) > qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500); > qtest_add_func("ast2500/hace/md5", test_md5_ast2500); > > + /* > + * The AST2500 crypto engine uses direct access mode and supports > ECB/CBC. > + */ > + aspeed_add_crypto_tests("ast2500", "-machine ast2500-evb", > 0x1e6e3000, > + 0x80000000, CRYPT_MODE_ECB | > + CRYPT_MODE_CBC); > + > qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400); > qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400); > qtest_add_func("ast2400/hace/sha256", test_sha256_ast2400); diff --git > a/tests/qtest/meson.build b/tests/qtest/meson.build index > 56ff860e21..d5bde77689 100644 > --- a/tests/qtest/meson.build > +++ b/tests/qtest/meson.build > @@ -389,9 +389,11 @@ if get_option('replication').allowed() > endif > > qtests = { > - 'aspeed_hace-test': files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), > + 'aspeed_hace-test': [files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), > + crypto], > 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), > - 'ast2700-hace-test': files('aspeed-hace-utils.c', 'ast2700-hace-test.c'), > + 'ast2700-hace-test': [files('aspeed-hace-utils.c', 'ast2700-hace-test.c'), > + crypto], > 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), > 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], > 'cdrom-test': files('boot-sector.c'), > -- > 2.43.0 Reviewed-by: Kane Chen <[email protected]>