[PATCH 4/4] drivers/crypto: aspeed: Add Caliptra ECDSA384 support

ChiaWei Wang chiawei_wang at aspeedtech.com
Mon Sep 23 10:29:55 CEST 2024


Hi Simon,

> -----Original Message-----
> From: Simon Glass <sjg at chromium.org>
> Sent: Saturday, September 21, 2024 12:02 AM
> 
> On Mon, 2 Sept 2024 at 07:33, Chia-Wei Wang
> <chiawei_wang at 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 at 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 at 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




More information about the U-Boot mailing list