mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Jonas Rebmann <jre@pengutronix.de>
To: Sascha Hauer <s.hauer@pengutronix.de>,
	 BAREBOX <barebox@lists.infradead.org>
Cc: Jonas Rebmann <jre@pengutronix.de>
Subject: [PATCH 09/15] common: tlv: Add TLV-Signature support
Date: Tue, 14 Oct 2025 13:03:00 +0200	[thread overview]
Message-ID: <20251014-tlv-signature-v1-9-7a8aaf95081c@pengutronix.de> (raw)
In-Reply-To: <20251014-tlv-signature-v1-0-7a8aaf95081c@pengutronix.de>

Implement TLV signature using the existing placeholders for it. Use the
existing cryptographic primitives and public key handling used for
fitimage verification.

Signature is verified and then must be valid iff CONFIG_TLV_SIGNATURE is
enabled and a keyring is selected for the decoder. SHA256 hashing is
hardcoded for now.

As 16 bit are well sufficient to store the length of the signature
section in bytes, reduce it to its least significant 16 bit and reserve
the remaining 16 bit for future use.

As sig_len where the only reserved bits left, and where zero-reserved,
this leaves more wiggle room to still expand the format in the future.

Signed-off-by: Jonas Rebmann <jre@pengutronix.de>
---
 common/Kconfig       |  4 +++
 common/tlv/parser.c  | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/tlv/format.h | 22 ++++++++++----
 3 files changed, 105 insertions(+), 5 deletions(-)

diff --git a/common/Kconfig b/common/Kconfig
index d923d4c4b6..b7ac7094a6 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1122,6 +1122,10 @@ config TLV
 	  barebox TLV is a scheme for storing factory data on non-volatile
 	  storage. Unlike state, it's meant to be read-only.
 
+config TLV_SIGNATURE
+	bool "barebox TLV signature support"
+	select CRYPTO_BUILTIN_KEYS
+
 config TLV_DRV
 	bool "barebox TLV generic driver"
 	depends on TLV
diff --git a/common/tlv/parser.c b/common/tlv/parser.c
index f74ada99d7..0a23beba4e 100644
--- a/common/tlv/parser.c
+++ b/common/tlv/parser.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include "tlv/format.h"
 #define pr_fmt(fmt) "barebox-tlv: " fmt
 
 #include <common.h>
@@ -9,6 +10,81 @@
 #include <linux/stat.h>
 #include <crc.h>
 #include <net.h>
+#include <crypto/public_key.h>
+
+static int tlv_verify_try_key(const struct public_key *key, const uint8_t *sig,
+			      const uint32_t sig_len, const void *data,
+			      unsigned long data_len)
+{
+	enum hash_algo algo = HASH_ALGO_SHA256;
+	int ret;
+	struct digest *digest = digest_alloc_by_algo(algo);
+	void *hash;
+
+	if (!digest)
+		return -ENOMEM;
+
+	digest_init(digest);
+	if (IS_ERR(digest)) {
+		digest_free(digest);
+		return -EINVAL;
+	}
+	digest_update(digest, data, data_len);
+	hash = xzalloc(digest_length(digest));
+	digest_final(digest, hash);
+
+	ret = public_key_verify(key, sig, sig_len, hash, algo);
+
+	digest_free(digest);
+	free(hash);
+
+	if (ret)
+		return -ENOKEY;
+	return 0;
+}
+
+static int tlv_verify(struct tlv_header *header, const char *keyring)
+{
+	const struct public_key *key;
+	size_t payload_sz = tlv_spki_hash_offset(header);
+	void *spki_tlv_ptr = (void *)header + payload_sz;
+	u32 spki_tlv = get_unaligned_le32(spki_tlv_ptr);
+	const int SPKI_LEN = 4;
+	u32 sig_len = get_unaligned_be16(&header->length_sig);
+	int ret;
+	int count_spki_matches = 0;
+
+	if (!IS_ENABLED(CONFIG_TLV_SIGNATURE)) {
+		pr_err("TLV signature selected in decoder but not enabled!\n");
+		return -ENOSYS;
+	} else if (sig_len == 0) {
+		pr_err("TLV signature selected in decoder but an unsigned TLV matched by magic %08x!\n", be32_to_cpu(header->magic));
+		return -EPROTO;
+	}
+	/* signature length field must always be zeroed during signage and verification */
+	header->length_sig = 0;
+
+	for_each_public_key_keyring(key, keyring) {
+		u32 spki_key = get_unaligned_le32(key->hash);
+
+		if (spki_key == spki_tlv) {
+			count_spki_matches++;
+			ret = tlv_verify_try_key(key, spki_tlv_ptr + SPKI_LEN, sig_len - SPKI_LEN, header, payload_sz);
+			if (!ret)
+				return 0;
+			pr_warn("TLV spki %08x matched available key but signature verification failed: %s!\n", spki_tlv, strerror(-ret));
+		}
+	}
+
+	/* reset signature length field after verification to avoid later confusion */
+	put_unaligned_be16(sig_len, &header->length_sig);
+
+	if (!count_spki_matches) {
+		pr_warn("TLV spki %08x matched no key!\n", spki_tlv);
+		return -ENOKEY;
+	}
+	return -EINVAL;
+}
 
 int tlv_parse(struct tlv_device *tlvdev,
 	      const struct tlv_decoder *decoder)
