Skip to content

Commit 8796af8

Browse files
authored
Merge pull request #373 from danielinux/universal_keystore
Improvement to keystore and key management tools
2 parents 9cf9472 + dd8fb02 commit 8796af8

File tree

8 files changed

+277
-72
lines changed

8 files changed

+277
-72
lines changed

.github/workflows/test-keytools.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,97 @@ jobs:
144144
- name: Generate final signed binary
145145
run: |
146146
./tools/keytools/sign --rsa2048 --sha256 --manual-sign test-app/image.elf public-key.der 1 test-app/image_v1.sig
147+
148+
# SIGN tool options
149+
- name: make clean
150+
run: |
151+
make distclean
152+
153+
- name: Select config
154+
run: |
155+
cp config/examples/sim.config .config && make include/target.h
156+
157+
- name: Build tools
158+
run: |
159+
make -C tools/keytools && make -C tools/bin-assemble
160+
161+
- name: Build wolfboot
162+
run: |
163+
make SIGN=ECC256 HASH=SHA256
164+
165+
- name: Sign without timestamp
166+
run: |
167+
./tools/keytools/sign --ecc256 --sha256 --no-ts test-app/image.elf wolfboot_signing_private_key.der 2
168+
169+
# TODO: requires hexdump
170+
#- name: Check that timestamp is not included in the signed image
171+
# run: |
172+
# ! (hexdump -C -n 256 test-app/image_v3_signed.bin |grep "02 00 08 00")
173+
174+
# Universal keystore
175+
- name: make clean
176+
run: |
177+
make distclean
178+
179+
- name: Select config
180+
run: |
181+
cp config/examples/sim.config .config && make include/target.h
182+
183+
- name: Build tools
184+
run: |
185+
make -C tools/keytools && make -C tools/bin-assemble
186+
187+
- name: Generate external RSA2048 key
188+
run: |
189+
openssl genrsa -out private-key.pem 2048
190+
191+
- name: Convert to DER
192+
run: |
193+
openssl rsa -in private-key.pem -inform PEM -out private-key.der -outform DER
194+
195+
- name: Export external public key
196+
run: |
197+
openssl rsa -inform DER -outform DER -in private-key.der -out public-rsa2048-key.der -pubout
198+
199+
- name: Add different keys to the keystore (two generated ECC with different curves, one imported RSA)
200+
run: |
201+
./tools/keytools/keygen --rsa2048 -i public-rsa2048-key.der --ecc256 -g wolfboot_signing_private_key.der --ecc384 -g ecc384-priv-key.der
202+
203+
- name: Build wolfboot with universal keystore
204+
run: |
205+
make SIGN=ECC256 HASH=SHA256 WOLFBOOT_UNIVERSAL_KEYSTORE=1
206+
207+
# keygen option: masks
208+
- name: make clean
209+
run: |
210+
make distclean
211+
212+
- name: Select config
213+
run: |
214+
cp config/examples/sim.config .config && make include/target.h
215+
216+
- name: Build tools
217+
run: |
218+
make -C tools/keytools && make -C tools/bin-assemble
219+
220+
- name: Run keygen with no specific mask
221+
run: |
222+
./tools/keytools/keygen --ecc256 -g wolfboot_signing_private_key.der | grep "mask" | grep "ffffffff"
223+
224+
- name: Delete generated key
225+
run: |
226+
rm -f wolfboot_signing_private_key.der
227+
228+
- name: Run keygen with --id 0
229+
run: |
230+
./tools/keytools/keygen --id 0 --ecc256 -g wolfboot_signing_private_key.der | grep "mask" | grep "00000001"
231+
232+
- name: Delete generated key
233+
run: |
234+
rm -f wolfboot_signing_private_key.der
235+
236+
- name: Run keygen with test id set
237+
run: |
238+
./tools/keytools/keygen --id 1,3,5,10,11,13,14 --ecc256 -g wolfboot_signing_private_key.der | grep "mask" | grep "00006c2a"
239+
240+

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ tools/tpm/pcr_read
105105
tools/tpm/pcr_reset
106106
tools/tpm/pcr_extend
107107
tools/tpm/policy_create
108+
tools/tpm/policy_sign
108109
config/*.ld
109110

110111
# Generated confiuguration file

docs/keystore.md

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,24 +117,48 @@ By default, when a new keystore is created, the permissions mask is set
117117
to `KEY_VERIFY_ALL`, which means that the key can be used to verify a firmware
118118
targeting any partition id.
119119

120-
To restrict the permissions for single keys, it would be sufficient to change the value
121-
of their `part_id_mask` attributes.
122-
123120
The `part_id_mask` value is a bitmask, where each bit represent a different partition.
124121
The bit '0' is reserved for wolfBoot self-update, while typically the main firmware partition
125122
is associated to id 1, so it requires a key with the bit '1' set. In other words, signing a
126123
partition with `--id 3` would require turning on bit '3' in the mask, i.e. adding (1U << 3) to it.
127124

128-
Beside `KEY_VERIFY_ALL`, pre-defined mask values can also be used here:
125+
To restrict the permissions for single keys, it would be sufficient to change the value
126+
of each key `part_id_mask`. This is done via the `--id` command line option for keygen.
127+
Each generated or imported key can be associated with a number of partition by passing the
128+
partition IDs in a comma-separated list, e.g.:
129+
130+
```
131+
keygen --ecc256 -g generic.key --id 1,2,3 -g restricted.key
132+
```
129133

130-
- `KEY_VERIFY_APP_ONLY` only verifies the main application, with partition id 1
131-
- `KEY_VERIFY_SELF_ONLY` this key can only be used to authenticate wolfBoot self-updates (id = 0)
132-
- `KEY_VERIFY_ONLY_ID(N)` macro that can be used to restrict the usage of the key to a specific partition id `N`
134+
Generates two keypairs, `generic.key` and `restricted.key`. The former assumes the
135+
default mask `KEY_VERIFY_ALL`, which makes it possible to use it to authenticate any
136+
of the system components. The latter instead, will carry a mask with only the bits
137+
'1', '2', and '3' set (mask = b00001110 =0x000e), allowing the usage only with the assigned
138+
partition IDs.
133139

134140

135141
### Importing public keys
136142

137-
Work in progress.
143+
The "-i" option is used to import existing public keys into the keyvault. The usage is identical to the '-g' option, except that
144+
the file provided must exist and contain a valid public key of the given algorithm and key size.
145+
146+
### Generating and importing keys of different types
147+
148+
By default, wolfBoot hardcodes the type of key used for all the signature verification operations into the keystore format.
149+
150+
Alternatively, wolfBoot can be compiled with the option `WOLFBOOT_UNIVERSAL_KEYSTORE=1`, which disables the check at compile
151+
time and allows adding keys of different types to the keystore. For example, if we want to create two keypairs with different ECC curves,
152+
and additionally store a pre-existing RSA2048 public key file `rsa-pub.der`, we could run the following:
153+
154+
`keygen --ecc256 -g a.key --ecc384 -g b.key --rsa2048 -i rsa-pub.der`
155+
156+
The command above generates a keystore with three public keys that are accessible by the bootloader at runtime.
157+
158+
Please note that by default wolfBoot does not include any public key algorithm implementations besides the one
159+
selected via the option `SIGN=`, so usually this feature is reserved to specific use cases where other policies or components
160+
in the chain-of-trust require to store different key types for different purposes.
161+
138162

139163
## Using KeyStore with external Key Vaults
140164

@@ -152,7 +176,7 @@ The API consists of a few functions described below.
152176

153177
Returns the number of slots in the keystore. At least one slot
154178
should be populated if you want to authenticate your firmware today.
155-
The interface assumes that the slots are numbered sequentially, from zero to
179+
The interface assumes that the slots are numbered sequentially, from zero to
156180
`keystore_num_pubkeys() - 1`. Accessing those slots through this API should always
157181
return a valid public key.
158182

@@ -174,5 +198,3 @@ public key associated to the slot `id`.
174198
`uint32_t keystore_get_mask(int id)`
175199

176200
Returns the permissions mask, as a 32-bit word, for the public key stored in the slot `id`.
177-
178-

include/wolfboot/wolfboot.h

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,35 +175,53 @@ extern "C" {
175175
/* Authentication configuration */
176176
#if defined(WOLFBOOT_NO_SIGN)
177177
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_NONE
178-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_NONE
178+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
179+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_NONE
180+
# endif
179181
#elif defined(WOLFBOOT_SIGN_ED25519)
180182
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ED25519
181-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ED25519
183+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
184+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ED25519
185+
# endif
182186
#elif defined(WOLFBOOT_SIGN_ED448)
183187
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ED448
184-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ED448
188+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
189+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ED448
190+
# endif
185191
#elif defined(WOLFBOOT_SIGN_ECC256)
186192
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ECC256
187-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC256
193+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
194+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC256
195+
# endif
188196
#elif defined(WOLFBOOT_SIGN_ECC384)
189197
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ECC384
190-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC384
198+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
199+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC384
200+
# endif
191201
#elif defined(WOLFBOOT_SIGN_ECC521)
192202
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ECC521
193203
# error "ECC521 curves not yet supported in this version of wolfBoot. " \
194204
"Please select a valid SIGN= option."
195205
#elif defined(WOLFBOOT_SIGN_RSA2048)
196206
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSA2048
197-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA2048
207+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
208+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA2048
209+
# endif
198210
#elif defined(WOLFBOOT_SIGN_RSA3072)
199211
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSA3072
200-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA3072
212+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
213+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA3072
214+
# endif
201215
#elif defined(WOLFBOOT_SIGN_RSA4096)
202216
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSA4096
203-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA4096
217+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
218+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA4096
219+
# endif
204220
#elif defined(WOLFBOOT_SIGN_LMS)
205221
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_LMS
206-
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_LMS
222+
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
223+
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_LMS
224+
# endif
207225
#else
208226
# error "No valid authentication mechanism selected. " \
209227
"Please select a valid SIGN= option."

