mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: BAREBOX <barebox@lists.infradead.org>
Subject: [PATCH 4/4] public keys: allow keys to be members of multiple keyrings
Date: Wed, 27 May 2026 12:54:44 +0200	[thread overview]
Message-ID: <20260527-public-keys-v1-4-c87a1cc61d1b@pengutronix.de> (raw)
In-Reply-To: <20260527-public-keys-v1-0-c87a1cc61d1b@pengutronix.de>

The same signing identity can be valid in more than one context — e.g.
the development PEM is used both as a FIT image signer and as a TLV
signer. Until now keytoc forced one keyring per key, so the Kconfig
default listed the snakeoil PEM twice (once per target keyring) and
emitted two full copies of the modulus / rr / hash / public_key struct
into rodata.

Let the keyring= option in a keyspec appear more than once. Each
occurrence appends to a list; the emitted key data (struct public_key,
rsa/ecdsa_public_key, hash) is unchanged and singular, and one
struct public_key_record is emitted per keyring all pointing back at
the same key. Symbol/section names are uniquified with a per-key
record index (key_N_record_M).

For the development-key default, collapse the two CRYPTO_PUBLIC_KEYS
entries into one (keyring=fit,keyring=tlv-generic,fit-hint=...). With
4096-bit RSA this avoids re-emitting ~1 KB per shared identity into
rodata.

While here, have the keys command print a keyring header so the now
N-records-per-key output is readable.

Assisted-by: Claude Opus 4.7
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 crypto/Makefile  |  6 ++----
 scripts/keytoc.c | 61 ++++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/crypto/Makefile b/crypto/Makefile
index 17043316c4..0c4a900504 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -33,12 +33,10 @@ CONFIG_CRYPTO_PUBLIC_KEYS := $(foreach d,$(CONFIG_CRYPTO_PUBLIC_KEYS),"$(d)")
 
 ifdef CONFIG_CRYPTO_BUILTIN_DEVELOPMENT_KEYS
 ifdef CONFIG_CRYPTO_RSA
-CONFIG_CRYPTO_PUBLIC_KEYS += keyring=fit,fit-hint=rsa-devel:$(srctree)/crypto/snakeoil-4096-development.pem
-CONFIG_CRYPTO_PUBLIC_KEYS += keyring=tlv-generic:$(srctree)/crypto/snakeoil-4096-development.pem
+CONFIG_CRYPTO_PUBLIC_KEYS += keyring=fit,keyring=tlv-generic,fit-hint=rsa-devel:$(srctree)/crypto/snakeoil-4096-development.pem
 endif
 ifdef CONFIG_CRYPTO_ECDSA
-CONFIG_CRYPTO_PUBLIC_KEYS += keyring=fit,fit-hint=ecdsa-devel:$(srctree)/crypto/snakeoil-ecdsa-development.pem
-CONFIG_CRYPTO_PUBLIC_KEYS += keyring=tlv-generic:$(srctree)/crypto/snakeoil-ecdsa-development.pem
+CONFIG_CRYPTO_PUBLIC_KEYS += keyring=fit,keyring=tlv-generic,fit-hint=ecdsa-devel:$(srctree)/crypto/snakeoil-ecdsa-development.pem
 endif
 endif
 
diff --git a/scripts/keytoc.c b/scripts/keytoc.c
index 7e910422a7..e78d010481 100644
--- a/scripts/keytoc.c
+++ b/scripts/keytoc.c
@@ -34,7 +34,8 @@
 struct keyinfo {
 	char *spec;
 	char *name_hint;
-	char *keyring;
+	char **keyrings;
+	int nr_keyrings;
 	char *path;
 	char *name_c;
 };
@@ -564,6 +565,8 @@ static int gen_key_ecdsa(EVP_PKEY *key, struct keyinfo *info)
 		fprintf(outfilep, "\t.y = %s_y,\n", info->name_c);
 		fprintf(outfilep, "};\n");
 		if (!standalone) {
+			int i;
+
 			fprintf(outfilep, "\nstatic const struct public_key %s_public_key = {\n", info->name_c);
 			fprintf(outfilep, "\t.type = PUBLIC_KEY_TYPE_ECDSA,\n");
 			if (info->name_hint)
@@ -572,11 +575,14 @@ static int gen_key_ecdsa(EVP_PKEY *key, struct keyinfo *info)
 			fprintf(outfilep, "\t.hashlen = %u,\n", SHA256_DIGEST_LENGTH);
 			fprintf(outfilep, "\t.ecdsa = &%s,\n", info->name_c);
 			fprintf(outfilep, "};\n");
-			fprintf(outfilep, "\n");
-			fprintf(outfilep, "static const struct public_key_record __%s_public_key __ll_elem(.public_keys.rodata.%s) = {\n", info->name_c, info->name_c);
-			fprintf(outfilep, "\t.keyring = \"%s\",\n", info->keyring);
-			fprintf(outfilep, "\t.key = &%s_public_key,\n", info->name_c);
-			fprintf(outfilep, "};\n");
+			for (i = 0; i < info->nr_keyrings; i++) {
+				fprintf(outfilep, "\n");
+				fprintf(outfilep, "static const struct public_key_record __%s_record_%d __ll_elem(.public_keys.rodata.%s_record_%d) = {\n",
+					info->name_c, i, info->name_c, i);
+				fprintf(outfilep, "\t.keyring = \"%s\",\n", info->keyrings[i]);
+				fprintf(outfilep, "\t.key = &%s_public_key,\n", info->name_c);
+				fprintf(outfilep, "};\n");
+			}
 		}
 	}
 
