mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: "Sascha Hauer" <s.hauer@pengutronix.de>
To: "Michael Tretter" <m.tretter@pengutronix.de>
Cc: BAREBOX <barebox@lists.infradead.org>,
	Michael Tretter <m.tretter@pengutronix.de>
Subject: Re: [PATCH 2/2] arm: socfpga: agilex5: add SSBL verification
Date: Mon, 26 Oct 2026 13:32:40 +0000	[thread overview]
Message-ID: <15cbf71b-3da6-4993-98f9-0d5357fdbc54@pengutronix.de> (raw)
In-Reply-To: <20261021-socfpga-agilex5-verify-ssbl-v1-2-0463e94669ab@pengutronix.de>

On 2026-10-21 22:33, Michael Tretter wrote:
> Altera VAB usually uses a certificate that is appended to the SSBL image
> using the fcs_prepare [0] tool. The certificate contains a sha384
> checksum and is signed using a key chain that ends with the root key
> that is written to the hardware.
> 
> Assume that the certificate is appended to the SSBL image. Read the
> certificate from the same flash partition as the SSBL, pass it to the
> SDM firmware for verification and check against the root key, and
> finally verify the contained checksum in barebox.
> 
> The SDM firmware returns success for the certificate verification if VAB
> is disabled. Create a dummy certificate to check if VAB boot is disabled
> and accept an unsigned SSBL in this case. If there is a valid
> certificate attached, the checksum has to match, even if VAB is
> disabled.
> 
> The implementation is a bit quirky, because
> 
> 1. it needs to deal with the broken SDM firmware behavior, which expects
>    a 32 bit word with value 0 in front of the certificate,
> 
> 2. needs to walk and parse the (still untrusted) key chain to find the
>    actual size of the certificate, and
> 
> 3. I haven't found a better way if VAB is enabled than to check a dummy
>    certificate.
> 
> The VAB code could be moved to a separate module to make it available to
> other SoCFPGA platforms or to barebox proper. Since it's only used for
> SSBL verification for now and is mingled with the SSBL loading, I kept
> it in the xload code.
> 
> [0] https://github.com/altera-fpga/libfcs
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> ---
>  arch/arm/mach-socfpga/agilex5-xload.c | 157 ++++++++++++++++++++++++++++++++++
>  1 file changed, 157 insertions(+)
> 
> diff --git a/arch/arm/mach-socfpga/agilex5-xload.c b/arch/arm/mach-socfpga/agilex5-xload.c
> index 9e55252c04cc..077f67014945 100644
> --- a/arch/arm/mach-socfpga/agilex5-xload.c
> +++ b/arch/arm/mach-socfpga/agilex5-xload.c
> @@ -5,6 +5,11 @@
>  #include <linux/sizes.h>
>  #include <mach/socfpga/generic.h>
>  #include <pbl/bio.h>
> +#include <mach/socfpga/mailbox_s10.h>
> +#include <mach/socfpga/soc64-system-manager.h>
> +
> +#include <crypto/pbl-sha.h>
> +#include <crypto/sha.h>
>  
>  static inline u32 barebox_arm_size(const char *head)
>  {
> @@ -52,9 +57,128 @@ static ssize_t agilex5_bl33_read(struct pbl_bio *bio, void *bl33,
>  	return size;
>  }
>  
> +struct vab_certificate_data {
> +	u32 magic;
> +	u32 flags;
> +	u32 reserved0;
> +	u32 reserved1;
> +	u8 hash[SHA384_DIGEST_SIZE];
> +	u32 measurement;
> +	u32 reserved2;
> +};
> +
> +struct vab_certificate_int {
> +	u32 magic;
> +	u32 size;
> +	u32 version;
> +	u32 type;
> +	struct vab_certificate_data d;
> +	u32 keychain[0];
> +};
> +
> +/*
> + * Use a wrapper struct that starts with a zero word to be able to pass the
> + * certificate to the SDM firmware as it. Let the code that reads the
> + * certificate deal with it to avoid a copy of the certificate.
> + */
> +struct vab_certificate {
> +	u32 zero;
> +	struct vab_certificate_int cert;
> +};
> +
> +static ssize_t vab_get_cert_size(struct vab_certificate_int *cert,
> +				 size_t size)
> +{
> +	struct {
> +		u32 magic;
> +		u32 size;
> +	} *header;
> +	ssize_t offset = 0;
> +
> +	/*
> +	 * Each element in the key chain has a header with some magic and the
> +	 * size of the element. The length of the entire key chain is attached
> +	 * to the end of the key chain. Walk the entire key chain to find the
> +	 * actual size of the key chain.
> +	 *
> +	 * Note that the header is still untrusted!
> +	 */
> +	while (offset < size) {
> +		header = ((void *)cert) + offset;
> +		if (header->magic == offset)
> +			break;
> +		offset += header->size;
> +		if (offset < 0 || offset > size)
> +			return -EINVAL;
> +	}
> +
> +	return offset;
> +}
> +
> +static ssize_t agilex5_vab_read(struct pbl_bio *bio,
> +				struct vab_certificate *cert,
> +				off_t start, size_t size)
> +{
> +	ssize_t ret;
> +	struct vab_certificate_int *tmp = &(cert->cert);
> +	size_t tmp_size = size - sizeof(u32);
> +
> +	cert->zero = 0;
> +	ret = pbl_bio_read(bio, start, tmp, tmp_size);
> +	if (ret < 0)
> +		return -EINVAL;
> +
> +	if (tmp->magic != 0x25d04e7f) {
> +		pr_err("vab cert: invalid magic 0x%x\n", tmp->magic);
> +		return -EINVAL;
> +	}
> +	if (tmp->size != sizeof(*tmp)) {
> +		pr_err("vab cert: invalid size %u", tmp->size);
> +		return -EINVAL;
> +	}
> +
> +	ret = vab_get_cert_size(tmp, tmp_size);
> +	if (ret <= 0) {
> +		pr_err("vab cert: invalid certificate chain\n");
> +		return -EINVAL;
> +	}
> +
> +	pr_info("read vab cert to %p from %lx (%zu bytes)\n",
> +		tmp, start, ret);
> +
> +	return ret + sizeof(u32);
> +}
> +
> +static ssize_t agilex5_vab_dummy(struct vab_certificate *cert)
> +{
> +	struct vab_certificate_int *tmp = &(cert->cert);
> +
> +	tmp->magic = 0x25d04e7f;
> +	tmp->size = sizeof(*tmp);
> +	tmp->version = 1;
> +	tmp->type = 6;
> +
> +	return tmp->size;
> +}
> +
> +static int agilex5_vab_verify(const void *data, size_t size,
> +			      struct vab_certificate *cert)
> +{
> +	char computed_hash[SHA384_DIGEST_SIZE];
> +	char *hash = cert->cert.d.hash;
> +
> +	pbl_sha384(data, size, computed_hash);
> +
> +	return memcmp(hash, computed_hash, SHA384_DIGEST_SIZE);
> +}
> +
>  int agilex5_xload_bl33(struct pbl_bio *bio, void *bl33)
>  {
>  	ssize_t size;
> +	off_t cert_offset;
> +	ssize_t cert_size;
> +	struct vab_certificate *cert;
> +	int ret;
>  
>  	if (!bio) {
>  		pr_warn("source device for SSBL is not configured\n");
> @@ -70,5 +194,38 @@ int agilex5_xload_bl33(struct pbl_bio *bio, void *bl33)
>  	if (size < 0)
>  		return size;
>  
> +	/*
> +	 * The certificate is 8 byte aligned and attached to the SSBL binary.
> +	 * The certificate must not be larger than the partition and is
> +	 * usually smaller than 4K.
> +	 */
> +	size = ALIGN(size, 8);
> +	cert_offset = barebox_part->nor_offset + size;
> +	cert_size = min_t(size_t, SZ_4K, barebox_part->nor_size - size);
> +
> +	/* Use the SDRAM behind the bl33 for the certificate */
> +	cert = bl33 + size;
> +	cert_size = agilex5_vab_read(bio, cert, cert_offset, cert_size);
> +	if (cert_size < 0) {
> +		/*
> +		 * There is no valid certificate. Generate a dummy certificate
> +		 * to ask the firmware if authentication bypass is allowed.
> +		 */
> +		cert_size = agilex5_vab_dummy(cert);
> +	}
> +
> +	ret = mbox_vab_src_cert(cert, cert_size);
> +	if (ret)
> +		return ret;
> +
> +	ret = agilex5_vab_verify(bl33, size, cert);
> +	if (ret) {
> +		if (cert_size != sizeof(*cert)) {
> +			pr_err("SSBL hash mismatch\n");
> +			return ret;
> +		}

This is unnecessary hard to read. I assume cert_size != sizeof(*cert)
means "This is not the dummy cert generated above", because a real cert
must always have data besides the header, right?

> +		pr_debug("SSBL hash mismatch: Bypass authentication\n");

The dummy cert never passes agilex5_vab_verify(), so it's not necessary
to check its sha384 sum.

I think you should rather have a dummy_cert boolean and return
successfully in the dummy case right after calling mbox_vab_src_cert().
With this you would also not have to return successfully after a failed
verification, which raises eyebrows.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




      reply	other threads:[~2026-10-26 13:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21 20:33 [PATCH 0/2] arm: socfpga: agilex5: add VAB verification for SSBL Michael Tretter
2026-10-21 20:33 ` [PATCH 1/2] arm: socfpga: mailbox_s10: add certificate validation Michael Tretter
2026-10-21 20:33 ` [PATCH 2/2] arm: socfpga: agilex5: add SSBL verification Michael Tretter
2026-10-26 13:32   ` Sascha Hauer [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=15cbf71b-3da6-4993-98f9-0d5357fdbc54@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    --cc=m.tretter@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox