Skip to content

Commit 57b874b

Browse files
bigbrettdanielinux
authored andcommitted
Simplify use of user-supplied keys and certificates with test app via
new `USER_ variables`
1 parent 2e103d2 commit 57b874b

15 files changed

+212
-37
lines changed

Makefile

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,61 @@ ifneq ($(TARGET),library)
4040
OBJS+=./hal/$(TARGET).o
4141
endif
4242

43+
# User-provided key configuration
44+
# - USER_PRIVATE_KEY: Path to user's private key (DER format)
45+
# - USER_PUBLIC_KEY: Path to user's public key (DER format)
46+
# - USER_CERT_CHAIN: Path to user's certificate chain (DER format)
47+
# All must be provided together, or none at all
48+
49+
# Validate USER_PRIVATE_KEY and USER_PUBLIC_KEY are used together
50+
ifneq ($(USER_PRIVATE_KEY),)
51+
ifeq ($(USER_PUBLIC_KEY),)
52+
$(error USER_PRIVATE_KEY requires USER_PUBLIC_KEY to also be set)
53+
endif
54+
ifeq ($(wildcard $(USER_PRIVATE_KEY)),)
55+
$(error USER_PRIVATE_KEY file not found: $(USER_PRIVATE_KEY))
56+
endif
57+
endif
58+
59+
ifneq ($(USER_PUBLIC_KEY),)
60+
ifeq ($(USER_PRIVATE_KEY),)
61+
$(error USER_PUBLIC_KEY requires USER_PRIVATE_KEY to also be set)
62+
endif
63+
ifeq ($(wildcard $(USER_PUBLIC_KEY)),)
64+
$(error USER_PUBLIC_KEY file not found: $(USER_PUBLIC_KEY))
65+
endif
66+
endif
67+
68+
# Validate USER_CERT_CHAIN requires USER_PRIVATE_KEY and USER_PUBLIC_KEY
69+
ifneq ($(USER_CERT_CHAIN),)
70+
ifeq ($(USER_PRIVATE_KEY),)
71+
$(error USER_CERT_CHAIN requires USER_PRIVATE_KEY to also be set)
72+
endif
73+
ifeq ($(USER_PUBLIC_KEY),)
74+
$(error USER_CERT_CHAIN requires USER_PUBLIC_KEY to also be set)
75+
endif
76+
ifeq ($(wildcard $(USER_CERT_CHAIN)),)
77+
$(error USER_CERT_CHAIN file not found: $(USER_CERT_CHAIN))
78+
endif
79+
endif
80+
4381
ifeq ($(SIGN),NONE)
4482
PRIVATE_KEY=
4583
else
46-
# Key selection logic:
47-
# - Without CERT_CHAIN_GEN: Single key (wolfboot_signing_private_key.der) signs everything
48-
# - With CERT_CHAIN_GEN: Generate cert chain, use leaf key (test-dummy-ca/leaf-prvkey.der) for signing
49-
ifneq ($(CERT_CHAIN_GEN),)
50-
PRIVATE_KEY=test-dummy-ca/leaf-prvkey.der
84+
# Private Key selection logic:
85+
# 1. User-provided private keys take precedence (USER_PRIVATE_KEY)
86+
# 2. Otherwise, if CERT_CHAIN_VERIFY, use generated dummy cert chain leaf key
87+
# 3. Otherwise use standard generated private key
88+
ifneq ($(USER_PRIVATE_KEY),)
89+
PRIVATE_KEY=$(USER_PRIVATE_KEY)
5190
else
52-
PRIVATE_KEY=wolfboot_signing_private_key.der
91+
ifneq ($(CERT_CHAIN_VERIFY),)
92+
# Auto-generate cert chain mode - use leaf key
93+
PRIVATE_KEY?=test-dummy-ca/leaf-prvkey.der
94+
else
95+
# No cert chain verification - standard single key mode
96+
PRIVATE_KEY?=wolfboot_signing_private_key.der
97+
endif
5398
endif
5499
ifeq ($(FLASH_OTP_KEYSTORE),1)
55100
OBJS+=./src/flash_otp_keystore.o
@@ -268,21 +313,31 @@ hal/$(TARGET).o:
268313

269314
keytools_check: keytools
270315

271-
# Generate the initial signing key
272-
# - Always creates wolfboot_signing_private_key.der
273-
# - If CERT_CHAIN_GEN is set, also generates cert chain with leaf key
316+
# Generate the initial signing key (only if not using user-provided keys)
317+
# - Creates wolfboot_signing_private_key.der when USER_PRIVATE_KEY is not set
318+
# - If CERT_CHAIN_VERIFY is enabled and USER_CERT_CHAIN not provided, also generates cert chain with leaf key
274319
wolfboot_signing_private_key.der:
320+
ifeq ($(USER_PRIVATE_KEY),)
275321
$(Q)$(MAKE) keytools_check
276322
$(Q)(test $(SIGN) = NONE) || ($(SIGN_ENV) "$(KEYGEN_TOOL)" $(KEYGEN_OPTIONS) -g wolfboot_signing_private_key.der) || true
277323
$(Q)(test $(SIGN) = NONE) && (echo "// SIGN=NONE" > src/keystore.c) || true
278324
$(Q)(test "$(FLASH_OTP_KEYSTORE)" = "1") && (make -C tools/keytools/otp) || true
279-
$(Q)(test $(SIGN) = NONE) || (test "$(CERT_CHAIN_VERIFY)" = "") || (test "$(CERT_CHAIN_GEN)" = "") || (tools/scripts/sim-gen-dummy-chain.sh --algo $(CERT_CHAIN_GEN_ALGO) --leaf wolfboot_signing_private_key.der)
325+
$(Q)(test $(SIGN) = NONE) || (test "$(CERT_CHAIN_VERIFY)" = "") || (test "$(USER_CERT_CHAIN)" != "") || (tools/scripts/sim-gen-dummy-chain.sh --algo $(CERT_CHAIN_GEN_ALGO) --leaf wolfboot_signing_private_key.der)
326+
else
327+
@echo "Using user-provided private key: $(USER_PRIVATE_KEY)"
328+
endif
280329

281-
# CERT_CHAIN_GEN only: Ensure leaf key exists after cert chain generation
282-
ifneq ($(CERT_CHAIN_GEN),)
330+
# Auto-generate cert chain mode: Ensure leaf key exists after cert chain generation
331+
# Only applies when CERT_CHAIN_VERIFY is enabled and USER_CERT_CHAIN not provided
332+
# Skip this when using user-provided keys
333+
ifeq ($(USER_PRIVATE_KEY),)
334+
ifneq ($(CERT_CHAIN_VERIFY),)
335+
ifeq ($(USER_CERT_CHAIN),)
283336
$(PRIVATE_KEY): wolfboot_signing_private_key.der
284337
@test -f $(PRIVATE_KEY) || (echo "Error: $(PRIVATE_KEY) not found" && exit 1)
285338
endif
339+
endif
340+
endif
286341

287342
$(SECONDARY_PRIVATE_KEY): $(PRIVATE_KEY) keystore.der
288343
$(Q)$(MAKE) keytools_check
@@ -435,7 +490,15 @@ srec: wolfboot.srec
435490
@echo "\t[ELF2SREC] $@"
436491
@$(OBJCOPY) -O srec $^ $@
437492

493+
# Keystore generation: use user-provided public key if available
494+
ifneq ($(USER_PUBLIC_KEY),)
495+
src/keystore.c: $(USER_PUBLIC_KEY)
496+
@echo "Generating keystore from user-provided public key: $(USER_PUBLIC_KEY)"
497+
$(Q)$(MAKE) keytools_check
498+
$(Q)$(SIGN_ENV) "$(KEYGEN_TOOL)" $(KEYGEN_OPTIONS) --force -i $(USER_PUBLIC_KEY)
499+
else
438500
src/keystore.c: $(PRIVATE_KEY)
501+
endif
439502

440503
flash_keystore: src/flash_otp_keystore.o
441504

@@ -479,7 +542,7 @@ utilsclean: clean
479542

