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
next prev 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