[PATCH 4/4] public keys: allow keys to be members of multiple keyrings
Sascha Hauer
s.hauer at pengutronix.de
Wed May 27 03:54:44 PDT 2026
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 at 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
More information about the barebox
mailing list