options.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,10 @@ ifeq ($(64BIT),1)
657657
CFLAGS+=-DWOLFBOOT_64BIT
658658
endif
659659

660+
ifeq ($(WOLFBOOT_UNIVERSAL_KEYSTORE),1)
661+
CFLAGS+=-DWOLFBOOT_UNIVERSAL_KEYSTORE
662+
endif
663+
660664
ifeq ($(DISK_LOCK),1)
661665
CFLAGS+=-DWOLFBOOT_ATA_DISK_LOCK
662666
ifneq ($(DISK_LOCK_PASSWORD),)

tools/config.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ ifeq ($(ARCH),)
5353
MEASURED_BOOT?=0
5454
WOLFBOOT_TPM_SEAL?=0
5555
WOLFBOOT_TPM_KEYSTORE?=0
56+
WOLFBOOT_UNIVERSAL_KEYSTORE?=0
5657
TZEN?=0
5758
WOLFCRYPT_TZ?=0
5859
WOLFCRYPT_TZ_PKCS11?=0
@@ -91,4 +92,5 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
9192
WOLFBOOT_HUGE_STACK FORCE_32BIT\
9293
ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \
9394
LMS_LEVELS LMS_HEIGHT LMS_WINTERNITZ \
95+
WOLFBOOT_UNIVERSAL_KEYSTORE \
9496
ELF

0 commit comments

Comments
 (0)