@@ -674,6 +680,8 @@ static int gen_key_rsa(EVP_PKEY *key, struct keyinfo *info)
 		fprintf(outfilep, "};\n");
 
 		if (!standalone) {
+			int i;
+
 			fprintf(outfilep, "\nstatic const struct public_key %s_public_key = {\n", info->name_c);
 			fprintf(outfilep, "\t.type = PUBLIC_KEY_TYPE_RSA,\n");
 			if (info->name_hint)
@@ -682,11 +690,14 @@ static int gen_key_rsa(EVP_PKEY *key, struct keyinfo *info)
 			fprintf(outfilep, "\t.hashlen = %u,\n", SHA256_DIGEST_LENGTH);
 			fprintf(outfilep, "\t.rsa = &%s,\n", info->name_c);
 			fprintf(outfilep, "};\n");
-			fprintf(outfilep, "\n");
-			fprintf(outfilep, "static const struct public_key_record __%s_public_key __ll_elem(.public_keys.rodata.%s) = {\n", info->name_c, info->name_c);
-			fprintf(outfilep, "\t.keyring = \"%s\",\n", info->keyring);
-			fprintf(outfilep, "\t.key = &%s_public_key,\n", info->name_c);
-			fprintf(outfilep, "};\n");
+			for (i = 0; i < info->nr_keyrings; i++) {
+				fprintf(outfilep, "\n");
+				fprintf(outfilep, "static const struct public_key_record __%s_record_%d __ll_elem(.public_keys.rodata.%s_record_%d) = {\n",
+					info->name_c, i, info->name_c, i);
+				fprintf(outfilep, "\t.keyring = \"%s\",\n", info->keyrings[i]);
+				fprintf(outfilep, "\t.key = &%s_public_key,\n", info->name_c);
+				fprintf(outfilep, "};\n");
+			}
 		}
 	}
 
@@ -775,9 +786,21 @@ static bool parse_info(char *p, struct keyinfo *out)
 			v = strdup(v);
 			if (!v)
 				enomem_exit(__func__);
-			if (strcmp(k, "keyring") == 0)
-				out->keyring = strdup(v);
-			else if (strcmp(k, "fit-hint") == 0)
+			if (strcmp(k, "keyring") == 0) {
+				int i;
+				for (i = 0; i < out->nr_keyrings; i++) {
+					if (strcmp(out->keyrings[i], v) == 0) {
+						fprintf(stderr,
+							"duplicate keyring=%s in keyspec\n", v);
+						return false;
+					}
+				}
+				out->keyrings = realloc(out->keyrings,
+							(out->nr_keyrings + 1) * sizeof(char *));
+				if (!out->keyrings)
+					enomem_exit(__func__);
+				out->keyrings[out->nr_keyrings++] = strdup(v);
+			} else if (strcmp(k, "fit-hint") == 0)
 				out->name_hint = strdup(v);
 			else
 				return false;
@@ -862,7 +885,7 @@ int main(int argc, char *argv[])
 	}
 
 	if (optind == argc) {
-		fprintf(stderr, "Usage: %s [-ods] keyring=<keyring>[,fit-hint=<hint>]:<crt> ...\n", argv[0]);
+		fprintf(stderr, "Usage: %s [-ods] keyring=<keyring>[,keyring=<keyring>...][,fit-hint=<hint>]:<crt> ...\n", argv[0]);
 		fprintf(stderr, "\t-o FILE\twrite output into FILE instead of stdout\n");
 		fprintf(stderr, "\t-d\tgenerate device tree snippet instead of C code\n");
 		fprintf(stderr, "\t-s\tgenerate standalone key outside FIT image keyring\n");
@@ -926,8 +949,12 @@ int main(int argc, char *argv[])
 		if (asprintf(&info->name_c, "key_%i", keys_idx + 1) < 0)
 			enomem_exit("asprintf");
 
-		if (!info->keyring) {
-			info->keyring = strdup("fit");
+		if (info->nr_keyrings == 0) {
+			info->keyrings = malloc(sizeof(char *));
+			if (!info->keyrings)
+				enomem_exit(__func__);
+			info->keyrings[0] = strdup("fit");
+			info->nr_keyrings = 1;
 			fprintf(stderr, "Warning: No keyring provided in keyspec, defaulting to keyring=fit for %s\n", info->path);
 		}
 	}

-- 
2.47.3




  parent reply	other threads:[~2026-05-27 10:56 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-27 10:54 [PATCH 0/4] public keys: rework keyrings as nested containers Sascha Hauer
2026-05-27 10:54 ` [PATCH 1/4] public keys: make error message more informative Sascha Hauer
2026-05-27 10:54 ` [PATCH 2/4] public keys: make key_name_hint optional Sascha Hauer
2026-05-27 10:54 ` [PATCH 3/4] public keys: rework keyrings as nested containers Sascha Hauer
2026-05-27 10:54 ` Sascha Hauer [this message]
2026-05-29 11:43 ` [PATCH 0/4] " Sascha Hauer

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=20260527-public-keys-v1-4-c87a1cc61d1b@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /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