[PATCH 0/4] aspeed: ast2700: Add Caliptra ECDSA driver

Aspeed AST2700 SoCs integrates the Caliptra secure IP, where an ECDSA384 signature verification HW interface is exported for SoC crypto needs.
This patch series firstly extends the FIT image signing/verify common code to support the ECDSA384 algorithm. For better convenience, the device tree for ECDSA public key storage is also revised by referring to RSA implementations.
After the FIT common code revision, the driver is implemented for AST2700 to leverage the Caliptra ECDSA384 signature verification.
These are verified by signed FIT images with the algorithm "sha384,ecdsa384".
Chia-Wei Wang (4): lib: ecdsa: Add ECDSA384 support lib: ecdsa: Create device tree node automatically image-fit-sig: Remove padding check drivers/crypto: aspeed: Add Caliptra ECDSA384 support
boot/image-fit-sig.c | 2 +- drivers/crypto/aspeed/Kconfig | 10 ++ drivers/crypto/aspeed/Makefile | 1 + drivers/crypto/aspeed/cptra_ecdsa.c | 187 ++++++++++++++++++++++++++++ include/u-boot/ecdsa.h | 1 + lib/ecdsa/ecdsa-libcrypto.c | 25 ++-- lib/ecdsa/ecdsa-verify.c | 14 ++- tools/image-sig-host.c | 7 ++ 8 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 drivers/crypto/aspeed/cptra_ecdsa.c

Add ECDSA384 algorithm support for image signing and verification.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com --- include/u-boot/ecdsa.h | 1 + lib/ecdsa/ecdsa-verify.c | 14 +++++++++++--- tools/image-sig-host.c | 7 +++++++ 3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/include/u-boot/ecdsa.h b/include/u-boot/ecdsa.h index 53490c6b287..0d4df9887e6 100644 --- a/include/u-boot/ecdsa.h +++ b/include/u-boot/ecdsa.h @@ -65,5 +65,6 @@ int ecdsa_verify(struct image_sign_info *info, /** @} */
#define ECDSA256_BYTES (256 / 8) +#define ECDSA384_BYTES (384 / 8)
#endif diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c index 4d1835b598a..629b662cf6c 100644 --- a/lib/ecdsa/ecdsa-verify.c +++ b/lib/ecdsa/ecdsa-verify.c @@ -22,8 +22,10 @@ static int ecdsa_key_size(const char *curve_name) { if (!strcmp(curve_name, "prime256v1")) return 256; - else - return 0; + 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) @@ -121,12 +123,18 @@ int ecdsa_verify(struct image_sign_info *info, return ecdsa_verify_hash(dev, info, hash, sig, sig_len); }
-U_BOOT_CRYPTO_ALGO(ecdsa) = { +U_BOOT_CRYPTO_ALGO(ecdsa256) = { .name = "ecdsa256", .key_len = ECDSA256_BYTES, .verify = ecdsa_verify, };
+U_BOOT_CRYPTO_ALGO(ecdsa384) = { + .name = "ecdsa384", + .key_len = ECDSA384_BYTES, + .verify = ecdsa_verify, +}; + /* * uclass definition for ECDSA API * diff --git a/tools/image-sig-host.c b/tools/image-sig-host.c index d0133aec4c8..22253502065 100644 --- a/tools/image-sig-host.c +++ b/tools/image-sig-host.c @@ -76,6 +76,13 @@ struct crypto_algo crypto_algos[] = { .add_verify_data = ecdsa_add_verify_data, .verify = ecdsa_verify, }, + { + .name = "ecdsa384", + .key_len = ECDSA384_BYTES, + .sign = ecdsa_sign, + .add_verify_data = ecdsa_add_verify_data, + .verify = ecdsa_verify, + }, };
struct padding_algo padding_algos[] = {

On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
Add ECDSA384 algorithm support for image signing and verification.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com
include/u-boot/ecdsa.h | 1 + lib/ecdsa/ecdsa-verify.c | 14 +++++++++++--- tools/image-sig-host.c | 7 +++++++ 3 files changed, 19 insertions(+), 3 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/include/u-boot/ecdsa.h b/include/u-boot/ecdsa.h index 53490c6b287..0d4df9887e6 100644 --- a/include/u-boot/ecdsa.h +++ b/include/u-boot/ecdsa.h @@ -65,5 +65,6 @@ int ecdsa_verify(struct image_sign_info *info, /** @} */
#define ECDSA256_BYTES (256 / 8) +#define ECDSA384_BYTES (384 / 8)
#endif diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c index 4d1835b598a..629b662cf6c 100644 --- a/lib/ecdsa/ecdsa-verify.c +++ b/lib/ecdsa/ecdsa-verify.c @@ -22,8 +22,10 @@ static int ecdsa_key_size(const char *curve_name) { if (!strcmp(curve_name, "prime256v1")) return 256;
else
return 0;
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) @@ -121,12 +123,18 @@ int ecdsa_verify(struct image_sign_info *info, return ecdsa_verify_hash(dev, info, hash, sig, sig_len); }
-U_BOOT_CRYPTO_ALGO(ecdsa) = { +U_BOOT_CRYPTO_ALGO(ecdsa256) = { .name = "ecdsa256", .key_len = ECDSA256_BYTES, .verify = ecdsa_verify, };
+U_BOOT_CRYPTO_ALGO(ecdsa384) = {
.name = "ecdsa384",
.key_len = ECDSA384_BYTES,
.verify = ecdsa_verify,
+};
/*
- uclass definition for ECDSA API
diff --git a/tools/image-sig-host.c b/tools/image-sig-host.c index d0133aec4c8..22253502065 100644 --- a/tools/image-sig-host.c +++ b/tools/image-sig-host.c @@ -76,6 +76,13 @@ struct crypto_algo crypto_algos[] = { .add_verify_data = ecdsa_add_verify_data, .verify = ecdsa_verify, },
{
.name = "ecdsa384",
.key_len = ECDSA384_BYTES,
.sign = ecdsa_sign,
.add_verify_data = ecdsa_add_verify_data,
.verify = ecdsa_verify,
},
};
struct padding_algo padding_algos[] = {
2.25.1

Both the signature and the public key are stored as DTS nodes in the FIT image and SPL/U-Boot DTBs.
Like the RSA signing & verification do, this patch either creates the nodes or overwirte the content automatically.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com --- lib/ecdsa/ecdsa-libcrypto.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c index 5fa9be10b4b..cd0c09ca6e4 100644 --- a/lib/ecdsa/ecdsa-libcrypto.c +++ b/lib/ecdsa/ecdsa-libcrypto.c @@ -281,15 +281,26 @@ static int do_add(struct signer *ctx, void *fdt, const char *key_node_name) BIGNUM *x, *y;
signature_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME); - if (signature_node < 0) { - fprintf(stderr, "Could not find 'signature node: %s\n", - fdt_strerror(signature_node)); - return signature_node; + if (signature_node == -FDT_ERR_NOTFOUND) { + signature_node = fdt_add_subnode(fdt, 0, FIT_SIG_NODENAME); + if (signature_node < 0) { + fprintf(stderr, "Could not find 'signature node: %s\n", + fdt_strerror(signature_node)); + return signature_node; + } }
- key_node = fdt_add_subnode(fdt, signature_node, key_node_name); - if (key_node < 0) { - fprintf(stderr, "Could not create '%s' node: %s\n", + /* Either create or overwrite the named key node */ + key_node = fdt_subnode_offset(fdt, signature_node, key_node_name); + if (key_node == -FDT_ERR_NOTFOUND) { + key_node = fdt_add_subnode(fdt, signature_node, key_node_name); + if (key_node < 0) { + fprintf(stderr, "Could not create '%s' node: %s\n", + key_node_name, fdt_strerror(key_node)); + return key_node; + } + } else if (key_node < 0) { + fprintf(stderr, "cannot select '%s' node: %s\n", key_node_name, fdt_strerror(key_node)); return key_node; }

On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
Both the signature and the public key are stored as DTS nodes in the FIT image and SPL/U-Boot DTBs.
Like the RSA signing & verification do, this patch either creates the nodes or overwirte the content automatically.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com
lib/ecdsa/ecdsa-libcrypto.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c index 5fa9be10b4b..cd0c09ca6e4 100644 --- a/lib/ecdsa/ecdsa-libcrypto.c +++ b/lib/ecdsa/ecdsa-libcrypto.c @@ -281,15 +281,26 @@ static int do_add(struct signer *ctx, void *fdt, const char *key_node_name) BIGNUM *x, *y;
signature_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME);
if (signature_node < 0) {
fprintf(stderr, "Could not find 'signature node: %s\n",
fdt_strerror(signature_node));
return signature_node;
if (signature_node == -FDT_ERR_NOTFOUND) {
signature_node = fdt_add_subnode(fdt, 0, FIT_SIG_NODENAME);
if (signature_node < 0) {
fprintf(stderr, "Could not find 'signature node: %s\n",
s/find/add/ ?
fdt_strerror(signature_node));
return signature_node;
} }
key_node = fdt_add_subnode(fdt, signature_node, key_node_name);
if (key_node < 0) {
fprintf(stderr, "Could not create '%s' node: %s\n",
/* Either create or overwrite the named key node */
key_node = fdt_subnode_offset(fdt, signature_node, key_node_name);
if (key_node == -FDT_ERR_NOTFOUND) {
key_node = fdt_add_subnode(fdt, signature_node, key_node_name);
if (key_node < 0) {
fprintf(stderr, "Could not create '%s' node: %s\n",
key_node_name, fdt_strerror(key_node));
return key_node;
}
} else if (key_node < 0) {
fprintf(stderr, "cannot select '%s' node: %s\n", key_node_name, fdt_strerror(key_node)); return key_node; }
-- 2.25.1

Hi Simon
-----Original Message----- From: Simon Glass sjg@chromium.org Sent: Saturday, September 21, 2024 12:02 AM
On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
Both the signature and the public key are stored as DTS nodes in the FIT image and SPL/U-Boot DTBs.
Like the RSA signing & verification do, this patch either creates the nodes or overwirte the content automatically.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com
lib/ecdsa/ecdsa-libcrypto.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c index 5fa9be10b4b..cd0c09ca6e4 100644 --- a/lib/ecdsa/ecdsa-libcrypto.c +++ b/lib/ecdsa/ecdsa-libcrypto.c @@ -281,15 +281,26 @@ static int do_add(struct signer *ctx, void *fdt,
const char *key_node_name)
BIGNUM *x, *y; signature_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME);
if (signature_node < 0) {
fprintf(stderr, "Could not find 'signature node: %s\n",
fdt_strerror(signature_node));
return signature_node;
if (signature_node == -FDT_ERR_NOTFOUND) {
signature_node = fdt_add_subnode(fdt, 0,
FIT_SIG_NODENAME);
if (signature_node < 0) {
fprintf(stderr, "Could not find 'signature
- node: %s\n",
s/find/add/ ?
Will fix the typo as suggested.
Regards, Chiawei

The padding algorithm is not mandatory for all signing algorithm.
For example, ECDSA does not require a padding method. The RSA case which needs PKCS padding, the belonging info->crypto() also has the check on the validity of info->padding().
Thus, remove the info->padding check from the upper, general layer.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com --- boot/image-fit-sig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c index fe328df4a85..d06e6cc8ed6 100644 --- a/boot/image-fit-sig.c +++ b/boot/image-fit-sig.c @@ -95,7 +95,7 @@ static int fit_image_setup_verify(struct image_sign_info *info, info->required_keynode = required_keynode; printf("%s:%s", algo_name, info->keyname);
- if (!info->checksum || !info->crypto || !info->padding) { + if (!info->checksum || !info->crypto) { *err_msgp = "Unknown signature algorithm"; return -1; }

Hi,
On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
The padding algorithm is not mandatory for all signing algorithm.
For example, ECDSA does not require a padding method. The RSA case which needs PKCS padding, the belonging info->crypto() also has the check on the validity of info->padding().
Is that in rsa_verify_key() ?
Thus, remove the info->padding check from the upper, general layer.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com
boot/image-fit-sig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c index fe328df4a85..d06e6cc8ed6 100644 --- a/boot/image-fit-sig.c +++ b/boot/image-fit-sig.c @@ -95,7 +95,7 @@ static int fit_image_setup_verify(struct image_sign_info *info, info->required_keynode = required_keynode; printf("%s:%s", algo_name, info->keyname);
if (!info->checksum || !info->crypto || !info->padding) {
if (!info->checksum || !info->crypto) { *err_msgp = "Unknown signature algorithm"; return -1; }
-- 2.25.1
Regards, Simon

Hi Simon,
-----Original Message----- From: Simon Glass sjg@chromium.org Sent: Saturday, September 21, 2024 12:02 AM>
Hi,
On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
The padding algorithm is not mandatory for all signing algorithm.
For example, ECDSA does not require a padding method. The RSA case which needs PKCS padding, the belonging info->crypto() also has the check on the validity of info->padding().
Is that in rsa_verify_key() ?
Yes.
Regards, Chiawei

Aspeed AST27xx SoCs integrate the CPTRA 1.0 secure IP, which export an ECDSA384_SIGNATURE_VERIFY mailbox command service for SoC to use.
This patch is verified by the FIT signature verification using the "sha384,ecdsa384" algorithm.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com --- drivers/crypto/aspeed/Kconfig | 10 ++ drivers/crypto/aspeed/Makefile | 1 + drivers/crypto/aspeed/cptra_ecdsa.c | 187 ++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/crypto/aspeed/cptra_ecdsa.c
diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index 9bf317177aa..19fbe983888 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -18,3 +18,13 @@ config ASPEED_ACRY
Enabling this allows the use of RSA/ECC operations in hardware without requiring the software implementations. It also improves performance and saves code size. + +config ASPEED_CPTRA_ECDSA + bool "Caliptra ECDSA384 signature verifier for Aspeed SoCs" + depends on ECDSA_VERIFY || SPL_ECDSA_VERIFY + help + Select this option to enable a driver for using the ECDSA384_SIGNATURE_VERIFY + feature of Caliptra, which is integrated in AST27xx BMC SoCs. + + Enabling this allows the use of ECDSA384 signature verification in hardware. + Note that only ECDSA384 is supported by Caliptra. diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile index 58b55fc46e4..3ca5e829412 100644 --- a/drivers/crypto/aspeed/Makefile +++ b/drivers/crypto/aspeed/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o +obj-$(CONFIG_ASPEED_CPTRA_ECDSA) += cptra_ecdsa.o diff --git a/drivers/crypto/aspeed/cptra_ecdsa.c b/drivers/crypto/aspeed/cptra_ecdsa.c new file mode 100644 index 00000000000..aae14ca55aa --- /dev/null +++ b/drivers/crypto/aspeed/cptra_ecdsa.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2024 ASPEED Technology Inc. + */ +#include <asm/io.h> +#include <config.h> +#include <crypto/ecdsa-uclass.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <malloc.h> +#include <u-boot/ecdsa.h> + +/* SCU register offsets */ +#define SCU1_CPTRA 0x130 +#define SCU1_CPTRA_RDY_FOR_RT BIT(18) + +/* CPTRA MBOX register offsets */ +#define CPTRA_MBOX_LOCK 0x00 +#define CPTRA_MBOX_USER 0x04 +#define CPTRA_MBOX_CMD 0x08 +#define CPTRA_MBOX_DLEN 0x0c +#define CPTRA_MBOX_DATAIN 0x10 +#define CPTRA_MBOX_DATAOUT 0x14 +#define CPTRA_MBOX_EXEC 0x18 +#define CPTRA_MBOX_STS 0x1c +#define CPTRA_MBOX_STS_SOC_LOCK BIT(9) +#define CPTRA_MBOX_STS_FSM_PS GENMASK(8, 6) +#define CPTRA_MBOX_STS_PS GENMASK(3, 0) +#define CPTRA_MBOX_UNLOCK 0x20 + +#define CPTRA_ECDSA_SIG_LEN 96 /* ECDSA384 */ +#define CPTRA_ECDSA_SHA_LEN 48 /* SHA384 */ + +#define CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY 0x53494756 + +enum cptra_mbox_sts { + CPTRA_MBSTS_CMD_BUSY, + CPTRA_MBSTS_DATA_READY, + CPTRA_MBSTS_CMD_COMPLETE, + CPTRA_MBSTS_CMD_FAILURE, +}; + +enum cptra_mbox_fsm { + CPTRA_MBFSM_IDLE, + CPTRA_MBFSM_RDY_FOR_CMD, + CPTRA_MBFSM_RDY_FOR_DLEN, + CPTRA_MBFSM_RDY_FOR_DATA, + CPTRA_MBFSM_EXEC_UC, + CPTRA_MBFSM_EXEC_SOC, + CPTRA_MBFSM_ERROR, +}; + +struct cptra_ecdsa { + void *regs; +}; + +static uint32_t mbox_csum(uint32_t csum, uint8_t *data, uint32_t dlen) +{ + uint32_t i; + + if (!data) + return csum; + + for (i = 0; i < dlen; ++i) + csum -= data[i]; + + return csum; +} + +static int cptra_ecdsa_verify(struct udevice *dev, const struct ecdsa_public_key *pubkey, + const void *hash, size_t hash_len, + const void *signature, size_t sig_len) +{ + struct cptra_ecdsa *ce; + uint8_t *x, *y, *r, *s; + uint32_t cmd, csum; + uint32_t reg, sts; + uint32_t *p32; + int i; + + if (hash_len != CPTRA_ECDSA_SHA_LEN || sig_len != CPTRA_ECDSA_SIG_LEN) + return -EINVAL; + + if ((strcmp(pubkey->curve_name, "secp384r1") && strcmp(pubkey->curve_name, "prime384v1")) || + pubkey->size_bits != ((CPTRA_ECDSA_SIG_LEN / 2) << 3)) + return -EINVAL; + + ce = dev_get_priv(dev); + + /* get CPTRA MBOX lock */ + if (readl_poll_timeout(ce->regs + CPTRA_MBOX_LOCK, reg, reg == 0, 1000000)) + return -EBUSY; + + /* check MBOX is ready for command */ + sts = readl(ce->regs + CPTRA_MBOX_STS); + if (FIELD_GET(CPTRA_MBOX_STS_FSM_PS, sts) != CPTRA_MBFSM_RDY_FOR_CMD) + return -EACCES; + + /* init mbox parameters */ + cmd = CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY; + csum = 0; + x = (uint8_t *)pubkey->x; + y = (uint8_t *)pubkey->y; + r = (uint8_t *)signature; + s = (uint8_t *)signature + (CPTRA_ECDSA_SIG_LEN / 2); + + /* calculate checksum */ + csum = mbox_csum(csum, (uint8_t *)&cmd, sizeof(cmd)); + csum = mbox_csum(csum, x, CPTRA_ECDSA_SIG_LEN / 2); + csum = mbox_csum(csum, y, CPTRA_ECDSA_SIG_LEN / 2); + csum = mbox_csum(csum, r, CPTRA_ECDSA_SIG_LEN / 2); + csum = mbox_csum(csum, s, CPTRA_ECDSA_SIG_LEN / 2); + + /* write command, data length */ + writel(cmd, ce->regs + CPTRA_MBOX_CMD); + writel(sizeof(csum) + (CPTRA_ECDSA_SIG_LEN << 1), ce->regs + CPTRA_MBOX_DLEN); + + /* write ECDSA384_SIGNATURE_VERIFY command parameters */ + writel(csum, ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)x; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)y; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)r; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)s; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + /* trigger mbox command */ + writel(0x1, ce->regs + CPTRA_MBOX_EXEC); + + /* poll for result */ + while (1) { + sts = FIELD_GET(CPTRA_MBOX_STS_PS, readl(ce->regs + CPTRA_MBOX_STS)); + if (sts != CPTRA_MBSTS_CMD_BUSY) + break; + } + + /* unlock mbox */ + writel(0x0, ce->regs + CPTRA_MBOX_EXEC); + + return (sts == CPTRA_MBSTS_CMD_FAILURE) ? sts : 0; +} + +static int cptra_ecdsa_probe(struct udevice *dev) +{ + struct cptra_ecdsa *ce = dev_get_priv(dev); + + ce->regs = (void *)devfdt_get_addr(dev); + if (ce->regs == (void *)FDT_ADDR_T_NONE) { + debug("cannot map Caliptra mailbox registers\n"); + return -ENODEV; + } + + return 0; +} + +static int cptra_ecdsa_remove(struct udevice *dev) +{ + return 0; +} + +static const struct ecdsa_ops cptra_ecdsa_ops = { + .verify = cptra_ecdsa_verify, +}; + +static const struct udevice_id cptra_ecdsa_ids[] = { + { .compatible = "aspeed,ast2700-cptra-ecdsa" }, + { } +}; + +U_BOOT_DRIVER(aspeed_cptra_ecdsa) = { + .name = "aspeed_cptra_ecdsa", + .id = UCLASS_ECDSA, + .of_match = cptra_ecdsa_ids, + .ops = &cptra_ecdsa_ops, + .probe = cptra_ecdsa_probe, + .remove = cptra_ecdsa_remove, + .priv_auto = sizeof(struct cptra_ecdsa), + .flags = DM_FLAG_PRE_RELOC, +};

On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
Aspeed AST27xx SoCs integrate the CPTRA 1.0 secure IP, which export an ECDSA384_SIGNATURE_VERIFY mailbox command service for SoC to use.
This patch is verified by the FIT signature verification using the "sha384,ecdsa384" algorithm.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com
drivers/crypto/aspeed/Kconfig | 10 ++ drivers/crypto/aspeed/Makefile | 1 + drivers/crypto/aspeed/cptra_ecdsa.c | 187 ++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/crypto/aspeed/cptra_ecdsa.c
Reviewed-by: Simon Glass sjg@chromium.org
Qs below
diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index 9bf317177aa..19fbe983888 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -18,3 +18,13 @@ config ASPEED_ACRY
Enabling this allows the use of RSA/ECC operations in hardware without requiring the software implementations. It also improves performance and saves code size.
+config ASPEED_CPTRA_ECDSA
bool "Caliptra ECDSA384 signature verifier for Aspeed SoCs"
depends on ECDSA_VERIFY || SPL_ECDSA_VERIFY
help
Select this option to enable a driver for using the ECDSA384_SIGNATURE_VERIFY
feature of Caliptra, which is integrated in AST27xx BMC SoCs.
Enabling this allows the use of ECDSA384 signature verification in hardware.
Note that only ECDSA384 is supported by Caliptra.
diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile index 58b55fc46e4..3ca5e829412 100644 --- a/drivers/crypto/aspeed/Makefile +++ b/drivers/crypto/aspeed/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o +obj-$(CONFIG_ASPEED_CPTRA_ECDSA) += cptra_ecdsa.o diff --git a/drivers/crypto/aspeed/cptra_ecdsa.c b/drivers/crypto/aspeed/cptra_ecdsa.c new file mode 100644 index 00000000000..aae14ca55aa --- /dev/null +++ b/drivers/crypto/aspeed/cptra_ecdsa.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- Copyright 2024 ASPEED Technology Inc.
- */
+#include <asm/io.h> +#include <config.h> +#include <crypto/ecdsa-uclass.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <malloc.h> +#include <u-boot/ecdsa.h>
+/* SCU register offsets */ +#define SCU1_CPTRA 0x130 +#define SCU1_CPTRA_RDY_FOR_RT BIT(18)
+/* CPTRA MBOX register offsets */ +#define CPTRA_MBOX_LOCK 0x00 +#define CPTRA_MBOX_USER 0x04 +#define CPTRA_MBOX_CMD 0x08 +#define CPTRA_MBOX_DLEN 0x0c +#define CPTRA_MBOX_DATAIN 0x10 +#define CPTRA_MBOX_DATAOUT 0x14 +#define CPTRA_MBOX_EXEC 0x18 +#define CPTRA_MBOX_STS 0x1c +#define CPTRA_MBOX_STS_SOC_LOCK BIT(9) +#define CPTRA_MBOX_STS_FSM_PS GENMASK(8, 6) +#define CPTRA_MBOX_STS_PS GENMASK(3, 0) +#define CPTRA_MBOX_UNLOCK 0x20
+#define CPTRA_ECDSA_SIG_LEN 96 /* ECDSA384 */ +#define CPTRA_ECDSA_SHA_LEN 48 /* SHA384 */
+#define CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY 0x53494756
+enum cptra_mbox_sts {
CPTRA_MBSTS_CMD_BUSY,
CPTRA_MBSTS_DATA_READY,
CPTRA_MBSTS_CMD_COMPLETE,
CPTRA_MBSTS_CMD_FAILURE,
+};
+enum cptra_mbox_fsm {
CPTRA_MBFSM_IDLE,
CPTRA_MBFSM_RDY_FOR_CMD,
CPTRA_MBFSM_RDY_FOR_DLEN,
CPTRA_MBFSM_RDY_FOR_DATA,
CPTRA_MBFSM_EXEC_UC,
CPTRA_MBFSM_EXEC_SOC,
CPTRA_MBFSM_ERROR,
+};
+struct cptra_ecdsa {
void *regs;
+};
+static uint32_t mbox_csum(uint32_t csum, uint8_t *data, uint32_t dlen) +{
uint32_t i;
if (!data)
return csum;
do we need those two lines?
for (i = 0; i < dlen; ++i)
csum -= data[i];
return csum;
+}
+static int cptra_ecdsa_verify(struct udevice *dev, const struct ecdsa_public_key *pubkey,
const void *hash, size_t hash_len,
const void *signature, size_t sig_len)
+{
struct cptra_ecdsa *ce;
uint8_t *x, *y, *r, *s;
uint32_t cmd, csum;
uint32_t reg, sts;
uint32_t *p32;
int i;
if (hash_len != CPTRA_ECDSA_SHA_LEN || sig_len != CPTRA_ECDSA_SIG_LEN)
return -EINVAL;
if ((strcmp(pubkey->curve_name, "secp384r1") && strcmp(pubkey->curve_name, "prime384v1")) ||
pubkey->size_bits != ((CPTRA_ECDSA_SIG_LEN / 2) << 3))
return -EINVAL;
ce = dev_get_priv(dev);
/* get CPTRA MBOX lock */
if (readl_poll_timeout(ce->regs + CPTRA_MBOX_LOCK, reg, reg == 0, 1000000))
return -EBUSY;
/* check MBOX is ready for command */
sts = readl(ce->regs + CPTRA_MBOX_STS);
if (FIELD_GET(CPTRA_MBOX_STS_FSM_PS, sts) != CPTRA_MBFSM_RDY_FOR_CMD)
return -EACCES;
/* init mbox parameters */
cmd = CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY;
csum = 0;
x = (uint8_t *)pubkey->x;
y = (uint8_t *)pubkey->y;
r = (uint8_t *)signature;
s = (uint8_t *)signature + (CPTRA_ECDSA_SIG_LEN / 2);
/* calculate checksum */
csum = mbox_csum(csum, (uint8_t *)&cmd, sizeof(cmd));
csum = mbox_csum(csum, x, CPTRA_ECDSA_SIG_LEN / 2);
csum = mbox_csum(csum, y, CPTRA_ECDSA_SIG_LEN / 2);
csum = mbox_csum(csum, r, CPTRA_ECDSA_SIG_LEN / 2);
csum = mbox_csum(csum, s, CPTRA_ECDSA_SIG_LEN / 2);
/* write command, data length */
writel(cmd, ce->regs + CPTRA_MBOX_CMD);
writel(sizeof(csum) + (CPTRA_ECDSA_SIG_LEN << 1), ce->regs + CPTRA_MBOX_DLEN);
/* write ECDSA384_SIGNATURE_VERIFY command parameters */
writel(csum, ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)x; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)y; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)r; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)s; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
/* trigger mbox command */
writel(0x1, ce->regs + CPTRA_MBOX_EXEC);
/* poll for result */
while (1) {
sts = FIELD_GET(CPTRA_MBOX_STS_PS, readl(ce->regs + CPTRA_MBOX_STS));
if (sts != CPTRA_MBSTS_CMD_BUSY)
break;
}
/* unlock mbox */
writel(0x0, ce->regs + CPTRA_MBOX_EXEC);
return (sts == CPTRA_MBSTS_CMD_FAILURE) ? sts : 0;
+}
+static int cptra_ecdsa_probe(struct udevice *dev) +{
struct cptra_ecdsa *ce = dev_get_priv(dev);
ce->regs = (void *)devfdt_get_addr(dev);
if (ce->regs == (void *)FDT_ADDR_T_NONE) {
debug("cannot map Caliptra mailbox registers\n");
return -ENODEV;
-EINVAL for devicetree issues. -ENODEV means there is no device
}
return 0;
+}
+static int cptra_ecdsa_remove(struct udevice *dev) +{
return 0;
+}
+static const struct ecdsa_ops cptra_ecdsa_ops = {
.verify = cptra_ecdsa_verify,
+};
+static const struct udevice_id cptra_ecdsa_ids[] = {
{ .compatible = "aspeed,ast2700-cptra-ecdsa" },
{ }
+};
+U_BOOT_DRIVER(aspeed_cptra_ecdsa) = {
.name = "aspeed_cptra_ecdsa",
.id = UCLASS_ECDSA,
.of_match = cptra_ecdsa_ids,
.ops = &cptra_ecdsa_ops,
.probe = cptra_ecdsa_probe,
.remove = cptra_ecdsa_remove,
.priv_auto = sizeof(struct cptra_ecdsa),
.flags = DM_FLAG_PRE_RELOC,
Do you actually need this before relocation?
+};
2.25.1
Regards, Simon

Hi Simon,
-----Original Message----- From: Simon Glass sjg@chromium.org Sent: Saturday, September 21, 2024 12:02 AM
On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang chiawei_wang@aspeedtech.com wrote:
Aspeed AST27xx SoCs integrate the CPTRA 1.0 secure IP, which export an ECDSA384_SIGNATURE_VERIFY mailbox command service for SoC to use.
This patch is verified by the FIT signature verification using the "sha384,ecdsa384" algorithm.
Signed-off-by: Chia-Wei Wang chiawei_wang@aspeedtech.com
drivers/crypto/aspeed/Kconfig | 10 ++ drivers/crypto/aspeed/Makefile | 1 + drivers/crypto/aspeed/cptra_ecdsa.c | 187 ++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/crypto/aspeed/cptra_ecdsa.c
Reviewed-by: Simon Glass sjg@chromium.org
Qs below
diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index 9bf317177aa..19fbe983888 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -18,3 +18,13 @@ config ASPEED_ACRY
Enabling this allows the use of RSA/ECC operations in hardware
without requiring the
software implementations. It also improves performance and
saves code size.
+config ASPEED_CPTRA_ECDSA
bool "Caliptra ECDSA384 signature verifier for Aspeed SoCs"
depends on ECDSA_VERIFY || SPL_ECDSA_VERIFY
help
Select this option to enable a driver for using the
ECDSA384_SIGNATURE_VERIFY
feature of Caliptra, which is integrated in AST27xx BMC SoCs.
Enabling this allows the use of ECDSA384 signature verification
in hardware.
Note that only ECDSA384 is supported by Caliptra.
diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile index 58b55fc46e4..3ca5e829412 100644 --- a/drivers/crypto/aspeed/Makefile +++ b/drivers/crypto/aspeed/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o +obj-$(CONFIG_ASPEED_CPTRA_ECDSA) += cptra_ecdsa.o diff --git a/drivers/crypto/aspeed/cptra_ecdsa.c b/drivers/crypto/aspeed/cptra_ecdsa.c new file mode 100644 index 00000000000..aae14ca55aa --- /dev/null +++ b/drivers/crypto/aspeed/cptra_ecdsa.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- Copyright 2024 ASPEED Technology Inc.
- */
+#include <asm/io.h> +#include <config.h> +#include <crypto/ecdsa-uclass.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <malloc.h> +#include <u-boot/ecdsa.h>
+/* SCU register offsets */ +#define SCU1_CPTRA 0x130 +#define SCU1_CPTRA_RDY_FOR_RT BIT(18)
+/* CPTRA MBOX register offsets */ +#define CPTRA_MBOX_LOCK 0x00 +#define CPTRA_MBOX_USER 0x04 +#define CPTRA_MBOX_CMD 0x08 +#define CPTRA_MBOX_DLEN 0x0c +#define CPTRA_MBOX_DATAIN 0x10 +#define CPTRA_MBOX_DATAOUT 0x14 +#define CPTRA_MBOX_EXEC 0x18 +#define CPTRA_MBOX_STS 0x1c +#define CPTRA_MBOX_STS_SOC_LOCK BIT(9) +#define CPTRA_MBOX_STS_FSM_PS GENMASK(8, 6) +#define CPTRA_MBOX_STS_PS GENMASK(3, 0) +#define CPTRA_MBOX_UNLOCK 0x20
+#define CPTRA_ECDSA_SIG_LEN 96 /* ECDSA384 */ +#define CPTRA_ECDSA_SHA_LEN 48 /* SHA384 */
+#define CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY 0x53494756
+enum cptra_mbox_sts {
CPTRA_MBSTS_CMD_BUSY,
CPTRA_MBSTS_DATA_READY,
CPTRA_MBSTS_CMD_COMPLETE,
CPTRA_MBSTS_CMD_FAILURE,
+};
+enum cptra_mbox_fsm {
CPTRA_MBFSM_IDLE,
CPTRA_MBFSM_RDY_FOR_CMD,
CPTRA_MBFSM_RDY_FOR_DLEN,
CPTRA_MBFSM_RDY_FOR_DATA,
CPTRA_MBFSM_EXEC_UC,
CPTRA_MBFSM_EXEC_SOC,
CPTRA_MBFSM_ERROR,
+};
+struct cptra_ecdsa {
void *regs;
+};
+static uint32_t mbox_csum(uint32_t csum, uint8_t *data, uint32_t +dlen) {
uint32_t i;
if (!data)
return csum;
do we need those two lines?
No, I forgot to remove this when changing this function from non-static to static. Will revise as suggested.
for (i = 0; i < dlen; ++i)
csum -= data[i];
return csum;
+}
+static int cptra_ecdsa_verify(struct udevice *dev, const struct
ecdsa_public_key *pubkey,
const void *hash, size_t hash_len,
const void *signature, size_t sig_len) {
struct cptra_ecdsa *ce;
uint8_t *x, *y, *r, *s;
uint32_t cmd, csum;
uint32_t reg, sts;
uint32_t *p32;
int i;
if (hash_len != CPTRA_ECDSA_SHA_LEN || sig_len !=
CPTRA_ECDSA_SIG_LEN)
return -EINVAL;
if ((strcmp(pubkey->curve_name, "secp384r1") &&
strcmp(pubkey->curve_name, "prime384v1")) ||
pubkey->size_bits != ((CPTRA_ECDSA_SIG_LEN / 2) << 3))
return -EINVAL;
ce = dev_get_priv(dev);
/* get CPTRA MBOX lock */
if (readl_poll_timeout(ce->regs + CPTRA_MBOX_LOCK, reg, reg ==
0, 1000000))
return -EBUSY;
/* check MBOX is ready for command */
sts = readl(ce->regs + CPTRA_MBOX_STS);
if (FIELD_GET(CPTRA_MBOX_STS_FSM_PS, sts) !=
CPTRA_MBFSM_RDY_FOR_CMD)
return -EACCES;
/* init mbox parameters */
cmd = CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY;
csum = 0;
x = (uint8_t *)pubkey->x;
y = (uint8_t *)pubkey->y;
r = (uint8_t *)signature;
s = (uint8_t *)signature + (CPTRA_ECDSA_SIG_LEN / 2);
/* calculate checksum */
csum = mbox_csum(csum, (uint8_t *)&cmd, sizeof(cmd));
csum = mbox_csum(csum, x, CPTRA_ECDSA_SIG_LEN / 2);
csum = mbox_csum(csum, y, CPTRA_ECDSA_SIG_LEN / 2);
csum = mbox_csum(csum, r, CPTRA_ECDSA_SIG_LEN / 2);
csum = mbox_csum(csum, s, CPTRA_ECDSA_SIG_LEN / 2);
/* write command, data length */
writel(cmd, ce->regs + CPTRA_MBOX_CMD);
writel(sizeof(csum) + (CPTRA_ECDSA_SIG_LEN << 1), ce->regs +
- CPTRA_MBOX_DLEN);
/* write ECDSA384_SIGNATURE_VERIFY command parameters */
writel(csum, ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)x; i < ((CPTRA_ECDSA_SIG_LEN / 2) /
sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)y; i < ((CPTRA_ECDSA_SIG_LEN / 2) /
sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)r; i < ((CPTRA_ECDSA_SIG_LEN / 2) /
sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
for (i = 0, p32 = (uint32_t *)s; i < ((CPTRA_ECDSA_SIG_LEN / 2) /
sizeof(*p32)); ++i)
writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN);
/* trigger mbox command */
writel(0x1, ce->regs + CPTRA_MBOX_EXEC);
/* poll for result */
while (1) {
sts = FIELD_GET(CPTRA_MBOX_STS_PS, readl(ce->regs +
CPTRA_MBOX_STS));
if (sts != CPTRA_MBSTS_CMD_BUSY)
break;
}
/* unlock mbox */
writel(0x0, ce->regs + CPTRA_MBOX_EXEC);
return (sts == CPTRA_MBSTS_CMD_FAILURE) ? sts : 0; }
+static int cptra_ecdsa_probe(struct udevice *dev) {
struct cptra_ecdsa *ce = dev_get_priv(dev);
ce->regs = (void *)devfdt_get_addr(dev);
if (ce->regs == (void *)FDT_ADDR_T_NONE) {
debug("cannot map Caliptra mailbox registers\n");
return -ENODEV;
-EINVAL for devicetree issues. -ENODEV means there is no device
Will revise as suggested.
}
return 0;
+}
+static int cptra_ecdsa_remove(struct udevice *dev) {
return 0;
+}
+static const struct ecdsa_ops cptra_ecdsa_ops = {
.verify = cptra_ecdsa_verify,
+};
+static const struct udevice_id cptra_ecdsa_ids[] = {
{ .compatible = "aspeed,ast2700-cptra-ecdsa" },
{ }
+};
+U_BOOT_DRIVER(aspeed_cptra_ecdsa) = {
.name = "aspeed_cptra_ecdsa",
.id = UCLASS_ECDSA,
.of_match = cptra_ecdsa_ids,
.ops = &cptra_ecdsa_ops,
.probe = cptra_ecdsa_probe,
.remove = cptra_ecdsa_remove,
.priv_auto = sizeof(struct cptra_ecdsa),
.flags = DM_FLAG_PRE_RELOC,
Do you actually need this before relocation?
We wish to use this driver also in SPL stage. Is this the wrong flag to use for this purpose?
Regards, Chiawei
participants (3)
-
Chia-Wei Wang
-
ChiaWei Wang
-
Simon Glass