diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2026-09-07 13:33:12 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2026-09-07 13:33:12 +0100 |
| commit | 35500e5c41aec76cde59befe750600dac7a9e37a (patch) | |
| tree | 108af14ab7700f9c29bc0b7ba8f513fbc5bace8a /tests | |
| parent | 61e537b7ef2f8b899827c72126cada6161e5803d (diff) | |
| parent | 1c05d7e94da04129ea16147074fe73158fb85ff9 (diff) | |
| download | qemu-35500e5c41aec76cde59befe750600dac7a9e37a.tar.gz qemu-35500e5c41aec76cde59befe750600dac7a9e37a.zip | |
aspeed queue:
* Fixes AST2600 SCU protection key registers on reset
* Fixes I2C byte latching for SMBus block reads
* Hardens EHCI get_dwords()/put_dwords() with DMA error checking
* Adds a second random number generator to the AST2600 SCU
* Adds the ASPEED ACRY RSA accelerator model with ModExp qtest coverage
* Adds ECDSA sign/verify support to the QEMU crypto akcipher layer
(gcrypt, nettle backends) with tests
* Adds ECDSA verify command to the ASPEED SBC model with qtest coverage
* Adds the ASPEED UDC (USB Device Controller) with gadget device
and programmable endpoint DMA, wired on the AST2600
* Reworks the TMP105 temperature sensor: Resettable reset, fault
queue enforcement, TMP75/TMP175/LM75B variants, and qtest coverage
* Adds the Facebook SanMiguel BMC machine with EEPROM data
* Uses real TMP75/LM75B models on the Catalina and Fuji boards
* Adds optional device tree model checking to functional boot tests
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmqdnl8ACgkQUaNDx8/7
# 7KGMzxAAgxO09nzutoyjvMRK+Tydd65h9TNxZTC68jzUjacGfU9Y+1+1OcgU25D1
# EUorhMrAGMe22zZ6Q6048HjBmw/xRxt4QB6A5CGIroSgVqQH6NAFalZz5jeCwZrm
# HMk2UAzf0/2euBAXRUFEtK/RpfdrSe1kNXcRX2lWkt5HdjfZJxcM/TmOtLl0vDDU
# BUMbmXLWvnv/W8OLiVmGwP8ufGey2HL2dsLn2Fs9riFF1ZUaJGFkKxEc7ApF6tOr
# 0YaY84lainh21Bp+IjXaV2Al8XCyyHpWKFrEYLEm9P3FfMEebIZbJu8he20cidiw
# R5LIgHpb6FcUZvVcfWyAfYK1+yRQDrL9PMQ8OdbiUgtW1WnvqSyQES4GWx55OmPc
# TSRDodPnETxF26n43ruIWdIGa6umgieT891UrI3CsCYc7JpSpujCgMiob6sLWjFD
# h65DNECnSl3qkK8kIneEhUK9MVIX62YskqAWkIF7rwy+Af7QkCcWuMKTGIpC+a/l
# H7SjxPWwy1XW9B+4dhF3teYxqb8iETM0BQwr2ZuAp3mbB/YkTMaIj5TfUpiGrClz
# RdkSc2njjqbeyQZSTV1P+M8cpWBYiHRJNhx58rH6qIpH6ATSZZAym6XCZV2wZDtU
# VJ7TwnOObQMogMp/9iThUd4jEtCcmEp1dxXF/KKXADso6EU6+Do=
# =sX4J
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun Sep 6 18:09:51 2026 BST
# gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [full]
# gpg: aka "Cédric Le Goater <clg@kaod.org>" [full]
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1
* tag 'pull-aspeed-20260906' of https://github.com/legoater/qemu: (40 commits)
tests/functional: aspeed: optionally check the device tree model on boot
hw/arm: fuji: use the real TMP75 and LM75B temperature sensors
hw/arm: catalina: use the real TMP75 model
hw/arm: sanmiguel: populate EEPROM data
hw/arm: sanmiguel: add Facebook SanMiguel BMC machine
tests/qtest: tmp105: cover shutdown clearing the ALERT across variants
tests/qtest: tmp105: cover one-shot and fault-queue write immunity
tests/qtest: tmp105: cover the TMP75, TMP175 and LM75B variants
tests/qtest: tmp105: cover the ALERT fault queue
hw/sensor: tmp105: add TMP75, TMP175 and LM75B variants
hw/arm: aspeed: guard board-local temperature-sensor aliases
hw/sensor: tmp105: describe the temperature property
hw/sensor: tmp105: enforce the configurable fault queue
hw/sensor: tmp105: implement Resettable reset
hw/sensor: tmp105: name the parent object field parent_obj
hw/sensor: tmp105: make device state private to the implementation
hw/arm/aspeed_ast2600: Wire up the UDC
hw/usb/aspeed-udc: Add programmable endpoint DMA transfers
hw/usb/aspeed-udc: Add ASPEED UDC gadget USB device
hw/usb/aspeed-udc: Add ASPEED UDC device controller
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/functional/aspeed.py | 5 | ||||
| -rw-r--r-- | tests/qtest/aspeed-acry-test.c | 406 | ||||
| -rw-r--r-- | tests/qtest/aspeed-hace-utils.c | 24 | ||||
| -rw-r--r-- | tests/qtest/aspeed-sbc-test.c | 194 | ||||
| -rw-r--r-- | tests/qtest/meson.build | 7 | ||||
| -rw-r--r-- | tests/qtest/tmp105-test.c | 359 | ||||
| -rw-r--r-- | tests/unit/test-crypto-akcipher.c | 236 |
7 files changed, 1221 insertions, 10 deletions
diff --git a/tests/functional/aspeed.py b/tests/functional/aspeed.py index 076da1036c..08af6b4839 100644 --- a/tests/functional/aspeed.py +++ b/tests/functional/aspeed.py @@ -8,7 +8,8 @@ from qemu_test import LinuxKernelTest class AspeedTest(LinuxKernelTest): def do_test_arm_aspeed_openbmc(self, machine, image, uboot='2019.04', - cpu_id='0x0', soc='AST2500 rev A1'): + cpu_id='0x0', soc='AST2500 rev A1', + dt_model=None): self.set_machine(machine) self.vm.set_console() self.vm.add_args('-drive', f'file={image},if=mtd,format=raw', @@ -19,6 +20,8 @@ class AspeedTest(LinuxKernelTest): self.wait_for_console_pattern('## Loading kernel from FIT Image') self.wait_for_console_pattern('Starting kernel ...') self.wait_for_console_pattern(f'Booting Linux on physical CPU {cpu_id}') + if dt_model: + self.wait_for_console_pattern(f'Machine model: {dt_model}') self.wait_for_console_pattern(f'ASPEED {soc}') self.wait_for_console_pattern('/init as init process') self.wait_for_boot_complete() diff --git a/tests/qtest/aspeed-acry-test.c b/tests/qtest/aspeed-acry-test.c new file mode 100644 index 0000000000..ec348c2206 --- /dev/null +++ b/tests/qtest/aspeed-acry-test.c @@ -0,0 +1,406 @@ +/* + * QTest testcase for the ASPEED ACRY Engine + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bitops.h" +#include "crypto/akcipher.h" + +#define ACRY_TRIGGER 0x000 +#define ACRY_TRIGGER_RSA_DMA_DATA BIT(1) +#define ACRY_TRIGGER_RSA_START BIT(0) +#define ACRY_DMA_CMD 0x048 +#define ACRY_DMA_CMD_DMEM_AHB BIT(8) +#define ACRY_DMA_CMD_SRAM_MODE_RSA (0x3 << 4) +#define ACRY_DMA_SRC 0x04C +#define ACRY_DMA_LEN 0x050 +#define ACRY_RSA_KEY_LEN 0x058 +#define ACRY_INT_MASK 0x3F8 +#define ACRY_INT_MASK_RSA_DMA_MASK BIT(2) +#define ACRY_INT_MASK_RSA_ENG_MASK BIT(1) +#define ACRY_STATUS 0x3FC +#define ACRY_STATUS_RSA_DMA_DONE BIT(2) +#define ACRY_STATUS_RSA_ENG_DONE BIT(1) +#define ACRY_STATUS_RSA_DONE (ACRY_STATUS_RSA_ENG_DONE | \ + ACRY_STATUS_RSA_DMA_DONE) + +#define ACRY_DATA_MAX_LEN 0x800 +#define ACRY_SRAM_SIZE (3 * ACRY_DATA_MAX_LEN) +#define ACRY_MAX_BITS 4096 +#define ACRY_MAX_BYTES (ACRY_MAX_BITS / 8) + +#define ACRY_BYTES_PER_DWORD 4 +#define ACRY_LANES_PER_BLOCK 4 +/* Each block holds 3 regions (exp, mod, data) of LANES_PER_BLOCK dwords. */ +#define ACRY_DWORDS_PER_BLOCK (3 * ACRY_LANES_PER_BLOCK) + +/* Dwords into each block where each operand's region starts. */ +#define ACRY_EXP_OFFSET (0 * ACRY_LANES_PER_BLOCK) +#define ACRY_MOD_OFFSET (1 * ACRY_LANES_PER_BLOCK) +#define ACRY_DATA_OFFSET (2 * ACRY_LANES_PER_BLOCK) + +/* + * Raw (unpadded) RSA known-answer vectors: c = m^e mod n with + * e = 0x10001 (65537) - exactly what the "rsa" akcipher transform backed by + * the ACRY FW computes. PKCS1 padding is a separate "pkcs1pad(rsa)" template + * layered on top in Linux, not done by the ACRY hardware. + * + * rsa2048_* and rsa4096_* are from the Linux kernel crypto/testmgr.h (v6.18), + * rsa_tv_template[2] and [3]. Grep that file's own comment to find them: + * + * RSA test vectors. Borrowed from openSSL. + * + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.h?h=v6.18 + * + * There the modulus n is DER-encoded in the .key field (not a raw field), the + * ciphertext is .c, and every entry reuses the same 8-byte .m message. + */ +/* rsa_tv_template[].m, shared by every entry */ +static const uint8_t rsa_m[8] = { + 0x54, 0x85, 0x9B, 0x34, 0x2C, 0x49, 0xEA, 0x2A, +}; +/* public exponent e = 65537, DER-encoded in every .key */ +static const uint8_t rsa_e[3] = { 0x01, 0x00, 0x01 }; + +/* rsa_tv_template[2].key, modulus n */ +static const uint8_t rsa2048_n[256] = { + 0xDB, 0x10, 0x1A, 0xC2, 0xA3, 0xF1, 0xDC, 0xFF, 0x13, 0x6B, 0xED, 0x44, + 0xDF, 0xF0, 0x02, 0x6D, 0x13, 0xC7, 0x88, 0xDA, 0x70, 0x6B, 0x54, 0xF1, + 0xE8, 0x27, 0xDC, 0xC3, 0x0F, 0x99, 0x6A, 0xFA, 0xC6, 0x67, 0xFF, 0x1D, + 0x1E, 0x3C, 0x1D, 0xC1, 0xB5, 0x5F, 0x6C, 0xC0, 0xB2, 0x07, 0x3A, 0x6D, + 0x41, 0xE4, 0x25, 0x99, 0xAC, 0xFC, 0xD2, 0x0F, 0x02, 0xD3, 0xD1, 0x54, + 0x06, 0x1A, 0x51, 0x77, 0xBD, 0xB6, 0xBF, 0xEA, 0xA7, 0x5C, 0x06, 0xA9, + 0x5D, 0x69, 0x84, 0x45, 0xD7, 0xF5, 0x05, 0xBA, 0x47, 0xF0, 0x1B, 0xD7, + 0x2B, 0x24, 0xEC, 0xCB, 0x9B, 0x1B, 0x10, 0x8D, 0x81, 0xA0, 0xBE, 0xB1, + 0x8C, 0x33, 0xE4, 0x36, 0xB8, 0x43, 0xEB, 0x19, 0x2A, 0x81, 0x8D, 0xDE, + 0x81, 0x0A, 0x99, 0x48, 0xB6, 0xF6, 0xBC, 0xCD, 0x49, 0x34, 0x3A, 0x8F, + 0x26, 0x94, 0xE3, 0x28, 0x82, 0x1A, 0x7C, 0x8F, 0x59, 0x9F, 0x45, 0xE8, + 0x5D, 0x1A, 0x45, 0x76, 0x04, 0x56, 0x05, 0xA1, 0xD0, 0x1B, 0x8C, 0x77, + 0x6D, 0xAF, 0x53, 0xFA, 0x71, 0xE2, 0x67, 0xE0, 0x9A, 0xFE, 0x03, 0xA9, + 0x85, 0xD2, 0xC9, 0xAA, 0xBA, 0x2A, 0xBC, 0xF4, 0xA0, 0x08, 0xF5, 0x13, + 0x98, 0x13, 0x5D, 0xF0, 0xD9, 0x33, 0x34, 0x2A, 0x61, 0xC3, 0x89, 0x55, + 0xF0, 0xAE, 0x1A, 0x9C, 0x22, 0xEE, 0x19, 0x05, 0x8D, 0x32, 0xFE, 0xEC, + 0x9C, 0x84, 0xBA, 0xB7, 0xF9, 0x6C, 0x3A, 0x4F, 0x07, 0xFC, 0x45, 0xEB, + 0x12, 0xE5, 0x7B, 0xFD, 0x55, 0xE6, 0x29, 0x69, 0xD1, 0xC2, 0xE8, 0xB9, + 0x78, 0x59, 0xF6, 0x79, 0x10, 0xC6, 0x4E, 0xEB, 0x6A, 0x5E, 0xB9, 0x9A, + 0xC7, 0xC4, 0x5B, 0x63, 0xDA, 0xA3, 0x3F, 0x5E, 0x92, 0x7A, 0x81, 0x5E, + 0xD6, 0xB0, 0xE2, 0x62, 0x8F, 0x74, 0x26, 0xC2, 0x0C, 0xD3, 0x9A, 0x17, + 0x47, 0xE6, 0x8E, 0xAB, +}; +/* rsa_tv_template[2].c */ +static const uint8_t rsa2048_c[256] = { + 0xB2, 0x97, 0x76, 0xB4, 0xAE, 0x3E, 0x38, 0x3C, 0x7E, 0x64, 0x1F, 0xCC, + 0xA2, 0x7F, 0xF6, 0xBE, 0xCF, 0x49, 0xBC, 0x48, 0xD3, 0x6C, 0x8F, 0x0A, + 0x0E, 0xC1, 0x73, 0xBD, 0x7B, 0x55, 0x79, 0x36, 0x0E, 0xA1, 0x87, 0x88, + 0xB9, 0x2C, 0x90, 0xA6, 0x53, 0x5E, 0xE9, 0xEF, 0xC4, 0xE2, 0x4D, 0xDD, + 0xF7, 0xA6, 0x69, 0x82, 0x3F, 0x56, 0xA4, 0x7B, 0xFB, 0x62, 0xE0, 0xAE, + 0xB8, 0xD3, 0x04, 0xB3, 0xAC, 0x5A, 0x15, 0x2A, 0xE3, 0x19, 0x9B, 0x03, + 0x9A, 0x0B, 0x41, 0xDA, 0x64, 0xEC, 0x0A, 0x69, 0xFC, 0xF2, 0x10, 0x92, + 0xF3, 0xC1, 0xBF, 0x84, 0x7F, 0xFD, 0x2C, 0xAE, 0xC8, 0xB5, 0xF6, 0x41, + 0x70, 0xC5, 0x47, 0x03, 0x8A, 0xF8, 0xFF, 0x6F, 0x3F, 0xD2, 0x6F, 0x09, + 0xB4, 0x22, 0xF3, 0x30, 0xBE, 0xA9, 0x85, 0xCB, 0x9C, 0x8D, 0xF9, 0x8F, + 0xEB, 0x32, 0x91, 0xA2, 0x25, 0x84, 0x8F, 0xF5, 0xDC, 0xC7, 0x06, 0x9C, + 0x2D, 0xE5, 0x11, 0x2C, 0x09, 0x09, 0x87, 0x09, 0xA9, 0xF6, 0x33, 0x73, + 0x90, 0xF1, 0x60, 0xF2, 0x65, 0xDD, 0x30, 0xA5, 0x66, 0xCE, 0x62, 0x7B, + 0xD0, 0xF8, 0x2D, 0x3D, 0x19, 0x82, 0x77, 0xE3, 0x0A, 0x5F, 0x75, 0x2F, + 0x8E, 0xB1, 0xE5, 0xE8, 0x91, 0x35, 0x1B, 0x3B, 0x33, 0xB7, 0x66, 0x92, + 0xD1, 0xF2, 0x8E, 0x6F, 0xE5, 0x75, 0x0C, 0xAD, 0x36, 0xFB, 0x4E, 0xD0, + 0x66, 0x61, 0xBD, 0x49, 0xFE, 0xF4, 0x1A, 0xA2, 0x2B, 0x49, 0xFE, 0x03, + 0x4C, 0x74, 0x47, 0x8D, 0x9A, 0x66, 0xB2, 0x49, 0x46, 0x4D, 0x77, 0xEA, + 0x33, 0x4D, 0x6B, 0x3C, 0xB4, 0x49, 0x4A, 0xC6, 0x7D, 0x3D, 0xB5, 0xB9, + 0x56, 0x41, 0x15, 0x67, 0x0F, 0x94, 0x3C, 0x93, 0x65, 0x27, 0xE0, 0x21, + 0x5D, 0x59, 0xC3, 0x62, 0xD5, 0xA6, 0xDA, 0x38, 0x26, 0x22, 0x5E, 0x34, + 0x1C, 0x94, 0xAF, 0x98, +}; + +/* rsa_tv_template[3].key, modulus n */ +static const uint8_t rsa4096_n[512] = { + 0xC3, 0x8B, 0x55, 0x7B, 0x73, 0x4D, 0xFF, 0xE9, 0x9B, 0xC6, 0xDC, 0x67, + 0x3C, 0xB4, 0x8E, 0xA0, 0x86, 0xED, 0xF2, 0xB9, 0x50, 0x5C, 0x54, 0x5C, + 0xBA, 0xE4, 0xA1, 0xB2, 0xA7, 0xAE, 0x2F, 0x1B, 0x7D, 0xF1, 0xFB, 0xAC, + 0x79, 0xC5, 0xDF, 0x1A, 0x00, 0xC9, 0xB2, 0xC1, 0x61, 0x25, 0x33, 0xE6, + 0x9C, 0xE9, 0xCF, 0xD6, 0x27, 0xC4, 0x4E, 0x44, 0x30, 0x44, 0x5E, 0x08, + 0xA1, 0x87, 0x52, 0xCC, 0x6B, 0x97, 0x70, 0x8C, 0xBC, 0xA5, 0x06, 0x31, + 0x0C, 0xD4, 0x2F, 0xD5, 0x7D, 0x26, 0x24, 0xA2, 0xE2, 0xAC, 0x78, 0xF4, + 0x53, 0x14, 0xCE, 0xF7, 0x19, 0x2E, 0xD7, 0xF7, 0xE6, 0x0C, 0xB9, 0x56, + 0x7F, 0x0B, 0xF1, 0xB1, 0xE2, 0x43, 0x70, 0xBD, 0x86, 0x1D, 0xA1, 0xCC, + 0x2B, 0x19, 0x08, 0x76, 0xEF, 0x91, 0xAC, 0xBF, 0x20, 0x24, 0x0D, 0x38, + 0xC0, 0x89, 0xB8, 0x9A, 0x70, 0xB3, 0x64, 0xD9, 0x8F, 0x80, 0x41, 0x10, + 0x5B, 0x9F, 0xB1, 0xCB, 0x76, 0x43, 0x00, 0x21, 0x25, 0x36, 0xD4, 0x19, + 0xFC, 0x55, 0x95, 0x10, 0xE4, 0x26, 0x74, 0x98, 0x2C, 0xD9, 0xBD, 0x0B, + 0x2B, 0x04, 0xC2, 0xAC, 0x82, 0x38, 0xB4, 0xDD, 0x4C, 0x04, 0x7E, 0x51, + 0x36, 0x40, 0x1E, 0x0B, 0xC4, 0x7C, 0x25, 0xDD, 0x4B, 0xB2, 0xE7, 0x20, + 0x0A, 0x57, 0xF9, 0xB4, 0x94, 0xC3, 0x08, 0x33, 0x22, 0x6F, 0x8B, 0x48, + 0xDB, 0x03, 0x68, 0x5A, 0x5B, 0xBA, 0xAE, 0xF3, 0xAD, 0xCF, 0xC3, 0x6D, + 0xBA, 0xF1, 0x28, 0x67, 0x7E, 0x6C, 0x79, 0x07, 0xDE, 0xFC, 0xED, 0xE7, + 0x96, 0xE3, 0x6C, 0xE0, 0x2C, 0x87, 0xF8, 0x02, 0x01, 0x28, 0x38, 0x43, + 0x21, 0x53, 0x84, 0x69, 0x75, 0x78, 0x15, 0x7E, 0xEE, 0xD2, 0x1B, 0xB9, + 0x23, 0x40, 0xA8, 0x86, 0x1E, 0x38, 0x83, 0xB2, 0x73, 0x1D, 0x53, 0xFB, + 0x9E, 0x2A, 0x8A, 0xB2, 0x75, 0x35, 0x01, 0xC3, 0xC3, 0xC4, 0x94, 0xE8, + 0x84, 0x86, 0x64, 0x81, 0xF4, 0x42, 0xAA, 0x3C, 0x0E, 0xD6, 0x4F, 0xBC, + 0x0A, 0x09, 0x2D, 0xE7, 0x1B, 0xD4, 0x10, 0xA8, 0x54, 0xEA, 0x89, 0x84, + 0x8A, 0xCB, 0xF7, 0x5A, 0x3C, 0xCA, 0x76, 0x08, 0x29, 0x62, 0xB4, 0x6A, + 0x22, 0xDF, 0x14, 0x95, 0x71, 0xFD, 0xB6, 0x86, 0x39, 0xB8, 0x8B, 0xF8, + 0x91, 0x7F, 0x38, 0xAA, 0x14, 0xCD, 0xE5, 0xF5, 0x1D, 0xC2, 0x6D, 0x53, + 0x69, 0x52, 0x84, 0x7F, 0xA3, 0x1A, 0x5E, 0x26, 0x04, 0x83, 0x06, 0x73, + 0x52, 0x56, 0xCF, 0x76, 0x26, 0xC9, 0xDD, 0x75, 0xD7, 0xFC, 0xF4, 0x69, + 0xD8, 0x7B, 0x55, 0xB7, 0x68, 0x13, 0x53, 0xB9, 0xE7, 0x89, 0xC3, 0xE8, + 0xD6, 0x6E, 0xA7, 0x6D, 0xEA, 0x81, 0xFD, 0xC4, 0xB7, 0x05, 0x5A, 0xB7, + 0x41, 0x0A, 0x23, 0x8E, 0x03, 0x8A, 0x1C, 0xAE, 0xD3, 0x1E, 0xCE, 0xE3, + 0x5E, 0xFC, 0x19, 0x4A, 0xEE, 0x61, 0x9B, 0x8E, 0xE5, 0xE5, 0xDD, 0x85, + 0xF9, 0x41, 0xEC, 0x14, 0x53, 0x92, 0xF7, 0xDD, 0x06, 0x85, 0x02, 0x91, + 0xE3, 0xEB, 0x6C, 0x43, 0x03, 0xB1, 0x36, 0x7B, 0x89, 0x5A, 0xA8, 0xEB, + 0xFC, 0xD5, 0xA8, 0x35, 0xDC, 0x81, 0xD9, 0x5C, 0xBD, 0xCA, 0xDC, 0x9B, + 0x98, 0x0B, 0x06, 0x5D, 0x0C, 0x5B, 0xEE, 0xF3, 0xD5, 0xCC, 0x57, 0xC9, + 0x71, 0x2F, 0x90, 0x3B, 0x3C, 0xF0, 0x8E, 0x4E, 0x35, 0x48, 0xAE, 0x63, + 0x74, 0xA9, 0xFC, 0x72, 0x75, 0x8E, 0x34, 0xA8, 0xF2, 0x1F, 0xEA, 0xDF, + 0x3A, 0x37, 0x2D, 0xE5, 0x39, 0x39, 0xF8, 0x57, 0x58, 0x3C, 0x04, 0xFE, + 0x87, 0x06, 0x98, 0xBC, 0x7B, 0xD3, 0x21, 0x36, 0x60, 0x25, 0x54, 0xA7, + 0x3D, 0xFA, 0x91, 0xCC, 0xA8, 0x0B, 0x92, 0x8E, 0xB4, 0xF7, 0x06, 0xFF, + 0x1E, 0x95, 0xCB, 0x07, 0x76, 0x97, 0x3B, 0x9D, +}; +/* rsa_tv_template[3].c */ +static const uint8_t rsa4096_c[512] = { + 0x5C, 0xCE, 0x9C, 0xD7, 0x9A, 0x9E, 0xA1, 0xFE, 0x7A, 0x82, 0x3C, 0x68, + 0x27, 0x98, 0xE3, 0x5D, 0xD5, 0xD7, 0x07, 0x29, 0xF5, 0xFB, 0xC3, 0x1A, + 0x7F, 0x63, 0x1E, 0x62, 0x31, 0x3B, 0x19, 0x87, 0x79, 0x4F, 0xEC, 0x7B, + 0xF3, 0xCB, 0xEA, 0x9B, 0x95, 0x52, 0x3A, 0x40, 0xE5, 0x87, 0x7B, 0x72, + 0xD1, 0x72, 0xC9, 0xFB, 0x54, 0x63, 0xD8, 0xC9, 0xD7, 0x2C, 0xFC, 0x7B, + 0xC3, 0x14, 0x1E, 0xBC, 0x18, 0xB4, 0x34, 0xA1, 0xBF, 0x14, 0xB1, 0x37, + 0x31, 0x6E, 0xF0, 0x1B, 0x35, 0x19, 0x54, 0x07, 0xF7, 0x99, 0xEC, 0x3E, + 0x63, 0xE2, 0xCD, 0x61, 0x28, 0x65, 0xC3, 0xCD, 0xB1, 0x38, 0x36, 0xA5, + 0xB2, 0xD7, 0xB0, 0xDC, 0x1F, 0xF5, 0xEF, 0x19, 0xC7, 0x53, 0x32, 0x2D, + 0x1C, 0x26, 0xDA, 0xE4, 0x0D, 0xD6, 0x90, 0x7E, 0x28, 0xD8, 0xDC, 0xE4, + 0x61, 0x05, 0xD2, 0x25, 0x90, 0x01, 0xD3, 0x96, 0x6D, 0xA6, 0xCF, 0x58, + 0x20, 0xBB, 0x03, 0xF4, 0x01, 0xBC, 0x79, 0xB9, 0x18, 0xD8, 0xB8, 0xBA, + 0xBD, 0x93, 0xFC, 0xF2, 0x62, 0x5D, 0x8C, 0x66, 0x1E, 0x0E, 0x84, 0x59, + 0x93, 0xDD, 0xE2, 0x93, 0xA2, 0x62, 0x7D, 0x08, 0x82, 0x7A, 0xDD, 0xFC, + 0xB8, 0xBC, 0xC5, 0x4F, 0x9C, 0x4E, 0xBF, 0xB4, 0xFC, 0xF4, 0xC5, 0x01, + 0xE8, 0x00, 0x70, 0x4D, 0x28, 0x26, 0xCC, 0x2E, 0xFE, 0x0E, 0x58, 0x41, + 0x8B, 0xEC, 0xAF, 0x7C, 0x4B, 0x54, 0xD0, 0xA0, 0x64, 0xF9, 0x32, 0xF4, + 0x2E, 0x47, 0x65, 0x0A, 0x67, 0x88, 0x39, 0x3A, 0xDB, 0xB2, 0xDB, 0x7B, + 0xB5, 0xF6, 0x17, 0xA8, 0xD9, 0xC6, 0x5E, 0x28, 0x13, 0x82, 0x8A, 0x99, + 0xDB, 0x60, 0x08, 0xA5, 0x23, 0x37, 0xFA, 0x88, 0x90, 0x31, 0xC8, 0x9D, + 0x8F, 0xEC, 0xFB, 0x85, 0x9F, 0xB1, 0xCE, 0xA6, 0x24, 0x50, 0x46, 0x44, + 0x47, 0xCB, 0x65, 0xD1, 0xDF, 0xC0, 0xB1, 0x6C, 0x90, 0x1F, 0x99, 0x8E, + 0x4D, 0xD5, 0x9E, 0x31, 0x07, 0x66, 0x87, 0xDF, 0x01, 0xAA, 0x56, 0x3C, + 0x71, 0xE0, 0x2B, 0x6F, 0x67, 0x3B, 0x23, 0xED, 0xC2, 0xBD, 0x03, 0x30, + 0x79, 0x76, 0x02, 0x10, 0x10, 0x98, 0x85, 0x8A, 0xFF, 0xFD, 0x0B, 0xDA, + 0xA5, 0xD9, 0x32, 0x48, 0x02, 0xA0, 0x0B, 0xB9, 0x2A, 0x8A, 0x18, 0xCA, + 0xC6, 0x8F, 0x3F, 0xBB, 0x16, 0xB2, 0xAA, 0x98, 0x27, 0xE3, 0x60, 0x43, + 0xED, 0x15, 0x70, 0xD4, 0x57, 0x15, 0xFE, 0x19, 0xD4, 0x9B, 0x13, 0x78, + 0x8A, 0xF7, 0x21, 0xF1, 0xA2, 0xA2, 0x2D, 0xB3, 0x09, 0xCF, 0x44, 0x91, + 0x6E, 0x08, 0x3A, 0x30, 0x81, 0x3E, 0x90, 0x93, 0x8A, 0x67, 0x33, 0x00, + 0x59, 0x54, 0x9A, 0x25, 0xD3, 0x49, 0x8E, 0x9F, 0xC1, 0x4B, 0xE5, 0x86, + 0xF3, 0x50, 0x4C, 0xBC, 0xC5, 0xD3, 0xF5, 0x3A, 0x54, 0xE1, 0x36, 0x3F, + 0xE2, 0x5A, 0xB4, 0x37, 0xC0, 0xEB, 0x70, 0x35, 0xEC, 0xF6, 0xB7, 0xE8, + 0x44, 0x3B, 0x7B, 0xF3, 0xF1, 0xF2, 0x1E, 0xDB, 0x60, 0x7D, 0xD5, 0xBE, + 0xF0, 0x71, 0x34, 0x90, 0x4C, 0xCB, 0xD4, 0x35, 0x51, 0xC7, 0xDD, 0xD8, + 0xC9, 0x81, 0xF5, 0x5D, 0x57, 0x46, 0x2C, 0xB1, 0x7B, 0x9B, 0xAA, 0xCB, + 0xD1, 0x22, 0x25, 0x49, 0x44, 0xA3, 0xD4, 0x6B, 0x29, 0x7B, 0xD8, 0xB2, + 0x07, 0x93, 0xBF, 0x3D, 0x52, 0x49, 0x84, 0x79, 0xEF, 0xB8, 0xE5, 0xC4, + 0xAD, 0xCA, 0xA8, 0xC6, 0xF6, 0xA6, 0x76, 0x70, 0x5B, 0x0B, 0xE5, 0x83, + 0xC6, 0x0E, 0xEF, 0x55, 0xF2, 0xE7, 0xFF, 0x04, 0xEA, 0xE6, 0x13, 0xBE, + 0x40, 0xE1, 0x40, 0x45, 0x48, 0x66, 0x75, 0x31, 0xAE, 0x35, 0x64, 0x91, + 0x11, 0x6F, 0xDA, 0xEE, 0x26, 0x86, 0x45, 0x6F, 0x0B, 0xD5, 0x9F, 0x03, + 0xB1, 0x65, 0x5B, 0xDB, 0xA4, 0xE4, 0xF9, 0x45, +}; + +/* + * Offset in the scattered buffer of byte 'op_byte' (0 = least significant) + * of the operand whose region starts 'region' dwords into each 12-dword + * block (0 = exp, 4 = mod, 8 = data). Reproduces the byte layout the ACRY + * engine mandates, so the test lays out its DMA input and decodes the + * result the same way the hardware does. + */ +static int acry_operand_offset(int region, int op_byte) +{ + int byte_in_dword; + int op_dword; + int offset; + int block; + int lane; + + op_dword = op_byte / ACRY_BYTES_PER_DWORD; + byte_in_dword = op_byte % ACRY_BYTES_PER_DWORD; + block = op_dword / ACRY_LANES_PER_BLOCK; + lane = op_dword % ACRY_LANES_PER_BLOCK; + + offset = (block * ACRY_DWORDS_PER_BLOCK + region + lane) + * ACRY_BYTES_PER_DWORD + byte_in_dword; + g_assert_cmpint(offset, <, ACRY_SRAM_SIZE); + + return offset; +} + +/* + * Write a big-endian (most significant byte first) bignum of 'be_len' bytes + * into the scattered buffer region 'region' (exp, mod, or data), placing + * significance level k at acry_operand_offset(region, k). + */ +static void put_bignum_be_bytes(uint8_t *buf, int region, + const uint8_t *be, int be_len) +{ + int be_index; + int offset; + int k; + + /* be[0] (MSB) maps to the highest level; be_index walks up from 0. */ + be_index = 0; + for (k = be_len - 1; k >= 0; k--) { + offset = acry_operand_offset(region, k); + buf[offset] = be[be_index++]; + } +} + +/* Inverse of put_bignum_be_bytes(): gather a big-endian bignum back out. */ +static void get_bignum_be_bytes(const uint8_t *buf, int region, + uint8_t *out_be, int be_len) +{ + int be_index; + int offset; + int k; + + /* Inverse of put_bignum_be_bytes(): highest level -> out_be[0] (MSB). */ + be_index = 0; + for (k = be_len - 1; k >= 0; k--) { + offset = acry_operand_offset(region, k); + out_be[be_index++] = buf[offset]; + } +} + +typedef struct AspeedACRYModExp { + const char *name; + const uint8_t *n; + size_t n_len; + const uint8_t *e; + size_t e_len; + const uint8_t *m; + size_t m_len; + const uint8_t *c; + size_t c_len; +} AspeedACRYModExp; + +static const AspeedACRYModExp acry_modexp_tests[] = { + { + .name = "modexp_rsa2048", + .n = rsa2048_n, + .n_len = sizeof(rsa2048_n), + .e = rsa_e, + .e_len = sizeof(rsa_e), + .m = rsa_m, + .m_len = sizeof(rsa_m), + .c = rsa2048_c, + .c_len = sizeof(rsa2048_c), + }, + { + .name = "modexp_rsa4096", + .n = rsa4096_n, + .n_len = sizeof(rsa4096_n), + .e = rsa_e, + .e_len = sizeof(rsa_e), + .m = rsa_m, + .m_len = sizeof(rsa_m), + .c = rsa4096_c, + .c_len = sizeof(rsa4096_c), + }, +}; + +typedef struct AspeedACRYTest { + const char *machine; + uint64_t dram_addr; + uint64_t sram_addr; + uint64_t acry_addr; + int index; +} AspeedACRYTest; + +static void test_modexp_rsa(const void *opaque) +{ + const AspeedACRYTest *c = opaque; + const AspeedACRYModExp *t = &acry_modexp_tests[c->index]; + QCryptoAkCipherOptions opts = { + .alg = QCRYPTO_AK_CIPHER_ALGO_RSA, + .u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW, + }; + uint8_t dram_buf[ACRY_SRAM_SIZE] = { 0 }; + uint8_t sram_buf[ACRY_SRAM_SIZE] = { 0 }; + uint8_t result[ACRY_MAX_BYTES] = { 0 }; + QTestState *qts; + + if (!qcrypto_akcipher_supports(&opts)) { + g_test_skip("raw RSA not supported by the crypto backend"); + return; + } + + qts = qtest_init(c->machine); + + g_assert_cmpuint(t->c_len, <=, sizeof(result)); + + put_bignum_be_bytes(dram_buf, ACRY_EXP_OFFSET, t->e, t->e_len); + put_bignum_be_bytes(dram_buf, ACRY_MOD_OFFSET, t->n, t->n_len); + put_bignum_be_bytes(dram_buf, ACRY_DATA_OFFSET, t->m, t->m_len); + + qtest_memwrite(qts, c->dram_addr, dram_buf, sizeof(dram_buf)); + + qtest_writel(qts, c->acry_addr + ACRY_DMA_CMD, ACRY_DMA_CMD_DMEM_AHB); + qtest_writel(qts, c->acry_addr + ACRY_DMA_SRC, c->dram_addr); + qtest_writel(qts, c->acry_addr + ACRY_RSA_KEY_LEN, + ((uint32_t)(t->e_len * 8) << 16) | (uint32_t)(t->n_len * 8)); + qtest_writel(qts, c->acry_addr + ACRY_DMA_LEN, ACRY_SRAM_SIZE); + qtest_writel(qts, c->acry_addr + ACRY_INT_MASK, + ACRY_INT_MASK_RSA_ENG_MASK | ACRY_INT_MASK_RSA_DMA_MASK); + qtest_writel(qts, c->acry_addr + ACRY_DMA_CMD, ACRY_DMA_CMD_SRAM_MODE_RSA); + qtest_writel(qts, c->acry_addr + ACRY_TRIGGER, + ACRY_TRIGGER_RSA_START | ACRY_TRIGGER_RSA_DMA_DATA); + + /* Completion requires both RSA_ENG_DONE and RSA_DMA_DONE to be asserted. */ + g_assert_cmphex(qtest_readl(qts, c->acry_addr + ACRY_STATUS), ==, + ACRY_STATUS_RSA_DONE); + + qtest_memread(qts, c->sram_addr, sram_buf, sizeof(sram_buf)); + get_bignum_be_bytes(sram_buf, ACRY_DATA_OFFSET, result, t->c_len); + g_assert_cmpmem(result, t->c_len, t->c, t->c_len); + + /* Clear IRQ status and check it is deasserted */ + qtest_writel(qts, c->acry_addr + ACRY_STATUS, ACRY_STATUS_RSA_DONE); + g_assert_cmphex(qtest_readl(qts, c->acry_addr + ACRY_STATUS), ==, 0); + + qtest_quit(qts); +} + +static void aspeed_add_acry_tests(const char *prefix, const char *machine, + uint64_t acry_addr, uint64_t sram_addr, + uint64_t dram_addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(acry_modexp_tests); i++) { + g_autofree char *path = NULL; + AspeedACRYTest *t; + + path = g_strdup_printf("%s/acry/%s", prefix, + acry_modexp_tests[i].name); + t = g_new0(AspeedACRYTest, 1); + t->machine = machine; + t->acry_addr = acry_addr; + t->sram_addr = sram_addr; + t->dram_addr = dram_addr; + t->index = i; + qtest_add_data_func_full(path, t, test_modexp_rsa, g_free); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + aspeed_add_acry_tests("ast2600", "-machine ast2600-evb", + 0x1e6fa000, 0x1e710000, 0x80001000); + + return g_test_run(); +} diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 260eec043c..d20562fac9 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -1248,11 +1248,18 @@ static void aspeed_test_crypto(const void *data) { const AspeedCryptoTest *c = data; const CryptTest *t = &crypt_tests[c->index]; - QTestState *s = qtest_init(c->machine); + QTestState *s; uint8_t out[64]; uint8_t iv[16]; size_t iv_off; + if (!qcrypto_cipher_supports(t->alg, t->mode)) { + g_test_skip("cipher not supported by the crypto backend"); + return; + } + + s = qtest_init(c->machine); + g_assert_cmpuint(t->len, <=, sizeof(out)); /* Encrypt: ptext -> ctext */ @@ -1284,10 +1291,17 @@ static void aspeed_test_crypto_gcm(const void *data) { const AspeedCryptoTest *c = data; const CryptTest *t = &crypt_tests[c->index]; - QTestState *s = qtest_init(c->machine); + QTestState *s; uint8_t out[64]; uint8_t tag[16]; + if (!qcrypto_cipher_supports(t->alg, t->mode)) { + g_test_skip("cipher not supported by the crypto backend"); + return; + } + + s = qtest_init(c->machine); + g_assert_cmpuint(t->len, <=, sizeof(out)); /* Encrypt: ptext -> ctext, then check the authentication tag. */ @@ -1318,12 +1332,6 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine, 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); diff --git a/tests/qtest/aspeed-sbc-test.c b/tests/qtest/aspeed-sbc-test.c new file mode 100644 index 0000000000..c445dac47a --- /dev/null +++ b/tests/qtest/aspeed-sbc-test.c @@ -0,0 +1,194 @@ +/* + * QTest testcase for the ASPEED Secure Boot Controller (SBC) + * + * Copyright (C) 2026 ASPEED Technology Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bitops.h" +#include "crypto/akcipher.h" + +/* SBC register block */ +#define SBC_STATUS 0x014 +#define SBC_ECDSA_VERIFY_PASS BIT(21) +#define SBC_ECDSA_VERIFY_DONE BIT(20) +#define SBC_SEC_TRIGGER 0x0bc +#define SBC_ECDSA_CMD_TRIGGER BIT(1) + +/* + * SEC SRAM operand offsets for a secp384r1 ECDSA verify. Every operand is a + * 48-byte big-endian integer. + */ +#define ECDSA_SRAM_QX 0x2080 +#define ECDSA_SRAM_QY 0x20c0 +#define ECDSA_SRAM_R 0x21c0 +#define ECDSA_SRAM_S 0x2200 +#define ECDSA_SRAM_M 0x2240 + +/* + * ECDSA secp384r1 / SHA-384 known-answer vector from the Linux kernel crypto + * self-test manager (ecdsa_nist_p384_tv_template, sha384 entry in + * crypto/testmgr.h, v6.18), decoded into raw big-endian form: public key + * Qx || Qy, signature r || s and the SHA-384 message digest. + * + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.h?h=v6.18 + */ +static const uint8_t ecdsa_p384_pubkey[96] = { + /* Qx */ + 0x3a, 0x2f, 0x62, 0xe7, 0x1a, 0xcf, 0x24, 0xd0, + 0x0b, 0x7c, 0xe0, 0xed, 0x46, 0x0a, 0x4f, 0x74, + 0x16, 0x43, 0xe9, 0x1a, 0x25, 0x7c, 0x55, 0xff, + 0xf0, 0x29, 0x68, 0x66, 0x20, 0x91, 0xf9, 0xdb, + 0x2b, 0xf6, 0xb3, 0x6c, 0x54, 0x01, 0xca, 0xc7, + 0x6a, 0x5c, 0x0d, 0xeb, 0x68, 0xd9, 0x3c, 0xf1, + /* Qy */ + 0x01, 0x74, 0x1f, 0xf9, 0x6c, 0xe5, 0x5b, 0x60, + 0xe9, 0x7f, 0x5d, 0xb3, 0x12, 0x80, 0x2a, 0xd8, + 0x67, 0x92, 0xc9, 0x0e, 0x4c, 0x4c, 0x6b, 0xa1, + 0xb2, 0xa8, 0x1e, 0xac, 0x1c, 0x97, 0xd9, 0x21, + 0x67, 0xe5, 0x1b, 0x5a, 0x52, 0x31, 0x68, 0xd6, + 0xee, 0xf0, 0x19, 0xb0, 0x55, 0xed, 0x89, 0x9e, +}; + +static const uint8_t ecdsa_p384_signature[96] = { + /* r */ + 0x9b, 0x28, 0x68, 0xc0, 0xa1, 0xea, 0x8c, 0x50, + 0xee, 0x2e, 0x62, 0x35, 0x46, 0xfa, 0x00, 0xd8, + 0x2d, 0x7a, 0x91, 0x5f, 0x49, 0x2d, 0x22, 0x08, + 0x29, 0xe6, 0xfb, 0xca, 0x8c, 0xd6, 0xb6, 0xb4, + 0x3b, 0x1f, 0x07, 0x8f, 0x15, 0x02, 0xfe, 0x1d, + 0xa2, 0xa4, 0xc8, 0xf2, 0xea, 0x9d, 0x11, 0x1f, + /* s */ + 0xfc, 0x50, 0xf6, 0x43, 0xbd, 0x50, 0x82, 0x0e, + 0xbf, 0xe3, 0x75, 0x24, 0x49, 0xac, 0xfb, 0xc8, + 0x71, 0xcd, 0x8f, 0x18, 0x99, 0xf0, 0x0f, 0x13, + 0x44, 0x92, 0x8c, 0x86, 0x99, 0x65, 0xb3, 0x97, + 0x96, 0x17, 0x04, 0xc9, 0x05, 0x77, 0xf1, 0x8e, + 0xab, 0x8d, 0x4e, 0xde, 0xe6, 0x6d, 0x9b, 0x66, +}; + +static const uint8_t ecdsa_p384_dgst[48] = { + 0x8d, 0xf2, 0xc0, 0xe9, 0xa8, 0xf3, 0x8e, 0x44, + 0xc4, 0x8c, 0x1a, 0xa0, 0xb8, 0xd7, 0x17, 0xdf, + 0xf2, 0x37, 0x1b, 0xc6, 0xe3, 0xf5, 0x62, 0xcc, + 0x68, 0xf5, 0xd5, 0x0b, 0xbf, 0x73, 0x2b, 0xb1, + 0xb0, 0x4c, 0x04, 0x00, 0x31, 0xab, 0xfe, 0xc8, + 0xd6, 0x09, 0xc8, 0xf2, 0xea, 0xd3, 0x28, 0xff, +}; + +typedef struct AspeedSBCECDSA { + const char *name; + QCryptoCurveID curve_id; + const uint8_t *pubkey; + const uint8_t *signature; + const uint8_t *dgst; + size_t coord_len; +} AspeedSBCECDSA; + +static const AspeedSBCECDSA sbc_ecdsa_tests[] = { + { + .name = "secp384r1", + .curve_id = QCRYPTO_CURVE_ID_SECP384R1, + .pubkey = ecdsa_p384_pubkey, + .signature = ecdsa_p384_signature, + .dgst = ecdsa_p384_dgst, + .coord_len = 48, + }, +}; + +typedef struct AspeedSBCTest { + const char *machine; + uint32_t sec_addr; + uint64_t sram_addr; + int index; +} AspeedSBCTest; + +static void sbc_ecdsa_stage(QTestState *qts, const AspeedSBCTest *c, + const AspeedSBCECDSA *t) +{ + uint32_t len = t->coord_len; + + qtest_memwrite(qts, c->sram_addr + ECDSA_SRAM_QX, t->pubkey, len); + qtest_memwrite(qts, c->sram_addr + ECDSA_SRAM_QY, t->pubkey + len, len); + qtest_memwrite(qts, c->sram_addr + ECDSA_SRAM_R, t->signature, len); + qtest_memwrite(qts, c->sram_addr + ECDSA_SRAM_S, t->signature + len, len); + qtest_memwrite(qts, c->sram_addr + ECDSA_SRAM_M, t->dgst, len); +} + +/* + * Drive one ECDSA verify through the engine the way the firmware does: + * stage the operands in the SEC SRAM, trigger the command register and read + * back the done/pass bits in the status register. + */ +static void test_ecdsa_verify(const void *opaque) +{ + const AspeedSBCTest *c = opaque; + const AspeedSBCECDSA *t = &sbc_ecdsa_tests[c->index]; + QCryptoAkCipherOptions opts = { + .alg = QCRYPTO_AK_CIPHER_ALGO_ECDSA, + .u.ecdsa.curve_id = t->curve_id, + }; + QTestState *qts; + uint32_t status; + uint8_t bad; + + if (!qcrypto_akcipher_supports(&opts)) { + g_test_skip("ECDSA is not supported by the crypto backend"); + return; + } + + qts = qtest_init(c->machine); + + /* A valid signature verifies */ + sbc_ecdsa_stage(qts, c, t); + qtest_writel(qts, c->sec_addr + SBC_SEC_TRIGGER, SBC_ECDSA_CMD_TRIGGER); + status = qtest_readl(qts, c->sec_addr + SBC_STATUS); + g_assert_cmphex(status & (SBC_ECDSA_VERIFY_DONE | SBC_ECDSA_VERIFY_PASS), + ==, SBC_ECDSA_VERIFY_DONE | SBC_ECDSA_VERIFY_PASS); + + /* A tampered signature must fail */ + bad = t->signature[0] ^ 0xff; + qtest_memwrite(qts, c->sram_addr + ECDSA_SRAM_R, &bad, 1); + qtest_writel(qts, c->sec_addr + SBC_SEC_TRIGGER, SBC_ECDSA_CMD_TRIGGER); + status = qtest_readl(qts, c->sec_addr + SBC_STATUS); + g_assert_cmphex(status & SBC_ECDSA_VERIFY_DONE, ==, SBC_ECDSA_VERIFY_DONE); + g_assert_cmphex(status & SBC_ECDSA_VERIFY_PASS, ==, 0); + + qtest_quit(qts); +} + +static void aspeed_add_sbc_ecdsa_tests(const char *prefix, const char *machine, + uint32_t sec_addr, uint64_t sram_addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sbc_ecdsa_tests); i++) { + g_autofree char *path = NULL; + AspeedSBCTest *t; + + path = g_strdup_printf("%s/sbc/ecdsa/%s", prefix, + sbc_ecdsa_tests[i].name); + t = g_new0(AspeedSBCTest, 1); + t->machine = machine; + t->sec_addr = sec_addr; + t->sram_addr = sram_addr; + t->index = i; + qtest_add_data_func_full(path, t, test_ecdsa_verify, g_free); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + aspeed_add_sbc_ecdsa_tests("ast1030", "-machine ast1030-evb", + 0x7e6f2000, 0x79000000); + + aspeed_add_sbc_ecdsa_tests("ast1060", "-machine ast1060-evb", + 0x7e6f2000, 0x79000000); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 17870e339b..c3593f7530 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -230,8 +230,10 @@ qtests_npcm7xx = \ qtests_npcm8xx = \ ['npcm_gmac-test'] qtests_aspeed = \ - ['aspeed_gpio-test', + ['aspeed-acry-test', + 'aspeed_gpio-test', 'aspeed_hace-test', + 'aspeed-sbc-test', 'aspeed_scu-test', 'aspeed_smc-test'] qtests_aspeed64 = \ @@ -402,8 +404,11 @@ if get_option('replication').allowed() endif qtests = { + 'aspeed-acry-test': [files('aspeed-acry-test.c'), + crypto], 'aspeed_hace-test': [files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), crypto], + 'aspeed-sbc-test': [files('aspeed-sbc-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'), crypto], diff --git a/tests/qtest/tmp105-test.c b/tests/qtest/tmp105-test.c index 3b114a50f5..504f6b7202 100644 --- a/tests/qtest/tmp105-test.c +++ b/tests/qtest/tmp105-test.c @@ -17,6 +17,24 @@ #define TMP105_TEST_ID "tmp105-test" #define TMP105_TEST_ADDR 0x49 +#define TMP105_TEST_PATH "/machine/peripheral/" TMP105_TEST_ID + +#define TMP75_TEST_ID "tmp75-test" +#define TMP75_TEST_PATH "/machine/peripheral/" TMP75_TEST_ID + +#define TMP175_TEST_ID "tmp175-test" +#define TMP175_TEST_PATH "/machine/peripheral/" TMP175_TEST_ID + +#define LM75B_TEST_ID "lm75b-test" +#define LM75B_TEST_PATH "/machine/peripheral/" LM75B_TEST_ID + +#define TMP105_CONFIG_POL (1 << 2) /* ALERT active-high when set */ +#define TMP105_CONFIG_TM (1 << 1) /* interrupt (thermostat) mode */ +#define TMP105_CONFIG_FQ_1 (0 << 3) /* fault queue: 1 consecutive fault */ +#define TMP105_CONFIG_FQ_4 (2 << 3) /* fault queue: 4 consecutive faults */ +#define TMP105_CONFIG_FQ(f) ((f) << 3) /* raw F1:F0 fault-queue field value */ +#define TMP105_CONFIG_SD (1 << 0) /* shutdown mode */ +#define TMP105_CONFIG_OS (1 << 7) /* one-shot conversion */ static int qmp_tmp105_get_temperature(const char *id) { @@ -105,6 +123,302 @@ static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4230); } +/* + * The TMP105 exposes its alarm state only through the ALERT pin. + */ +static void test_alert_single_fault(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + + qtest_irq_intercept_out(global_qtest, TMP105_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_FQ_1); + g_assert_false(get_irq(0)); + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_true(get_irq(0)); + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 70000); + g_assert_false(get_irq(0)); +} + +static void test_fault_queue(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + int i; + + qtest_irq_intercept_out(global_qtest, TMP105_TEST_PATH); + + /* Comparator mode, active-high ALERT, fault queue of four. */ + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_FQ_4); + g_assert_false(get_irq(0)); + + for (i = 0; i < 3; i++) { + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_false(get_irq(0)); + } + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 25000); + g_assert_false(get_irq(0)); + + for (i = 0; i < 3; i++) { + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_false(get_irq(0)); + } + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_true(get_irq(0)); + + for (i = 0; i < 3; i++) { + qmp_tmp105_set_temperature(TMP105_TEST_ID, 70000); + g_assert_true(get_irq(0)); + } + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 70000); + g_assert_false(get_irq(0)); +} + +/* + * Drive @need consecutive over-limit conversions and check that the ALERT pin + * only asserts on the last one. This exercises the fault-queue length. + */ +static void check_fault_queue(QI2CDevice *i2cdev, const char *id, + const char *path, uint8_t fq_field, int need) +{ + int i; + + qtest_irq_intercept_out(global_qtest, path); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ(fq_field)); + g_assert_false(get_irq(0)); + + for (i = 0; i < need - 1; i++) { + qmp_tmp105_set_temperature(id, 85000); + g_assert_false(get_irq(0)); + } + qmp_tmp105_set_temperature(id, 85000); + g_assert_true(get_irq(0)); +} + +/* + * The one-shot (OS) bit starts a conversion only in shutdown mode. In + * continuous mode it is ignored, so writing it must not advance the fault + * queue; in shutdown each OS write performs one conversion that does. + */ +static void test_one_shot(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + int i; + + qtest_irq_intercept_out(global_qtest, TMP105_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_FQ_4); + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_false(get_irq(0)); + + for (i = 0; i < 8; i++) { + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ_4 | TMP105_CONFIG_OS); + g_assert_false(get_irq(0)); + } + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ_4 | TMP105_CONFIG_SD); + for (i = 0; i < 2; i++) { + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | + TMP105_CONFIG_FQ_4 | TMP105_CONFIG_SD | TMP105_CONFIG_OS); + g_assert_false(get_irq(0)); + } + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | + TMP105_CONFIG_FQ_4 | TMP105_CONFIG_SD | TMP105_CONFIG_OS); + g_assert_true(get_irq(0)); +} + +/* + * Configuration and limit-register writes are not conversions and must not + * advance the fault queue. + */ +static void test_fault_queue_ignores_writes(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + int i; + + qtest_irq_intercept_out(global_qtest, TMP105_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_FQ_4); + g_assert_false(get_irq(0)); + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_false(get_irq(0)); + + for (i = 0; i < 8; i++) { + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ_4); + i2c_set16(i2cdev, TMP105_REG_T_HIGH, 0x5000); + i2c_set16(i2cdev, TMP105_REG_T_LOW, 0x4b00); + g_assert_false(get_irq(0)); + } + + for (i = 0; i < 2; i++) { + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_false(get_irq(0)); + } + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_true(get_irq(0)); +} + +/* + * Leaving shutdown (SD 1->0) resumes continuous conversion, which must + * re-evaluate the current temperature against the limits. + */ +static void test_wake_from_shutdown(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + + qtest_irq_intercept_out(global_qtest, TMP105_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_FQ_1); + g_assert_false(get_irq(0)); + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 85000); + g_assert_true(get_irq(0)); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ_1 | TMP105_CONFIG_SD); + g_assert_true(get_irq(0)); + + qmp_tmp105_set_temperature(TMP105_TEST_ID, 70000); + g_assert_true(get_irq(0)); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_FQ_1); + g_assert_false(get_irq(0)); +} + +/* The TMP75 maps F1:F0 = 10b to 3 consecutive faults. */ +static void test_tmp75_fault_queue(void *obj, void *data, + QGuestAllocator *alloc) +{ + check_fault_queue(obj, TMP75_TEST_ID, TMP75_TEST_PATH, 2, 3); +} + +/* The TMP175 keeps the TMP105 mapping: F1:F0 = 10b means 4 faults. */ +static void test_tmp175_fault_queue(void *obj, void *data, + QGuestAllocator *alloc) +{ + check_fault_queue(obj, TMP175_TEST_ID, TMP175_TEST_PATH, 2, 4); +} + +/* + * Toggling the thermostat mode (TM) bit clears any active alert on the TMP75. + */ +static void test_tmp75_tm_clears_alert(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + int i; + + qtest_irq_intercept_out(global_qtest, TMP75_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ(3)); + for (i = 0; i < 4; i++) { + qmp_tmp105_set_temperature(TMP75_TEST_ID, 85000); + } + g_assert_true(get_irq(0)); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ(3) | TMP105_CONFIG_TM); + g_assert_false(get_irq(0)); +} + +/* + * Entering shutdown clears the ALERT in interrupt mode but leaves it asserted + * in comparator mode. + */ +static void test_tmp75_shutdown_clears_alert(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + int i; + + qtest_irq_intercept_out(global_qtest, TMP75_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_TM | TMP105_CONFIG_FQ(3)); + for (i = 0; i < 4; i++) { + qmp_tmp105_set_temperature(TMP75_TEST_ID, 85000); + } + g_assert_true(get_irq(0)); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_TM | TMP105_CONFIG_FQ(3) | + TMP105_CONFIG_SD); + g_assert_false(get_irq(0)); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ(3)); + for (i = 0; i < 4; i++) { + qmp_tmp105_set_temperature(TMP75_TEST_ID, 85000); + } + g_assert_true(get_irq(0)); + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_FQ(3) | TMP105_CONFIG_SD); + g_assert_true(get_irq(0)); +} + +/* + * The LM75B has a fixed 11-bit (0.125 C) converter: the resolution and one-shot + * Config bits are reserved (read/write as zero) and the temperature register is + * always masked to 11 bits regardless of what is written to Config. + */ +static void test_lm75b_resolution(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + uint16_t value; + + i2c_set8(i2cdev, TMP105_REG_CONFIG, 0x60); + g_assert_cmphex(i2c_get8(i2cdev, TMP105_REG_CONFIG), ==, 0x00); + + qmp_tmp105_set_temperature(LM75B_TEST_ID, 20938); + value = i2c_get16(i2cdev, TMP105_REG_TEMPERATURE); + g_assert_cmphex(value, ==, 0x14e0); +} + +/* The LM75B set-point registers store only 9 bits. */ +static void test_lm75b_limits(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + + i2c_set16(i2cdev, TMP105_REG_T_HIGH, 0x4231); + g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4200); + + i2c_set16(i2cdev, TMP105_REG_T_LOW, 0x12b4); + g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1280); +} + +/* The LM75B likewise resets its OS output on shutdown in interrupt mode. */ +static void test_lm75b_shutdown_clears_alert(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + + qtest_irq_intercept_out(global_qtest, LM75B_TEST_PATH); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, TMP105_CONFIG_POL | TMP105_CONFIG_TM); + qmp_tmp105_set_temperature(LM75B_TEST_ID, 85000); + g_assert_true(get_irq(0)); + + i2c_set8(i2cdev, TMP105_REG_CONFIG, + TMP105_CONFIG_POL | TMP105_CONFIG_TM | TMP105_CONFIG_SD); + g_assert_false(get_irq(0)); +} + static void tmp105_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -116,5 +430,50 @@ static void tmp105_register_nodes(void) qos_node_consumes("tmp105", "i2c-bus", &opts); qos_add_test("tx-rx", "tmp105", send_and_receive, NULL); + qos_add_test("alert-single-fault", "tmp105", test_alert_single_fault, NULL); + qos_add_test("fault-queue", "tmp105", test_fault_queue, NULL); + qos_add_test("fault-queue-ignores-writes", "tmp105", + test_fault_queue_ignores_writes, NULL); + qos_add_test("one-shot", "tmp105", test_one_shot, NULL); + qos_add_test("wake-from-shutdown", "tmp105", test_wake_from_shutdown, NULL); + + /* TMP75: register-compatible, but with a 1/2/3/4 fault queue. */ + QOSGraphEdgeOptions tmp75_opts = { + .extra_device_opts = "id=" TMP75_TEST_ID ",address=0x48" + }; + add_qi2c_address(&tmp75_opts, &(QI2CAddress) { 0x48 }); + + qos_node_create_driver("tmp75", i2c_device_create); + qos_node_consumes("tmp75", "i2c-bus", &tmp75_opts); + + qos_add_test("fault-queue", "tmp75", test_tmp75_fault_queue, NULL); + qos_add_test("tm-clears-alert", "tmp75", test_tmp75_tm_clears_alert, NULL); + qos_add_test("shutdown-clears-alert", "tmp75", + test_tmp75_shutdown_clears_alert, NULL); + + /* TMP175: like the TMP105, with a 1/2/4/6 fault queue. */ + QOSGraphEdgeOptions tmp175_opts = { + .extra_device_opts = "id=" TMP175_TEST_ID ",address=0x4a" + }; + add_qi2c_address(&tmp175_opts, &(QI2CAddress) { 0x4a }); + + qos_node_create_driver("tmp175", i2c_device_create); + qos_node_consumes("tmp175", "i2c-bus", &tmp175_opts); + + qos_add_test("fault-queue", "tmp175", test_tmp175_fault_queue, NULL); + + /* LM75B: fixed 11-bit conversion and 9-bit set-point registers. */ + QOSGraphEdgeOptions lm75b_opts = { + .extra_device_opts = "id=" LM75B_TEST_ID ",address=0x4c" + }; + add_qi2c_address(&lm75b_opts, &(QI2CAddress) { 0x4c }); + + qos_node_create_driver("lm75b", i2c_device_create); + qos_node_consumes("lm75b", "i2c-bus", &lm75b_opts); + + qos_add_test("resolution", "lm75b", test_lm75b_resolution, NULL); + qos_add_test("limits", "lm75b", test_lm75b_limits, NULL); + qos_add_test("shutdown-clears-alert", "lm75b", + test_lm75b_shutdown_clears_alert, NULL); } libqos_init(tmp105_register_nodes); diff --git a/tests/unit/test-crypto-akcipher.c b/tests/unit/test-crypto-akcipher.c index 53c2211ba8..fb1a6163e9 100644 --- a/tests/unit/test-crypto-akcipher.c +++ b/tests/unit/test-crypto-akcipher.c @@ -658,6 +658,117 @@ static const uint8_t rsa_public_key_extra_elem[] = { 0x02, 0x06, 0xe1, 0x22, 0xdb, 0xe1, 0x22, 0xdb, }; +/* + * ECDSA known-answer vectors from RFC 6979 (Deterministic ECDSA), message + * "sample", decoded into raw big-endian form. The same key pair drives both + * the verify test (against the RFC's known signature) and the sign round-trip + * test: + * - private key: the scalar d (curve size) + * - public key: Qx || Qy (2 * curve size) + * - dgst: the message digest (curve size) + * - signature: r || s (2 * curve size) + * + * prime256v1 / SHA-256 (RFC 6979 A.2.5): + */ +static const uint8_t ecdsa_p256_privkey[32] = { + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, + 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1, 0xd6, 0x93, + 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, +}; + +static const uint8_t ecdsa_p256_pubkey[64] = { + 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, + 0xc9, 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, + 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, 0xfa, 0x6c, + 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, + 0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, + 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, 0xbc, 0x64, + 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, + 0x77, 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99, +}; + +static const uint8_t ecdsa_p256_dgst[32] = { + 0xaf, 0x2b, 0xdb, 0xe1, 0xaa, 0x9b, 0x6e, 0xc1, + 0xe2, 0xad, 0xe1, 0xd6, 0x94, 0xf4, 0x1f, 0xc7, + 0x1a, 0x83, 0x1d, 0x02, 0x68, 0xe9, 0x89, 0x15, + 0x62, 0x11, 0x3d, 0x8a, 0x62, 0xad, 0xd1, 0xbf, +}; + +static const uint8_t ecdsa_p256_signature[64] = { + 0xef, 0xd4, 0x8b, 0x2a, 0xac, 0xb6, 0xa8, 0xfd, + 0x11, 0x40, 0xdd, 0x9c, 0xd4, 0x5e, 0x81, 0xd6, + 0x9d, 0x2c, 0x87, 0x7b, 0x56, 0xaa, 0xf9, 0x91, + 0xc3, 0x4d, 0x0e, 0xa8, 0x4e, 0xaf, 0x37, 0x16, + 0xf7, 0xcb, 0x1c, 0x94, 0x2d, 0x65, 0x7c, 0x41, + 0xd4, 0x36, 0xc7, 0xa1, 0xb6, 0xe2, 0x9f, 0x65, + 0xf3, 0xe9, 0x00, 0xdb, 0xb9, 0xaf, 0xf4, 0x06, + 0x4d, 0xc4, 0xab, 0x2f, 0x84, 0x3a, 0xcd, 0xa8, +}; + +/* secp384r1 / SHA-384 (RFC 6979 A.2.6): */ +static const uint8_t ecdsa_p384_privkey[48] = { + 0x6b, 0x9d, 0x3d, 0xad, 0x2e, 0x1b, 0x8c, 0x1c, + 0x05, 0xb1, 0x98, 0x75, 0xb6, 0x65, 0x9f, 0x4d, + 0xe2, 0x3c, 0x3b, 0x66, 0x7b, 0xf2, 0x97, 0xba, + 0x9a, 0xa4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xd8, + 0x96, 0xd5, 0x72, 0x4e, 0x4c, 0x70, 0xa8, 0x25, + 0xf8, 0x72, 0xc9, 0xea, 0x60, 0xd2, 0xed, 0xf5, +}; + +static const uint8_t ecdsa_p384_pubkey[96] = { + 0xec, 0x3a, 0x4e, 0x41, 0x5b, 0x4e, 0x19, 0xa4, + 0x56, 0x86, 0x18, 0x02, 0x9f, 0x42, 0x7f, 0xa5, + 0xda, 0x9a, 0x8b, 0xc4, 0xae, 0x92, 0xe0, 0x2e, + 0x06, 0xaa, 0xe5, 0x28, 0x6b, 0x30, 0x0c, 0x64, + 0xde, 0xf8, 0xf0, 0xea, 0x90, 0x55, 0x86, 0x60, + 0x64, 0xa2, 0x54, 0x51, 0x54, 0x80, 0xbc, 0x13, + 0x80, 0x15, 0xd9, 0xb7, 0x2d, 0x7d, 0x57, 0x24, + 0x4e, 0xa8, 0xef, 0x9a, 0xc0, 0xc6, 0x21, 0x89, + 0x67, 0x08, 0xa5, 0x93, 0x67, 0xf9, 0xdf, 0xb9, + 0xf5, 0x4c, 0xa8, 0x4b, 0x3f, 0x1c, 0x9d, 0xb1, + 0x28, 0x8b, 0x23, 0x1c, 0x3a, 0xe0, 0xd4, 0xfe, + 0x73, 0x44, 0xfd, 0x25, 0x33, 0x26, 0x47, 0x20, +}; + +static const uint8_t ecdsa_p384_dgst[48] = { + 0x9a, 0x90, 0x83, 0x50, 0x5b, 0xc9, 0x22, 0x76, + 0xae, 0xc4, 0xbe, 0x31, 0x26, 0x96, 0xef, 0x7b, + 0xf3, 0xbf, 0x60, 0x3f, 0x4b, 0xbd, 0x38, 0x11, + 0x96, 0xa0, 0x29, 0xf3, 0x40, 0x58, 0x53, 0x12, + 0x31, 0x3b, 0xca, 0x4a, 0x9b, 0x5b, 0x89, 0x0e, + 0xfe, 0xe4, 0x2c, 0x77, 0xb1, 0xee, 0x25, 0xfe, +}; + +static const uint8_t ecdsa_p384_signature[96] = { + 0x94, 0xed, 0xbb, 0x92, 0xa5, 0xec, 0xb8, 0xaa, + 0xd4, 0x73, 0x6e, 0x56, 0xc6, 0x91, 0x91, 0x6b, + 0x3f, 0x88, 0x14, 0x06, 0x66, 0xce, 0x9f, 0xa7, + 0x3d, 0x64, 0xc4, 0xea, 0x95, 0xad, 0x13, 0x3c, + 0x81, 0xa6, 0x48, 0x15, 0x2e, 0x44, 0xac, 0xf9, + 0x6e, 0x36, 0xdd, 0x1e, 0x80, 0xfa, 0xbe, 0x46, + 0x99, 0xef, 0x4a, 0xeb, 0x15, 0xf1, 0x78, 0xce, + 0xa1, 0xfe, 0x40, 0xdb, 0x26, 0x03, 0x13, 0x8f, + 0x13, 0x0e, 0x74, 0x0a, 0x19, 0x62, 0x45, 0x26, + 0x20, 0x3b, 0x63, 0x51, 0xd0, 0xa3, 0xa9, 0x4f, + 0xa3, 0x29, 0xc1, 0x45, 0x78, 0x6e, 0x67, 0x9e, + 0x7b, 0x82, 0xc7, 0x1a, 0x38, 0x62, 0x8a, 0xc8, +}; + +typedef struct QCryptoECDSATestData QCryptoECDSATestData; +struct QCryptoECDSATestData { + const char *path; + QCryptoCurveID curve_id; + const uint8_t *priv_key; + size_t priv_key_len; + const uint8_t *pub_key; + size_t pub_key_len; + const uint8_t *dgst; + size_t dlen; + const uint8_t *signature; + size_t slen; +}; + typedef struct QCryptoRSAKeyTestData QCryptoRSAKeyTestData; struct QCryptoRSAKeyTestData { const char *path; @@ -969,6 +1080,120 @@ static void test_rsakey(const void *opaque) g_assert(qcrypto_akcipher_max_dgst_len(key) == data->exp_key_len); } +static QCryptoECDSATestData ecdsa_test_data[] = { + { + .path = "/crypto/akcipher/ecdsa-prime256v1", + .curve_id = QCRYPTO_CURVE_ID_PRIME256V1, + .priv_key = ecdsa_p256_privkey, + .priv_key_len = sizeof(ecdsa_p256_privkey), + .pub_key = ecdsa_p256_pubkey, + .pub_key_len = sizeof(ecdsa_p256_pubkey), + .dgst = ecdsa_p256_dgst, + .dlen = sizeof(ecdsa_p256_dgst), + .signature = ecdsa_p256_signature, + .slen = sizeof(ecdsa_p256_signature), + }, + { + .path = "/crypto/akcipher/ecdsa-secp384r1", + .curve_id = QCRYPTO_CURVE_ID_SECP384R1, + .priv_key = ecdsa_p384_privkey, + .priv_key_len = sizeof(ecdsa_p384_privkey), + .pub_key = ecdsa_p384_pubkey, + .pub_key_len = sizeof(ecdsa_p384_pubkey), + .dgst = ecdsa_p384_dgst, + .dlen = sizeof(ecdsa_p384_dgst), + .signature = ecdsa_p384_signature, + .slen = sizeof(ecdsa_p384_signature), + }, + /* Add more curves here as they gain backend support. */ +}; + +static void test_ecdsa_verify(const void *opaque) +{ + const QCryptoECDSATestData *data = opaque; + QCryptoAkCipherOptions opt = { + .alg = QCRYPTO_AK_CIPHER_ALGO_ECDSA, + .u.ecdsa = { + .curve_id = data->curve_id, + }, + }; + g_autoptr(QCryptoAkCipher) pub_key = NULL; + g_autofree uint8_t *signature = NULL; + g_autofree uint8_t *dgst = NULL; + + if (!qcrypto_akcipher_supports(&opt)) { + g_test_skip("ECDSA is not supported by the crypto backend"); + return; + } + + pub_key = qcrypto_akcipher_new(&opt, QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC, + data->pub_key, data->pub_key_len, + &error_abort); + g_assert(pub_key != NULL); + g_assert(qcrypto_akcipher_max_signature_len(pub_key) == data->slen); + g_assert(qcrypto_akcipher_max_dgst_len(pub_key) == data->dlen); + + /* A valid signature must verify. */ + g_assert(qcrypto_akcipher_verify(pub_key, data->signature, data->slen, + data->dgst, data->dlen, + &error_abort) == 0); + + /* A tampered signature must fail (error is expected, so ignore it). */ + signature = g_memdup2(data->signature, data->slen); + signature[0]++; + g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen, + data->dgst, data->dlen, NULL) != 0); + + /* A tampered digest must also fail. */ + dgst = g_memdup2(data->dgst, data->dlen); + dgst[0]++; + g_assert(qcrypto_akcipher_verify(pub_key, data->signature, data->slen, + dgst, data->dlen, NULL) != 0); +} + +static void test_ecdsa_sign(const void *opaque) +{ + const QCryptoECDSATestData *data = opaque; + QCryptoAkCipherOptions opt = { + .alg = QCRYPTO_AK_CIPHER_ALGO_ECDSA, + .u.ecdsa = { + .curve_id = data->curve_id, + }, + }; + g_autoptr(QCryptoAkCipher) priv_key = NULL; + g_autoptr(QCryptoAkCipher) pub_key = NULL; + g_autofree uint8_t *signature = NULL; + int slen; + + if (!qcrypto_akcipher_supports(&opt)) { + g_test_skip("ECDSA is not supported by the crypto backend"); + return; + } + + priv_key = qcrypto_akcipher_new(&opt, QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE, + data->priv_key, data->priv_key_len, + &error_abort); + g_assert(priv_key != NULL); + + /* + * Sign the digest. + * ECDSA signatures are randomized so only length is fixed. + */ + slen = qcrypto_akcipher_max_signature_len(priv_key); + signature = g_new0(uint8_t, slen); + g_assert(qcrypto_akcipher_sign(priv_key, data->dgst, data->dlen, + signature, slen, &error_abort) == slen); + + /* The freshly produced signature must verify with the public key. */ + pub_key = qcrypto_akcipher_new(&opt, QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC, + data->pub_key, data->pub_key_len, + &error_abort); + g_assert(pub_key != NULL); + g_assert(qcrypto_akcipher_verify(pub_key, signature, slen, + data->dgst, data->dlen, + &error_abort) == 0); +} + int main(int argc, char **argv) { size_t i; @@ -985,6 +1210,17 @@ int main(int argc, char **argv) &rsakey_test_data[i], test_rsakey); } + for (i = 0; i < G_N_ELEMENTS(ecdsa_test_data); i++) { + g_autofree char *verify_path = + g_strdup_printf("%s-verify", ecdsa_test_data[i].path); + g_autofree char *sign_path = + g_strdup_printf("%s-sign", ecdsa_test_data[i].path); + + g_test_add_data_func(verify_path, &ecdsa_test_data[i], + test_ecdsa_verify); + g_test_add_data_func(sign_path, &ecdsa_test_data[i], + test_ecdsa_sign); + } return g_test_run(); } |