480543
keysclean: clean
481544
$(Q)rm -f *.pem *.der tags ./src/*_pub_key.c ./src/keystore.c include/target.h
482-
$(Q)(test "$(CERT_CHAIN_GEN)" = "") || rm -rf test-dummy-ca || true
545+
$(Q)(test "$(CERT_CHAIN_VERIFY)" = "" || test "$(USER_CERT_CHAIN)" != "") || rm -rf test-dummy-ca || true
483546

484547
distclean: clean keysclean utilsclean
485548
$(Q)rm -f *.bin *.elf

arch.mk

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,14 @@ ifeq ($(ARCH),sim)
11631163
$(WOLFBOOT_LIB_WOLFHSM)/src/wh_transport_mem.o
11641164

11651165
endif
1166+
# wolfHSM NVM image generation support for simulator
1167+
# User must provide NVM_CONFIG for their specific setup
1168+
ifneq ($(filter 1,$(WOLFHSM_CLIENT) $(WOLFHSM_SERVER)),)
1169+
WH_NVM_BIN ?= whNvmImage.bin
1170+
WH_NVM_HEX ?= whNvmImage.hex
1171+
WH_NVM_PART_SIZE ?= 16384 # must match partition size in hal/sim.c
1172+
WH_NVM_BASE_ADDRESS ?= 0x0
1173+
endif
11661174
endif
11671175

11681176
# Infineon AURIX Tricore
@@ -1204,10 +1212,11 @@ ifeq ($(ARCH), AURIX_TC3)
12041212
WH_NVM_BASE_ADDRESS ?= 0xAFC00000
12051213

12061214
# Select config file based on certificate chain verification
1215+
# Use ?= to allow user override via command line (e.g., for offline cert chain)
12071216
ifneq ($(CERT_CHAIN_VERIFY),)
1208-
NVM_CONFIG = tools/scripts/tc3xx/wolfBoot-wolfHSM-dummy-certchain.nvminit
1217+
NVM_CONFIG ?= tools/scripts/tc3xx/wolfBoot-wolfHSM-dummy-certchain.nvminit
12091218
else
1210-
NVM_CONFIG = tools/scripts/tc3xx/wolfBoot-wolfHSM-keys.nvminit
1219+
NVM_CONFIG ?= tools/scripts/tc3xx/wolfBoot-wolfHSM-keys.nvminit
12111220
endif
12121221
endif
12131222

config/examples/aurix-tc375-elf-wolfHSM-certs.config

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ ELF_FLASH_SCATTER=1
2626

2727
# Cert chain options
2828
CERT_CHAIN_VERIFY=1
29-
CERT_CHAIN_GEN=1
3029

3130
# Ensure header is large enough to hold the cert chain (check sign tool output)
3231
# for actual length

config/examples/aurix-tc375-hsm-wolfHSM-certs.config

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ WOLFHSM_SERVER=1
2323

2424
# Cert chain options
2525
CERT_CHAIN_VERIFY=1
26-
CERT_CHAIN_GEN=1
2726

2827
# Ensure header is large enough to hold the cert chain (check sign tool output)
2928
# for actual length

config/examples/sim-wolfHSM-client-certchain.config

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ SPMATH=1
99

1010
# Cert chain options
1111
CERT_CHAIN_VERIFY=1
12-
CERT_CHAIN_GEN=1
1312

1413
# Ensure header is large enough to hold the cert chain (check sign tool output)
1514
# for actual length

config/examples/sim-wolfHSM-server-certchain.config

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ SPMATH=1
99

1010
# Cert chain options
1111
CERT_CHAIN_VERIFY=1
12-
CERT_CHAIN_GEN=1
1312

1413
# Ensure header is large enough to hold the cert chain (check sign tool output)
1514
# for actual length

docs/Signing.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,25 @@ wolfBoot also supports verifying firmware images using certificate chains instea
128128

129129
To generate an image for use with this mode, pass the `--cert-chain CERT_CHAIN.der` option to the sign tool, where `CERT_CHAIN.der` is a der encoded certificate chain containing one or more certificates in SSL order (leaf/signer cert last). Note that the sign tool still expects a signing private key to be provided as described above, and assumes that the public key of the signer cert in the chain corresponds to the signing private key.
130130

131+
When building wolfBoot and the test app with the Makefile, certificate chain signing can be configured using the following variables:
132+
133+
- `CERT_CHAIN_VERIFY=1`: Enables certificate chain verification mode
134+
- `USER_PRIVATE_KEY`: Path to your leaf signing key (DER format)
135+
- `USER_PUBLIC_KEY`: Path to your leaf public key (DER format)
136+
- `USER_CERT_CHAIN`: Path to your certificate chain (DER format)
137+
138+
Example:
139+
140+
```sh
141+
make CERT_CHAIN_VERIFY=1 \
142+
USER_PRIVATE_KEY=my-leaf-private-key.der \
143+
USER_PUBLIC_KEY=my-leaf-pubkey.der \
144+
USER_CERT_CHAIN=my-cert-chain.der
145+
```
146+
Note that it is up to the user to guarantee that `USER_PUBLIC_KEY` and `USER_PRIVATE_KEY` both correspond to the leaf certificate identity in the chain.
147+
148+
If `USER_CERT_CHAIN` is not provided when `CERT_CHAIN_VERIFY=1`, a dummy certificate hierarchy is auto-generated for testing. See the [Compiling wolfBoot](compile.md#key-generation-and-signing) documentation for full details on these options.
149+
131150
Certificate chain verification of images is currently limited to use in conjunction with wolfHSM. See [wolfHSM.md](wolfHSM.md) for more details.
132151

133152
#### Target partition id (Multiple partition images, "self-update" feature)

docs/compile.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,82 @@ Available overrides:
355355
- `WOLFBOOT_LIB_WOLFTPM`: Path to the [wolfTPM](https://github.com/wolfSSL/wolfTPM) library source code
356356
- `WOLFBOOT_LIB_WOLFPKCS11`: Path to the [wolfPKCS11](https://github.com/wolfssl/wolfpkcs11) library source code
357357
- `WOLFBOOT_LIB_WOLFHSM`: Path to the [wolfHSM](https://github.com/wolfSSL/wolfHSM) library source code
358+
359+
## Key Generation and Signing
360+
361+
### Default Key Behavior
362+
363+
When building wolfBoot for the first time, the build system automatically generates the cryptographic keys needed for firmware signing and verification.
364+
365+
- **Private Key**: `wolfboot_signing_private_key.der` - Used to sign firmware images
366+
- **Keystore**: `src/keystore.c` - Contains the public key embedded in the bootloader
367+
368+
The key algorithm is determined by the `SIGN` variable (e.g., `SIGN=ECC256`, `SIGN=RSA2048`).
369+
370+
For most targets, the makefile also builds the wolfBoot test app and signs it with the aforementioned key.
371+
372+
### User-Provided Keys
373+
374+
Instead of auto-generating keys, you can provide your own pre-existing keys for use with the test app by using the following Makefile variables:
375+
376+
- `USER_PRIVATE_KEY`: Path to your private signing key (DER format)
377+
- `USER_PUBLIC_KEY`: Path to your public key (DER format)
378+
379+
**Usage:**
380+
381+
```sh
382+
make USER_PRIVATE_KEY=/path/to/my-signing-key.der \
383+
USER_PUBLIC_KEY=/path/to/my-public-key.der
384+
```
385+
386+
#### Requirements
387+
388+
- Both `USER_PRIVATE_KEY` and `USER_PUBLIC_KEY` must be provided together. You cannot supply one without the other.
389+
- Keys must be in DER format appropriate for the selected `SIGN` algorithm
390+
391+
When user-provided keys are specified:
392+
393+
1. The build skips auto-generation of `wolfboot_signing_private_key.der`
394+
2. The keystore (`src/keystore.c`) is generated from your public key
395+
3. Your private key is used for all signing operations
396+
397+
The `USER_` variables are meant to simplify the wolfBoot "demo" behavior where wolfBoot boots a simple test app.
398+
399+
### User-Provided Certificate Chain
400+
401+
When using certificate chain verification (`CERT_CHAIN_VERIFY=1`), you can also provide your own certificate chain:
402+
403+
- `USER_CERT_CHAIN`: Path to your certificate chain (DER format, wolfHSM order with leaf last)
404+
405+
**Usage:**
406+
407+
```sh
408+
make CERT_CHAIN_VERIFY=1 \
409+
USER_PRIVATE_KEY=/path/to/leaf-signing-key.der \
410+
USER_PUBLIC_KEY=/path/to/leaf-public-key.der \
411+
USER_CERT_CHAIN=/path/to/my-cert-chain.der
412+
```
413+
414+
**Requirements:**
415+
416+
- `USER_CERT_CHAIN` requires both `USER_PRIVATE_KEY` and `USER_PUBLIC_KEY` to be set
417+
- The user-supplied private and public keys must correspond to the identity of the leaf certificate in the chain
418+
419+
When `CERT_CHAIN_VERIFY=1` is set without `USER_CERT_CHAIN`, the build system auto-generates a dummy 3-tier certificate hierarchy (root CA, intermediate, and leaf) in the `test-dummy-ca/` directory for testing purposes. This is then used to sign the test app.
420+
421+
### Manual Key Generation
422+
423+
As an alternative to the `USER_*` variables, you can manually fulfill the build dependencies:
424+
425+
1. **Generate or import your keystore manually:**
426+
```sh
427+
./tools/keytools/keygen --ecc256 -i my-public-key.der
428+
```
429+
This creates `src/keystore.c` from your public key.
430+
431+
2. **Place your signing key at the expected location:**
432+
```sh
433+
cp my-private-key.der wolfboot_signing_private_key.der
434+
```
435+
436+
The build system will detect these existing files and skip auto-generation when make is subsequently invoked. This approach is required when more advanced options like multiple public keys in the keystore are required. In these cases, the keystore generation using the keygen tool and image signing via the sign tool must be performed manually.

docs/keystore.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,13 @@ Returns the permissions mask, as a 32-bit word, for the public key stored in the
221221
wolfBoot supports certain platforms that contain connected HSMs (Hardware Security Modules) that can provide cryptographic services using keys that are not stored in the device NVM or readable by wolfBoot, for example, wolfHSM. In these scenarios, wolfBoot key tools should be used to generate the keys, which can then be manually loaded into the HSM (see [--exportpubkey](#exporting-the-public-key-to-a-file)). At runtime, wolfBoot will still use the keystore to obtain information about the public keys, specifically the size of the key and the key type, but does not need access to the actual key material.
222222

223223
To support this mode of operation, the `keygen` tool supports the `--nolocalkeys` option, which instructs the tool to generate a keystore entry with a zeroed key material. It still generates the `.der` files for private and public keys, so the wolfBoot key tools can sign images, but the `keystore.c` file that is linked into wolfBoot will contain all zeros in the `pubkey` field. Because the key material isn't present in the keystore, the keypair used to sign the image and stored on the HSM for verification can be updated in the field without needing to rebuild wolfBoot against a new `keystore.c`, as long as the signature algorithm and key size does not change. Most targets that use this option will automatically add it to the key generation options or explicitly mention this step in the build documentation.
224+
225+
## Using User-Provided Keys with the Keystore and Build System
226+
227+
By default, when running `make` for the first time, wolfBoot automatically generates:
228+
- A signing keypair at `wolfboot_signing_private_key.der`
229+
- The keystore module at `src/keystore.c` containing the corresponding public key
230+
231+
This default behavior can be overridden using the `USER_PRIVATE_KEY` and `USER_PUBLIC_KEY` Makefile variables, allowing you to use externally-managed keys for building the test application and keystore.
232+
233+
See [compile.md](./compile.md#key-generation-and-signing) for more information

include/user_settings.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ extern int tolower(int c);
214214
# define WC_RSA_DIRECT
215215
# define RSA_LOW_MEM
216216
# define WC_ASN_HASH_SHA256
217-
# if !defined(WOLFBOOT_TPM) && !defined(WOLFCRYPT_SECURE_MODE)
217+
# if !defined(WOLFBOOT_TPM) && !defined(WOLFCRYPT_SECURE_MODE) && \
218+
!defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
219+
!defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)
218220
# define WOLFSSL_RSA_VERIFY_INLINE
219221
# define WOLFSSL_RSA_VERIFY_ONLY
220222
# define WOLFSSL_RSA_PUBLIC_ONLY
@@ -585,6 +587,7 @@ extern int tolower(int c);
585587
# define WOLFSSL_USER_IO
586588
# define WOLFSSL_SP_MUL_D
587589
# define WOLFSSL_PEM_TO_DER
590+
# define WOLFSSL_ALLOW_NO_SUITES
588591
#endif
589592

590593
#ifdef WOLFSSL_STM32_PKA

0 commit comments

Comments
 (0)