@@ -17,6 +93,7 @@ int tlv_parse(struct tlv_device *tlvdev,
 	struct tlv_mapping *map = NULL;
 	struct tlv_header *header = tlv_device_header(tlvdev);
 	u32 magic;
+	u16 reserved;
 	size_t size;
 	int ret = 0;
 	u32 crc = ~0;
@@ -24,6 +101,7 @@ int tlv_parse(struct tlv_device *tlvdev,
 	magic = be32_to_cpu(header->magic);
 
 	size = tlv_total_len(header);
+	reserved = get_unaligned_be16(&header->reserved);
 
 	if (size == SIZE_MAX) {
 		pr_warn("Invalid TLV header, overflows\n");
@@ -36,6 +114,12 @@ int tlv_parse(struct tlv_device *tlvdev,
 		return -EILSEQ;
 	}
 
+	if (decoder->signature_keyring) {
+		ret = tlv_verify(header, decoder->signature_keyring);
+		if (ret)
+			return ret;
+	}
+
 	for_each_tlv(header, tlv) {
 		struct tlv_mapping **mappings;
 		u16 tag = TLV_TAG(tlv);
diff --git a/include/tlv/format.h b/include/tlv/format.h
index c4521c3131..cbe0a132b1 100644
--- a/include/tlv/format.h
+++ b/include/tlv/format.h
@@ -47,11 +47,12 @@ struct tlv {
 struct tlv_header {
 	__be32 magic;
 	__be32 length_tlv; /* in bytes */
-	__be32 length_sig; /* in bytes */
+	__be16 reserved;
+	__be16 length_sig; /* in bytes */
 	struct tlv tlvs[];
-	/* __be32 crc; */
 	/* u8 sig[]; */
-};
+	/* __be32 crc; */
+} __packed;
 static_assert(sizeof(struct tlv_header) == 3 * 4);
 
 #define for_each_tlv(tlv_head, tlv) \
@@ -62,8 +63,19 @@ static inline size_t tlv_total_len(const struct tlv_header *header)
 	size_t ret;
 
 	ret = size_add(sizeof(struct tlv_header), get_unaligned_be32(&header->length_tlv));
-	ret = size_add(ret, sizeof(__be32)); /* CRC appended after TLVs */
-	ret = size_add(ret, get_unaligned_be32(&header->length_sig)); /* optional signature appended after CRC */
+	ret = size_add(ret, get_unaligned_be16(&header->length_sig)); /* optional signature appended after TLVs */
+	ret = size_add(ret, sizeof(__be32)); /* CRC at end of file */
+
+	return ret; /* SIZE_MAX on overflow */
+}
+
+/*
+ * Retrieve length of header+TLVs (offset of spki hash part of signature if available)
+ */
+
+static inline size_t tlv_spki_hash_offset(const struct tlv_header *header)
+{
+	size_t ret = size_add(sizeof(struct tlv_header), get_unaligned_be32(&header->length_tlv));
 
 	return ret; /* SIZE_MAX on overflow */
 }

-- 
2.51.0.297.gca2559c1d6




  parent reply	other threads:[~2025-10-14 11:04 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-14 11:02 [PATCH 00/15] TLV-Signature and keyrings Jonas Rebmann
2025-10-14 11:02 ` [PATCH 01/15] common: clean up TLV code Jonas Rebmann
2025-10-14 11:02 ` [PATCH 02/15] crypto: Add support for keyrings Jonas Rebmann
2025-10-14 11:02 ` [PATCH 03/15] fit: only accept keys from "fit"-keyring Jonas Rebmann
2025-10-14 11:02 ` [PATCH 04/15] crypto: keytoc: Rename "hint" to "fit-hint" and do not use it in identifiers Jonas Rebmann
2025-10-15 10:15   ` Jonas Rebmann
2025-10-14 11:02 ` [PATCH 05/15] commands: keys: update output format to include keyring Jonas Rebmann
2025-10-14 11:02 ` [PATCH 06/15] commands: tlv: Error out on invalid TLVs Jonas Rebmann
2025-10-14 11:02 ` [PATCH 07/15] scripts: bareboxtlv-generator: Implement signature Jonas Rebmann
2025-10-14 11:02 ` [PATCH 08/15] scripts: bareboxtlv-generator: Increase max_size in example schema Jonas Rebmann
2025-10-14 11:03 ` Jonas Rebmann [this message]
2025-10-17  9:08   ` [PATCH 09/15] common: tlv: Add TLV-Signature support Jonas Rebmann
2025-10-14 11:03 ` [PATCH 10/15] common: tlv: default decoder for signed TLV Jonas Rebmann
2025-10-14 11:03 ` [PATCH 11/15] crypto: Use "development" keys for "fit" and "tlv" keyring Jonas Rebmann
2025-10-14 11:03 ` [PATCH 12/15] test: py: add signature to TLV integration tests Jonas Rebmann
2025-10-14 11:03 ` [PATCH 13/15] ci: pytest: Add kconfig fragment for TLV signature " Jonas Rebmann
2025-10-14 11:03 ` [PATCH 14/15] doc/barebox-tlv: Update documentation regarding TLV-Signature Jonas Rebmann
2025-10-15 10:20   ` Jonas Rebmann
2025-10-14 11:03 ` [PATCH 15/15] Documentation: migration-2025.11.0: List changes to CONFIG_CRYPTO_PUBLIC_KEYS Jonas Rebmann
2025-10-15 14:34   ` Jonas Rebmann

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=20251014-tlv-signature-v1-9-7a8aaf95081c@pengutronix.de \
    --to=jre@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    --cc=s.hauer@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