The Allwinner sunxi Crypto Engine found on the H616 includes an ECC engine which can verify ECDSA signatures. Add a UCLASS_ECDSA provider so FIT signature verification can use the hardware block from U-Boot proper and SPL.
The CE takes explicit curve parameters, so provide parameter tables for secp224r1, prime256v1, secp384r1 and secp521r1 using the curves accepted by U-Boot's FIT ECDSA parser. Extend the generic ECDSA signing and verification plumbing for the additional algorithm names and for non-32-bit coordinate sizes. The CE input buffer uses fixed-width curve fields. Reuse the parameter packing logic for the message digest as well, so wider digests are truncated to the leftmost curve-width bytes according to ECDSA rules. Signed-off-by: James Hilliard <[email protected]> --- MAINTAINERS | 1 + doc/mkimage.1 | 3 + doc/usage/fit/signature.rst | 3 +- drivers/crypto/Kconfig | 26 ++ drivers/crypto/Makefile | 1 + drivers/crypto/sunxi_ecdsa.c | 612 +++++++++++++++++++++++++++++++++ include/u-boot/ecdsa.h | 16 + include/u-boot/fdt-libcrypto.h | 4 +- lib/ecdsa/Kconfig | 2 +- lib/ecdsa/ecdsa-libcrypto.c | 109 +++--- lib/ecdsa/ecdsa-verify.c | 33 +- lib/fdt-libcrypto.c | 57 +-- tools/image-sig-host.c | 7 + 13 files changed, 764 insertions(+), 110 deletions(-) create mode 100644 drivers/crypto/sunxi_ecdsa.c diff --git a/MAINTAINERS b/MAINTAINERS index 370bcff56c1..d62252e1d1b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -770,6 +770,7 @@ F: arch/arm/include/asm/arch-sunxi/ F: arch/arm/mach-sunxi/ F: board/sunxi/ F: drivers/clk/sunxi/ +F: drivers/crypto/sunxi_ecdsa.c F: drivers/phy/allwinner/ F: drivers/pinctrl/sunxi/ F: drivers/video/sunxi/ diff --git a/doc/mkimage.1 b/doc/mkimage.1 index 9a2d07cee75..b6ba88dd314 100644 --- a/doc/mkimage.1 +++ b/doc/mkimage.1 @@ -459,7 +459,10 @@ lb. rsa2048 rsa3072 rsa4096 +ecdsa224 ecdsa256 +ecdsa384 +secp521r1 .TE .RE . diff --git a/doc/usage/fit/signature.rst b/doc/usage/fit/signature.rst index da08cc75c3a..4f35f44bc8a 100644 --- a/doc/usage/fit/signature.rst +++ b/doc/usage/fit/signature.rst @@ -132,7 +132,8 @@ rsa,n0-inverse For ECDSA the following are mandatory: ecdsa,curve - Name of ECDSA curve (e.g. "prime256v1") + Name of ECDSA curve, such as "secp224r1", "prime256v1", + "secp384r1", or "secp521r1" ecdsa,x-point Public key X coordinate as a big-endian multi-word integer diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0d58e3910fe..9b0a4f18e24 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -6,6 +6,32 @@ source "drivers/crypto/aes/Kconfig" source "drivers/crypto/fsl/Kconfig" +config SUNXI_ECDSA + bool "Allwinner sunxi CE ECDSA verifier" + depends on ARCH_SUNXI + depends on ECDSA_VERIFY + depends on CLK && DM_RESET + help + Select this option to enable ECDSA signature verification using + the Crypto Engine found in Allwinner sunxi SoCs. FIT image + signatures can then be checked by the hardware accelerator in + U-Boot proper. Digests wider than the selected curve are + truncated according to ECDSA rules. + +config SPL_SUNXI_ECDSA + bool "Allwinner sunxi CE ECDSA verifier in SPL" + depends on ARCH_SUNXI + depends on SPL_DM + depends on SPL_OF_CONTROL + depends on SPL_ECDSA_VERIFY + select SPL_CRYPTO + help + Select this option to enable ECDSA signature verification in SPL + using the Crypto Engine found in Allwinner sunxi SoCs. This allows + SPL FIT image signatures to be checked by the hardware accelerator + before U-Boot proper is loaded. Digests wider than the selected + curve are truncated according to ECDSA rules. + source "drivers/crypto/aspeed/Kconfig" source "drivers/crypto/nuvoton/Kconfig" diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index e4a4482b7f3..88291ae235f 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -4,6 +4,7 @@ # http://www.samsung.com obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o +obj-$(CONFIG_$(PHASE_)SUNXI_ECDSA) += sunxi_ecdsa.o obj-y += aes/ obj-y += rsa_mod_exp/ obj-y += fsl/ diff --git a/drivers/crypto/sunxi_ecdsa.c b/drivers/crypto/sunxi_ecdsa.c new file mode 100644 index 00000000000..e74239d640c --- /dev/null +++ b/drivers/crypto/sunxi_ecdsa.c @@ -0,0 +1,612 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 James Hilliard + */ + +#include <cpu_func.h> +#include <crypto/ecdsa-uclass.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <reset.h> +#include <log.h> +#include <malloc.h> +#include <memalign.h> +#include <string.h> +#include <asm/cache.h> +#include <asm/arch/cpu.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> + +#define SUNXI_CE_TDA 0x00 +#define SUNXI_CE_ICR 0x08 +#define SUNXI_CE_ISR 0x0c +#define SUNXI_CE_TLR 0x10 +#define SUNXI_CE_ERR 0x18 + +#define SUNXI_CE_CHAN 0 +#define SUNXI_CE_CHAN_INT BIT(SUNXI_CE_CHAN) +#define SUNXI_CE_CHAN_ERR_MASK (0xff << (SUNXI_CE_CHAN * 8)) +#define SUNXI_CE_TASK_INT BIT(31) +#define SUNXI_CE_METHOD_ECC 33 +#define SUNXI_CE_TLR_METHOD_SHIFT 8 +#define SUNXI_CE_ECC_OP_VERIFY 7 +#define SUNXI_CE_ECC_OP_SHIFT 16 +#define SUNXI_CE_WORD_SHIFT 2 +#define SUNXI_CE_TIMEOUT_US 1000000 + +#define SUN50I_H616_CCU_CE_CLK 0x680 +#define SUN50I_H616_CCU_CE_BGR 0x68c +#define SUN50I_H616_CCU_MBUS_GATE 0x804 +#define SUN50I_H616_CCU_CE_CLK_SRC_PLL_PERIPH0_2X BIT(24) +#define SUN50I_H616_CCU_CE_CLK_N_MASK GENMASK(9, 8) +#define SUN50I_H616_CCU_CE_CLK_M_MASK GENMASK(3, 0) +#define SUN50I_H616_CCU_CE_CLK_M_4 3 +#define SUN50I_H616_CCU_CE_CLK_GATE BIT(31) +#define SUN50I_H616_CCU_CE_BUS_GATE BIT(0) +#define SUN50I_H616_CCU_CE_BUS_RST BIT(16) +#define SUN50I_H616_CCU_MBUS_GATE_CE BIT(2) + +#define SUNXI_ECDSA_PARAMS 12 +#define SUNXI_ECDSA_MAX_WORDS 17 +#define SUNXI_ECDSA_MAX_BYTES (SUNXI_ECDSA_MAX_WORDS * sizeof(u32)) +#define SUNXI_ECDSA_MAX_SRC_BYTES (SUNXI_ECDSA_PARAMS * SUNXI_ECDSA_MAX_BYTES) + +struct sunxi_ce_sg { + u32 addr; + u32 len; +}; + +struct sunxi_ce_task { + u32 chan_id; + u32 comm_ctl; + u32 sym_ctl; + u32 asym_ctl; + u32 key_addr; + u32 iv_addr; + u32 ctr_addr; + u32 data_len; + struct sunxi_ce_sg src[8]; + struct sunxi_ce_sg dst[8]; + u32 next; + u32 reserved[3]; +}; + +struct sunxi_ecdsa_job { + struct sunxi_ce_task task __aligned(ARCH_DMA_MINALIGN); + u8 src[SUNXI_ECDSA_MAX_SRC_BYTES] __aligned(ARCH_DMA_MINALIGN); + u8 dst[SUNXI_ECDSA_MAX_BYTES] __aligned(ARCH_DMA_MINALIGN); +}; + +struct sunxi_ecdsa_curve { + const char *name; + const u8 *p; + const u8 *a; + const u8 *gx; + const u8 *gy; + const u8 *n; + u16 bits; + u8 bytes; + u8 words; +}; + +struct sunxi_ecdsa_variant { + void (*spl_enable_clocks)(void); +}; + +struct sunxi_ecdsa_priv { + void __iomem *base; + const struct sunxi_ecdsa_variant *variant; + struct clk_bulk clks; + struct reset_ctl_bulk resets; +}; + +static const u8 ecdsa_p224_p[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, +}; + +static const u8 ecdsa_p224_a[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, +}; + +static const u8 ecdsa_p224_gx[] = { + 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, + 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, + 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, + 0x11, 0x5c, 0x1d, 0x21, +}; + +static const u8 ecdsa_p224_gy[] = { + 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, + 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, + 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, + 0x85, 0x00, 0x7e, 0x34, +}; + +static const u8 ecdsa_p224_n[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x3d, +}; + +static const u8 ecdsa_p256_p[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static const u8 ecdsa_p256_a[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, +}; + +static const u8 ecdsa_p256_gx[] = { + 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, +}; + +static const u8 ecdsa_p256_gy[] = { + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5, +}; + +static const u8 ecdsa_p256_n[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, + 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, +}; + +static const u8 ecdsa_p384_p[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +}; + +static const u8 ecdsa_p384_a[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, +}; + +static const u8 ecdsa_p384_gx[] = { + 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, +}; + +static const u8 ecdsa_p384_gy[] = { + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, +}; + +static const u8 ecdsa_p384_n[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, + 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, + 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73, +}; + +static const u8 ecdsa_p521_p[] = { + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, +}; + +static const u8 ecdsa_p521_a[] = { + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, +}; + +static const u8 ecdsa_p521_gx[] = { + 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, + 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, + 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, + 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, + 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, + 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, + 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, + 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, + 0xbd, 0x66, +}; + +static const u8 ecdsa_p521_gy[] = { + 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, + 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, + 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, + 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, + 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, + 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, + 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, + 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, + 0x66, 0x50, +}; + +static const u8 ecdsa_p521_n[] = { + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, + 0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, + 0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, + 0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, + 0x64, 0x09, +}; + +static const struct sunxi_ecdsa_curve sunxi_ecdsa_curves[] = { + { + .name = "secp224r1", + .bits = 224, + .bytes = 28, + .words = 7, + .p = ecdsa_p224_p, + .a = ecdsa_p224_a, + .gx = ecdsa_p224_gx, + .gy = ecdsa_p224_gy, + .n = ecdsa_p224_n, + }, { + .name = "prime256v1", + .bits = 256, + .bytes = 32, + .words = 8, + .p = ecdsa_p256_p, + .a = ecdsa_p256_a, + .gx = ecdsa_p256_gx, + .gy = ecdsa_p256_gy, + .n = ecdsa_p256_n, + }, { + .name = "secp384r1", + .bits = 384, + .bytes = 48, + .words = 12, + .p = ecdsa_p384_p, + .a = ecdsa_p384_a, + .gx = ecdsa_p384_gx, + .gy = ecdsa_p384_gy, + .n = ecdsa_p384_n, + }, { + .name = "secp521r1", + .bits = 521, + .bytes = 66, + .words = 17, + .p = ecdsa_p521_p, + .a = ecdsa_p521_a, + .gx = ecdsa_p521_gx, + .gy = ecdsa_p521_gy, + .n = ecdsa_p521_n, + }, +}; + +static const struct sunxi_ecdsa_curve * +sunxi_ecdsa_find_curve(const struct ecdsa_public_key *pubkey) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sunxi_ecdsa_curves); i++) { + if (!strcmp(pubkey->curve_name, sunxi_ecdsa_curves[i].name)) + return &sunxi_ecdsa_curves[i]; + } + + return NULL; +} + +static void sunxi_ecdsa_flush(void *buf, size_t len) +{ + ulong start = ALIGN_DOWN((ulong)buf, ARCH_DMA_MINALIGN); + ulong end = ALIGN((ulong)buf + len, ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +} + +static void sunxi_ecdsa_invalidate(void *buf, size_t len) +{ + ulong start = ALIGN_DOWN((ulong)buf, ARCH_DMA_MINALIGN); + ulong end = ALIGN((ulong)buf + len, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static u32 sunxi_ecdsa_word_addr(void *buf) +{ + return (u32)(virt_to_phys(buf) >> SUNXI_CE_WORD_SHIFT); +} + +static void sun50i_h616_ecdsa_spl_enable_clocks(void) +{ + void __iomem *ccu = (void __iomem *)SUNXI_CCM_BASE; + + clrsetbits_le32(ccu + SUN50I_H616_CCU_CE_CLK, + SUN50I_H616_CCU_CE_CLK_SRC_PLL_PERIPH0_2X | + SUN50I_H616_CCU_CE_CLK_N_MASK | + SUN50I_H616_CCU_CE_CLK_M_MASK, + SUN50I_H616_CCU_CE_CLK_GATE | + SUN50I_H616_CCU_CE_CLK_SRC_PLL_PERIPH0_2X | + SUN50I_H616_CCU_CE_CLK_M_4); + setbits_le32(ccu + SUN50I_H616_CCU_CE_BGR, + SUN50I_H616_CCU_CE_BUS_GATE | + SUN50I_H616_CCU_CE_BUS_RST); + setbits_le32(ccu + SUN50I_H616_CCU_MBUS_GATE, + SUN50I_H616_CCU_MBUS_GATE_CE); +} + +static void sunxi_ecdsa_spl_enable_clocks(struct sunxi_ecdsa_priv *priv) +{ + if (priv->variant && priv->variant->spl_enable_clocks) + priv->variant->spl_enable_clocks(); +} + +static void sunxi_ecdsa_copy_le_param(u8 **dst, + const struct sunxi_ecdsa_curve *curve, + const void *src, size_t len) +{ + const u8 *p = src; + size_t copy_len; + int i; + + copy_len = min_t(size_t, len, curve->bytes); + for (i = 0; i < copy_len; i++) + (*dst)[i] = p[copy_len - 1 - i]; + *dst += curve->words * sizeof(u32); +} + +static void sunxi_ecdsa_fill_src(struct sunxi_ecdsa_job *job, + const struct sunxi_ecdsa_curve *curve, + const struct ecdsa_public_key *pubkey, + const void *hash, size_t hash_len, + const void *signature) +{ + const u8 *r = signature; + const u8 *s = r + curve->bytes; + u8 *dst = job->src; + + sunxi_ecdsa_copy_le_param(&dst, curve, curve->n, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, s, curve->bytes); + /* ECDSA uses the leftmost bits when the digest is wider than the key. */ + sunxi_ecdsa_copy_le_param(&dst, curve, hash, hash_len); + sunxi_ecdsa_copy_le_param(&dst, curve, r, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, curve->p, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, curve->a, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, curve->gx, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, curve->gy, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, pubkey->x, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, pubkey->y, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, curve->n, curve->bytes); + sunxi_ecdsa_copy_le_param(&dst, curve, r, curve->bytes); +} + +static void sunxi_ecdsa_fill_task(struct sunxi_ecdsa_job *job, + const struct sunxi_ecdsa_curve *curve) +{ + struct sunxi_ce_task *task = &job->task; + u32 bytes = curve->words * sizeof(u32); + + task->chan_id = SUNXI_CE_CHAN; + task->comm_ctl = SUNXI_CE_TASK_INT | SUNXI_CE_METHOD_ECC; + task->asym_ctl = curve->words | + (SUNXI_CE_ECC_OP_VERIFY << SUNXI_CE_ECC_OP_SHIFT); + task->data_len = SUNXI_ECDSA_PARAMS * bytes; + task->src[0].addr = sunxi_ecdsa_word_addr(job->src); + task->src[0].len = task->data_len / sizeof(u32); + task->dst[0].addr = sunxi_ecdsa_word_addr(job->dst); + task->dst[0].len = curve->words; +} + +static int sunxi_ecdsa_run(struct sunxi_ecdsa_priv *priv, + struct sunxi_ecdsa_job *job) +{ + u32 val, err, result; + int ret; + + sunxi_ecdsa_flush(&job->task, sizeof(job->task)); + sunxi_ecdsa_flush(job->src, job->task.data_len); + sunxi_ecdsa_flush(job->dst, job->task.dst[0].len * sizeof(u32)); + + writel(SUNXI_CE_CHAN_INT, priv->base + SUNXI_CE_ISR); + writel(SUNXI_CE_CHAN_ERR_MASK, priv->base + SUNXI_CE_ERR); + writel(SUNXI_CE_CHAN_INT, priv->base + SUNXI_CE_ICR); + + writel(sunxi_ecdsa_word_addr(&job->task), priv->base + SUNXI_CE_TDA); + writel(BIT(0) | (SUNXI_CE_METHOD_ECC << SUNXI_CE_TLR_METHOD_SHIFT), + priv->base + SUNXI_CE_TLR); + + ret = readl_poll_timeout(priv->base + SUNXI_CE_ISR, val, + val & SUNXI_CE_CHAN_INT, + SUNXI_CE_TIMEOUT_US); + if (ret) + return ret; + + err = readl(priv->base + SUNXI_CE_ERR) & SUNXI_CE_CHAN_ERR_MASK; + writel(SUNXI_CE_CHAN_INT, priv->base + SUNXI_CE_ISR); + writel(SUNXI_CE_CHAN_ERR_MASK, priv->base + SUNXI_CE_ERR); + + if (err) { + debug("%s: CE error %#x\n", __func__, err); + return -EIO; + } + + sunxi_ecdsa_invalidate(job->dst, job->task.dst[0].len * sizeof(u32)); + result = *(u32 *)job->dst; + + return result == 1 ? 0 : -EPERM; +} + +static int sunxi_ecdsa_verify_common(struct sunxi_ecdsa_priv *priv, + const struct ecdsa_public_key *pubkey, + const void *hash, size_t hash_len, + const void *signature, size_t sig_len) +{ + const struct sunxi_ecdsa_curve *curve; + struct sunxi_ecdsa_job *job; + int ret; + + curve = sunxi_ecdsa_find_curve(pubkey); + if (!curve || pubkey->size_bits != curve->bits || !hash_len || + sig_len != curve->bytes * 2) + return -EINVAL; + + job = malloc_cache_aligned(sizeof(*job)); + if (!job) + return -ENOMEM; + + memset(job, 0, sizeof(*job)); + sunxi_ecdsa_fill_src(job, curve, pubkey, hash, hash_len, signature); + sunxi_ecdsa_fill_task(job, curve); + + if (IS_ENABLED(CONFIG_XPL_BUILD)) + sunxi_ecdsa_spl_enable_clocks(priv); + + ret = sunxi_ecdsa_run(priv, job); + free(job); + + return ret; +} + +static int sunxi_ecdsa_verify_dm(struct udevice *dev, + const struct ecdsa_public_key *pubkey, + const void *hash, size_t hash_len, + const void *signature, size_t sig_len) +{ + struct sunxi_ecdsa_priv *priv = dev_get_priv(dev); + + return sunxi_ecdsa_verify_common(priv, pubkey, hash, hash_len, + signature, sig_len); +} + +static int sunxi_ecdsa_probe(struct udevice *dev) +{ + struct sunxi_ecdsa_priv *priv = dev_get_priv(dev); + int ret; + + priv->variant = (const struct sunxi_ecdsa_variant *) + dev_get_driver_data(dev); + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + if (IS_ENABLED(CONFIG_XPL_BUILD)) { + sunxi_ecdsa_spl_enable_clocks(priv); + return 0; + } + + ret = reset_get_bulk(dev, &priv->resets); + if (ret) { + dev_err(dev, "failed to get resets: %d\n", ret); + return ret; + } + + ret = clk_get_bulk(dev, &priv->clks); + if (ret) { + dev_err(dev, "failed to get clocks: %d\n", ret); + goto err_release_resets; + } + + ret = reset_deassert_bulk(&priv->resets); + if (ret) { + dev_err(dev, "failed to deassert resets: %d\n", ret); + goto err_release_clks; + } + + ret = clk_enable_bulk(&priv->clks); + if (ret) { + dev_err(dev, "failed to enable clocks: %d\n", ret); + goto err_assert_resets; + } + + return 0; + +err_assert_resets: + reset_assert_bulk(&priv->resets); +err_release_clks: + clk_release_bulk(&priv->clks); +err_release_resets: + reset_release_bulk(&priv->resets); + + return ret; +} + +static int sunxi_ecdsa_remove(struct udevice *dev) +{ + struct sunxi_ecdsa_priv *priv = dev_get_priv(dev); + + if (IS_ENABLED(CONFIG_XPL_BUILD)) + return 0; + + clk_disable_bulk(&priv->clks); + clk_release_bulk(&priv->clks); + reset_assert_bulk(&priv->resets); + reset_release_bulk(&priv->resets); + + return 0; +} + +static const struct ecdsa_ops sunxi_ecdsa_ops = { + .verify = sunxi_ecdsa_verify_dm, +}; + +static const struct sunxi_ecdsa_variant sun50i_h616_variant = { + .spl_enable_clocks = sun50i_h616_ecdsa_spl_enable_clocks, +}; + +static const struct udevice_id sunxi_ecdsa_ids[] = { + { + .compatible = "allwinner,sun50i-h616-crypto", + .data = (ulong)&sun50i_h616_variant, + }, + { } +}; + +U_BOOT_DRIVER(sunxi_ecdsa) = { + .name = "sunxi_ecdsa", + .id = UCLASS_ECDSA, + .of_match = sunxi_ecdsa_ids, + .ops = &sunxi_ecdsa_ops, + .probe = sunxi_ecdsa_probe, + .remove = sunxi_ecdsa_remove, + .priv_auto = sizeof(struct sunxi_ecdsa_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/u-boot/ecdsa.h b/include/u-boot/ecdsa.h index f0ac0f327e9..e8b01cd0258 100644 --- a/include/u-boot/ecdsa.h +++ b/include/u-boot/ecdsa.h @@ -8,6 +8,7 @@ #include <errno.h> #include <image.h> +#include <string.h> /** * crypto_algo API impementation for ECDSA; @@ -64,8 +65,23 @@ int ecdsa_verify(struct image_sign_info *info, uint8_t *sig, uint sig_len); /** @} */ +#define ECDSA224_BYTES (224 / 8) #define ECDSA256_BYTES (256 / 8) #define ECDSA384_BYTES (384 / 8) #define ECDSA521_BYTES ((521 + 7) / 8) +static inline unsigned int ecdsa_curve_size(const char *curve_name) +{ + if (!strcmp(curve_name, "secp224r1")) + return 224; + else if (!strcmp(curve_name, "prime256v1")) + return 256; + else if (!strcmp(curve_name, "secp384r1")) + return 384; + else if (!strcmp(curve_name, "secp521r1")) + return 521; + + return 0; +} + #endif diff --git a/include/u-boot/fdt-libcrypto.h b/include/u-boot/fdt-libcrypto.h index b15d8a1eaf4..a7631cd0e04 100644 --- a/include/u-boot/fdt-libcrypto.h +++ b/include/u-boot/fdt-libcrypto.h @@ -12,7 +12,7 @@ /** * fdt_add_bignum() - Write a libcrypto BIGNUM as an FDT property * - * Convert a libcrypto BIGNUM * into a big endian array of integers. + * Convert a libcrypto BIGNUM * into a fixed-width big endian byte array. * * @blob: FDT blob to modify * @noffset: Offset of the FDT node @@ -22,6 +22,6 @@ * Return: 0 if all good all working, -ve on horror */ int fdt_add_bignum(void *blob, int noffset, const char *prop_name, - BIGNUM *num, int num_bits); + const BIGNUM *num, int num_bits); #endif /* _FDT_LIBCRYPTO_H */ diff --git a/lib/ecdsa/Kconfig b/lib/ecdsa/Kconfig index ca13b6bfa1f..f0c56278fb6 100644 --- a/lib/ecdsa/Kconfig +++ b/lib/ecdsa/Kconfig @@ -17,7 +17,7 @@ config ECDSA_VERIFY config SPL_ECDSA_VERIFY bool "Enable ECDSA verification support in SPL" - depends on SPL + depends on SPL && SPL_DM help Allow ECDSA signatures to be recognized and verified in SPL. diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c index c4bfb2cec61..4877940c631 100644 --- a/lib/ecdsa/ecdsa-libcrypto.c +++ b/lib/ecdsa/ecdsa-libcrypto.c @@ -31,7 +31,7 @@ struct signer { EVP_PKEY *evp_key; /* Pointer to EVP_PKEY object */ EC_KEY *ecdsa_key; /* Pointer to EC_KEY object */ void *hash; /* Pointer to hash used for verification */ - void *signature; /* Pointer to output signature. Do not free()!*/ + void *signature; /* Pointer to raw signature buffer */ }; struct ecdsa_public_key { @@ -50,11 +50,8 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node) if (!key->curve_name) return -ENOMSG; - if (!strcmp(key->curve_name, "prime256v1")) - key->size_bits = 256; - else if (!strcmp(key->curve_name, "secp384r1")) - key->size_bits = 384; - else + key->size_bits = ecdsa_curve_size(key->curve_name); + if (!key->size_bits) return -EINVAL; key->x = fdt_getprop(fdt, node, "ecdsa,x-point", &x_len); @@ -63,7 +60,8 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node) if (!key->x || !key->y) return -EINVAL; - if (x_len != key->size_bits / 8 || y_len != key->size_bits / 8) + if (x_len != (key->size_bits + 7) / 8 || + y_len != (key->size_bits + 7) / 8) return -EINVAL; return 0; @@ -85,11 +83,8 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node) return ret; } - if (!strcmp(pubkey.curve_name, "prime256v1")) { - nid = NID_X9_62_prime256v1; - } else if (!strcmp(pubkey.curve_name, "secp384r1")) { - nid = NID_secp384r1; - } else { + nid = OBJ_sn2nid(pubkey.curve_name); + if (nid == NID_undef) { fprintf(stderr, "Unsupported curve name: '%s'\n", pubkey.curve_name); return -EINVAL; } @@ -111,7 +106,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node) return -ENOMEM; } - len = pubkey.size_bits / 8; + len = (pubkey.size_bits + 7) / 8; uint8_t buf[1 + len * 2]; @@ -140,7 +135,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node) return 0; } -static int alloc_ctx(struct signer *ctx, const struct image_sign_info *info) +static int init_ctx(struct signer *ctx) { memset(ctx, 0, sizeof(*ctx)); @@ -149,11 +144,21 @@ static int alloc_ctx(struct signer *ctx, const struct image_sign_info *info) return -1; } + return 0; +} + +static int alloc_sig_ctx(struct signer *ctx, const struct image_sign_info *info) +{ ctx->hash = malloc(info->checksum->checksum_len); ctx->signature = malloc(info->crypto->key_len * 2); - if (!ctx->hash || !ctx->signature) + if (!ctx->hash || !ctx->signature) { + free(ctx->hash); + free(ctx->signature); + ctx->hash = NULL; + ctx->signature = NULL; return -ENOMEM; + } return 0; } @@ -166,8 +171,8 @@ static void free_ctx(struct signer *ctx) if (ctx->evp_key) EVP_PKEY_free(ctx->evp_key); - if (ctx->hash) - free(ctx->hash); + free(ctx->hash); + free(ctx->signature); } /* @@ -271,10 +276,6 @@ static int load_key_from_fdt(struct signer *ctx, const struct image_sign_info *i if (!fdt) return -EINVAL; - ret = alloc_ctx(ctx, info); - if (ret) - return ret; - sig_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME); if (sig_node < 0) { fprintf(stderr, "No /signature node found\n"); @@ -331,7 +332,9 @@ static int prepare_ctx(struct signer *ctx, const struct image_sign_info *info) int key_len_bytes, ret; char kname[1024]; - memset(ctx, 0, sizeof(*ctx)); + ret = init_ctx(ctx); + if (ret) + return ret; if (info->fdt_blob) { return load_key_from_fdt(ctx, info); @@ -345,10 +348,6 @@ static int prepare_ctx(struct signer *ctx, const struct image_sign_info *info) return -EINVAL; } - ret = alloc_ctx(ctx, info); - if (ret) - return ret; - ret = read_key(ctx, kname); if (ret) return ret; @@ -371,8 +370,11 @@ static int do_sign(struct signer *ctx, struct image_sign_info *info, algo->calculate(algo->name, region, region_count, ctx->hash); sig = ECDSA_do_sign(ctx->hash, algo->checksum_len, ctx->ecdsa_key); + if (!sig) + return -EIO; ecdsa_sig_encode_raw(ctx->signature, sig, info->crypto->key_len); + ECDSA_SIG_free(sig); return 0; } @@ -420,11 +422,16 @@ int ecdsa_sign(struct image_sign_info *info, const struct image_region region[], ret = prepare_ctx(&ctx, info); if (ret >= 0) { - do_sign(&ctx, info, region, region_count); - *sigp = ctx.signature; - *sig_len = info->crypto->key_len * 2; - - ret = ecdsa_check_signature(&ctx, info); + ret = alloc_sig_ctx(&ctx, info); + if (!ret) + ret = do_sign(&ctx, info, region, region_count); + if (!ret) + ret = ecdsa_check_signature(&ctx, info); + if (!ret) { + *sigp = ctx.signature; + *sig_len = info->crypto->key_len * 2; + ctx.signature = NULL; + } } free_ctx(&ctx); @@ -439,8 +446,12 @@ int ecdsa_verify(struct image_sign_info *info, int ret; ret = prepare_ctx(&ctx, info); - if (ret >= 0) - ret = do_verify(&ctx, info, region, region_count, sig, sig_len); + if (ret >= 0) { + ret = alloc_sig_ctx(&ctx, info); + if (!ret) + ret = do_verify(&ctx, info, region, region_count, + sig, sig_len); + } free_ctx(&ctx); return ret; @@ -453,7 +464,7 @@ static int do_add(struct signer *ctx, void *fdt, const char *key_node_name, const char *curve_name; const EC_GROUP *group; const EC_POINT *point; - BIGNUM *x, *y; + BIGNUM *x = NULL, *y = NULL; signature_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME); if (signature_node == -FDT_ERR_NOTFOUND) { @@ -491,42 +502,54 @@ static int do_add(struct signer *ctx, void *fdt, const char *key_node_name, group = EC_KEY_get0_group(ctx->ecdsa_key); key_bits = EC_GROUP_order_bits(group); curve_name = OBJ_nid2sn(EC_GROUP_get_curve_name(group)); - /* Let 'x' and 'y' memory leak by not BN_free()'ing them. */ x = BN_new(); y = BN_new(); + if (!x || !y) { + ret = -ENOMEM; + goto out; + } + point = EC_KEY_get0_public_key(ctx->ecdsa_key); - EC_POINT_get_affine_coordinates(group, point, x, y, NULL); + if (!EC_POINT_get_affine_coordinates(group, point, x, y, NULL)) { + ret = -EINVAL; + goto out; + } ret = fdt_setprop_string(fdt, key_node, FIT_KEY_HINT, info->keyname); if (ret < 0) - return ret; + goto out; ret = fdt_setprop_string(fdt, key_node, "ecdsa,curve", curve_name); if (ret < 0) - return ret; + goto out; ret = fdt_add_bignum(fdt, key_node, "ecdsa,x-point", x, key_bits); if (ret < 0) - return ret; + goto out; ret = fdt_add_bignum(fdt, key_node, "ecdsa,y-point", y, key_bits); if (ret < 0) - return ret; + goto out; ret = fdt_setprop_string(fdt, key_node, FIT_ALGO_PROP, info->name); if (ret < 0) - return ret; + goto out; if (info->require_keys) { ret = fdt_setprop_string(fdt, key_node, FIT_KEY_REQUIRED, info->require_keys); if (ret < 0) - return ret; + goto out; } - return key_node; + ret = key_node; + +out: + BN_free(x); + BN_free(y); + return ret; } int ecdsa_add_verify_data(struct image_sign_info *info, void *fdt) diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c index 629b662cf6c..201111bc128 100644 --- a/lib/ecdsa/ecdsa-verify.c +++ b/lib/ecdsa/ecdsa-verify.c @@ -12,22 +12,6 @@ #include <dm/uclass.h> #include <u-boot/ecdsa.h> -/* - * Derive size of an ECDSA key from the curve name - * - * While it's possible to extract the key size by using string manipulation, - * use a list of known curves for the time being. - */ -static int ecdsa_key_size(const char *curve_name) -{ - if (!strcmp(curve_name, "prime256v1")) - return 256; - else if (!strcmp(curve_name, "secp384r1")) - return 384; - - return 0; -} - static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node) { int x_len, y_len; @@ -38,7 +22,7 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node) return -ENOMSG; } - key->size_bits = ecdsa_key_size(key->curve_name); + key->size_bits = ecdsa_curve_size(key->curve_name); if (key->size_bits == 0) { debug("Unknown ECDSA curve '%s'", key->curve_name); return -EINVAL; @@ -50,7 +34,8 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node) if (!key->x || !key->y) return -EINVAL; - if (x_len != (key->size_bits / 8) || y_len != (key->size_bits / 8)) { + if (x_len != (key->size_bits + 7) / 8 || + y_len != (key->size_bits + 7) / 8) { printf("%s: node=%d, curve@%p x@%p+%i y@%p+%i\n", __func__, node, key->curve_name, key->x, x_len, key->y, y_len); return -EINVAL; @@ -123,6 +108,12 @@ int ecdsa_verify(struct image_sign_info *info, return ecdsa_verify_hash(dev, info, hash, sig, sig_len); } +U_BOOT_CRYPTO_ALGO(ecdsa224) = { + .name = "ecdsa224", + .key_len = ECDSA224_BYTES, + .verify = ecdsa_verify, +}; + U_BOOT_CRYPTO_ALGO(ecdsa256) = { .name = "ecdsa256", .key_len = ECDSA256_BYTES, @@ -135,6 +126,12 @@ U_BOOT_CRYPTO_ALGO(ecdsa384) = { .verify = ecdsa_verify, }; +U_BOOT_CRYPTO_ALGO(secp521r1) = { + .name = "secp521r1", + .key_len = ECDSA521_BYTES, + .verify = ecdsa_verify, +}; + /* * uclass definition for ECDSA API * diff --git a/lib/fdt-libcrypto.c b/lib/fdt-libcrypto.c index ecb0344c8f6..8afe31cbe9d 100644 --- a/lib/fdt-libcrypto.c +++ b/lib/fdt-libcrypto.c @@ -5,68 +5,35 @@ */ #include <libfdt.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> #include <u-boot/fdt-libcrypto.h> int fdt_add_bignum(void *blob, int noffset, const char *prop_name, - BIGNUM *num, int num_bits) + const BIGNUM *num, int num_bits) { - int nwords = num_bits / 32; - int size; - uint32_t *buf, *ptr; - BIGNUM *tmp, *big2, *big32, *big2_32; - BN_CTX *ctx; + int size = (num_bits + 7) / 8; + unsigned char *buf; int ret; - tmp = BN_new(); - big2 = BN_new(); - big32 = BN_new(); - big2_32 = BN_new(); + if (size <= 0) + return -EINVAL; - /* - * Note: This code assumes that all of the above succeed, or all fail. - * In practice memory allocations generally do not fail (unless the - * process is killed), so it does not seem worth handling each of these - * as a separate case. Technicaly this could leak memory on failure, - * but a) it won't happen in practice, and b) it doesn't matter as we - * will immediately exit with a failure code. - */ - if (!tmp || !big2 || !big32 || !big2_32) { - fprintf(stderr, "Out of memory (bignum)\n"); - return -ENOMEM; - } - ctx = BN_CTX_new(); - if (!ctx) { - fprintf(stderr, "Out of memory (bignum context)\n"); - return -ENOMEM; - } - BN_set_word(big2, 2L); - BN_set_word(big32, 32L); - BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ - - size = nwords * sizeof(uint32_t); buf = malloc(size); if (!buf) { fprintf(stderr, "Out of memory (%d bytes)\n", size); return -ENOMEM; } - /* Write out modulus as big endian array of integers */ - for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { - BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ - *ptr = cpu_to_fdt32(BN_get_word(tmp)); - BN_rshift(num, num, 32); /* N = N/B */ + if (BN_bn2binpad(num, buf, size) != size) { + free(buf); + return -EINVAL; } - /* - * We try signing with successively increasing size values, so this - * might fail several times - */ + /* Callers may retry with a larger FDT if the property does not fit. */ ret = fdt_setprop(blob, noffset, prop_name, buf, size); free(buf); - BN_free(tmp); - BN_free(big2); - BN_free(big32); - BN_free(big2_32); return ret ? -FDT_ERR_NOSPACE : 0; } diff --git a/tools/image-sig-host.c b/tools/image-sig-host.c index 5285263c616..aeca83bd440 100644 --- a/tools/image-sig-host.c +++ b/tools/image-sig-host.c @@ -69,6 +69,13 @@ struct crypto_algo crypto_algos[] = { .add_verify_data = rsa_add_verify_data, .verify = rsa_verify, }, + { + .name = "ecdsa224", + .key_len = ECDSA224_BYTES, + .sign = ecdsa_sign, + .add_verify_data = ecdsa_add_verify_data, + .verify = ecdsa_verify, + }, { .name = "ecdsa256", .key_len = ECDSA256_BYTES, -- 2.53.0

