Skip to content

Commit 43cda33

Browse files
committed
Move key_id from header into TLV
Remove the key_id field from the image header. There are two problems with this field. First, it is only an integer offset, and so causes an unnecessarily tight coupling between the particular keys built into the bootloader, and the key that is used to sign. Second, it makes the key_id part of the image header, which is included in the signature. This makes it impossible to later sign the image with a different signature. Instead of the key-id, add a TLV KEYHASH entry. This will hold the SHA256 of the public key that the signature is against. Each signature placed in the TLV should be preceeded by this entry to indicate the public key used. The signature check will check each signature, and if the KEYHASH is known and the signature type is supported, it will be checked. As long as at least one signature is considered valid, the image will be considered signed. This also allows the image to be signed with multiple signatures to support having different devices with possibly different keys compiled into the bootloaders. Based on work by Marko Kiiskila <marko@runtime.io> Signed-off-by: Marko Kiiskila <marko@runtime.io> Signed-off-by: David Brown <david.brown@linaro.org>
1 parent 76528c4 commit 43cda33

File tree

8 files changed

+170
-122
lines changed

8 files changed

+170
-122
lines changed

boot/bootutil/include/bootutil/image.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,7 @@ struct flash_area;
3737
* Image header flags.
3838
*/
3939
#define IMAGE_F_PIC 0x00000001 /* Not supported. */
40-
#define IMAGE_F_SHA256 0x00000002 /* Hash TLV is present */
41-
#define IMAGE_F_PKCS15_RSA2048_SHA256 0x00000004 /* PKCS15 w/RSA and SHA */
42-
#define IMAGE_F_ECDSA224_SHA256 0x00000008 /* ECDSA224 over SHA256 */
4340
#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */
44-
#define IMAGE_F_ECDSA256_SHA256 0x00000020 /* ECDSA256 over SHA256 */
45-
#define IMAGE_F_PKCS1_PSS_RSA2048_SHA256 0x00000040 /* PKCS1 PSS */
4641

4742
/*
4843
* ECSDA224 is with NIST P-224
@@ -52,6 +47,7 @@ struct flash_area;
5247
/*
5348
* Image trailer TLV types.
5449
*/
50+
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
5551
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
5652
#define IMAGE_TLV_RSA2048 0x20 /* RSA2048 of hash output */
5753
#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output */
@@ -71,7 +67,7 @@ struct image_version {
7167
struct image_header {
7268
uint32_t ih_magic;
7369
uint16_t ih_tlv_size; /* Combined size of trailing TLVs (bytes). */
74-
uint8_t ih_key_id; /* Which key image is signed with (0xff=unsigned). */
70+
uint8_t _pad0;
7571
uint8_t _pad1;
7672
uint16_t ih_hdr_size; /* Size of image header (bytes). */
7773
uint16_t _pad2;

boot/bootutil/src/image_validate.c

Lines changed: 103 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,53 @@ bootutil_img_hash(struct image_header *hdr, const struct flash_area *fap,
8787
return 0;
8888
}
8989

90+
/*
91+
* Currently, we only support being able to verify one type of
92+
* signature, because there is a single verification function that we
93+
* call. List the type of TLV we are expecting. If we aren't
94+
* configured for any signature, don't define this macro.
95+
*/
96+
#if defined(MCUBOOT_SIGN_RSA)
97+
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048
98+
# define EXPECTED_SIG_LEN(x) ((x) == 256) /* 2048 bits */
99+
# if defined(MCUBOOT_SIGN_EC) || defined(MCUBOOT_SIGN_EC256)
100+
# error "Multiple signature types not yet supported"
101+
# endif
102+
#elif defined(MCUBOOT_SIGN_EC)
103+
# define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA224
104+
# define EXPECTED_SIG_LEN(x) ((x) >= 64) /* oids + 2 * 28 bytes */
105+
# if defined(MCUBOOT_SIGN_EC256)
106+
# error "Multiple signature types not yet supported"
107+
# endif
108+
#elif defined(MCUBOOT_SIGN_EC256)
109+
# define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA256
110+
# define EXPECTED_SIG_LEN(x) ((x) >= 72) /* oids + 2 * 32 bytes */
111+
#endif
112+
113+
#ifdef EXPECTED_SIG_TLV
114+
static int
115+
bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len)
116+
{
117+
bootutil_sha256_context sha256_ctx;
118+
int i;
119+
const struct bootutil_key *key;
120+
uint8_t hash[32];
121+
122+
assert(keyhash_len == 32);
123+
124+
for (i = 0; i < bootutil_key_cnt; i++) {
125+
key = &bootutil_keys[i];
126+
bootutil_sha256_init(&sha256_ctx);
127+
bootutil_sha256_update(&sha256_ctx, key->key, *key->len);
128+
bootutil_sha256_finish(&sha256_ctx, hash);
129+
if (!memcmp(hash, keyhash, keyhash_len)) {
130+
return i;
131+
}
132+
}
133+
return -1;
134+
}
135+
#endif
136+
90137
/*
91138
* Verify the integrity of the image.
92139
* Return non-zero if image could not be validated/does not validate.
@@ -98,42 +145,16 @@ bootutil_img_validate(struct image_header *hdr, const struct flash_area *fap,
98145
{
99146
uint32_t off;
100147
uint32_t size;
101-
uint32_t sha_off = 0;
102-
#if defined(MCUBOOT_SIGN_RSA) || defined(MCUBOOT_SIGN_EC) || \
103-
defined(MCUBOOT_SIGN_EC256)
104-
uint32_t sig_off = 0;
105-
uint32_t sig_len = 0;
148+
int sha256_valid = 0;
149+
#ifdef EXPECTED_SIG_TLV
150+
int valid_signature = 0;
151+
int key_id = -1;
106152
#endif
107153
struct image_tlv tlv;
108154
uint8_t buf[256];
109155
uint8_t hash[32];
110156
int rc;
111157

112-
#ifdef MCUBOOT_SIGN_RSA
113-
#ifdef MCUBOOT_RSA_PKCS1_15
114-
if ((hdr->ih_flags & IMAGE_F_PKCS15_RSA2048_SHA256) == 0) {
115-
return -1;
116-
}
117-
#else
118-
if ((hdr->ih_flags & IMAGE_F_PKCS1_PSS_RSA2048_SHA256) == 0) {
119-
return -1;
120-
}
121-
#endif
122-
#endif
123-
#ifdef MCUBOOT_SIGN_EC
124-
if ((hdr->ih_flags & IMAGE_F_ECDSA224_SHA256) == 0) {
125-
return -1;
126-
}
127-
#endif
128-
#ifdef MCUBOOT_SIGN_EC256
129-
if ((hdr->ih_flags & IMAGE_F_ECDSA256_SHA256) == 0) {
130-
return -1;
131-
}
132-
#endif
133-
if ((hdr->ih_flags & IMAGE_F_SHA256) == 0) {
134-
return -1;
135-
}
136-
137158
rc = bootutil_img_hash(hdr, fap, tmp_buf, tmp_buf_sz, hash,
138159
seed, seed_len);
139160
if (rc) {
@@ -148,81 +169,81 @@ bootutil_img_validate(struct image_header *hdr, const struct flash_area *fap,
148169
off = hdr->ih_img_size + hdr->ih_hdr_size;
149170
size = off + hdr->ih_tlv_size;
150171

172+
/*
173+
* Traverse through all of the TLVs, performing any checks we know
174+
* and are able to do.
175+
*/
151176
for (; off < size; off += sizeof(tlv) + tlv.it_len) {
152177
rc = flash_area_read(fap, off, &tlv, sizeof tlv);
153178
if (rc) {
154179
return rc;
155180
}
181+
156182
if (tlv.it_type == IMAGE_TLV_SHA256) {
183+
/*
184+
* Verify the SHA256 image hash. This must always be
185+
* present.
186+
*/
157187
if (tlv.it_len != sizeof(hash)) {
158188
return -1;
159189
}
160-
sha_off = off + sizeof(tlv);
161-
}
162-
#ifdef MCUBOOT_SIGN_RSA
163-
if (tlv.it_type == IMAGE_TLV_RSA2048) {
164-
if (tlv.it_len != 256) { /* 2048 bits */
190+
rc = flash_area_read(fap, off + sizeof(tlv), buf, sizeof hash);
191+
if (rc) {
192+
return rc;
193+
}
194+
if (memcmp(hash, buf, sizeof(hash))) {
195+
return -1;
196+
}
197+
198+
sha256_valid = 1;
199+
#ifdef EXPECTED_SIG_TLV
200+
} else if (tlv.it_type == IMAGE_TLV_KEYHASH) {
201+
/*
202+
* Determine which key we should be checking.
203+
*/
204+
if (tlv.it_len > 32) {
165205
return -1;
166206
}
167-
sig_off = off + sizeof(tlv);
168-
sig_len = tlv.it_len;
169-
}
170-
#endif
171-
#ifdef MCUBOOT_SIGN_EC
172-
if (tlv.it_type == IMAGE_TLV_ECDSA224) {
173-
if (tlv.it_len < 64) { /* oids + 2 * 28 bytes */
207+
rc = flash_area_read(fap, off + sizeof tlv, buf, tlv.it_len);
208+
if (rc) {
209+
return rc;
210+
}
211+
key_id = bootutil_find_key(buf, tlv.it_len);
212+
/*
213+
* The key may not be found, which is acceptable. There
214+
* can be multiple signatures, each preceded by a key.
215+
*/
216+
} else if (tlv.it_type == EXPECTED_SIG_TLV) {
217+
/* Ignore this signature if it is out of bounds. */
218+
if (key_id < 0 || key_id >= bootutil_key_cnt) {
219+
key_id = -1;
220+
continue;
221+
}
222+
if (!EXPECTED_SIG_LEN(tlv.it_len) || tlv.it_len > sizeof(buf)) {
174223
return -1;
175224
}
176-
sig_off = off + sizeof(tlv);
177-
sig_len = tlv.it_len;
178-
}
179-
#endif
180-
#ifdef MCUBOOT_SIGN_EC256
181-
if (tlv.it_type == IMAGE_TLV_ECDSA256) {
182-
if (tlv.it_len < 72) { /* oids + 2 * 32 bytes */
225+
rc = flash_area_read(fap, off + sizeof(tlv), buf, tlv.it_len);
226+
if (rc) {
183227
return -1;
184228
}
185-
sig_off = off + sizeof(tlv);
186-
sig_len = tlv.it_len;
187-
}
229+
rc = bootutil_verify_sig(hash, sizeof(hash), buf, tlv.it_len, key_id);
230+
if (rc == 0) {
231+
valid_signature = 1;
232+
}
233+
key_id = -1;
188234
#endif
189-
}
190-
if (hdr->ih_flags & IMAGE_F_SHA256) {
191-
if (!sha_off) {
192-
/*
193-
* Header said there should be hash TLV, no TLV found.
194-
*/
195-
return -1;
196-
}
197-
rc = flash_area_read(fap, sha_off, buf, sizeof hash);
198-
if (rc) {
199-
return rc;
200-
}
201-
if (memcmp(hash, buf, sizeof(hash))) {
202-
return -1;
203235
}
204236
}
205-
#if defined(MCUBOOT_SIGN_RSA) || defined(MCUBOOT_SIGN_EC) || \
206-
defined(MCUBOOT_SIGN_EC256)
207-
if (!sig_off) {
208-
/*
209-
* Header said there should be PKCS1.v5 signature, no TLV
210-
* found.
211-
*/
212-
return -1;
213-
}
214-
rc = flash_area_read(fap, sig_off, buf, sig_len);
215-
if (rc) {
216-
return -1;
217-
}
218237

219-
if (hdr->ih_key_id >= bootutil_key_cnt) {
238+
if (!sha256_valid) {
220239
return -1;
221240
}
222-
rc = bootutil_verify_sig(hash, sizeof(hash), buf, sig_len, hdr->ih_key_id);
223-
if (rc) {
241+
242+
#ifdef EXPECTED_SIG_TLV
243+
if (!valid_signature) {
224244
return -1;
225245
}
226246
#endif
247+
227248
return 0;
228249
}

scripts/imgtool/image.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,10 @@
1212
# Image header flags.
1313
IMAGE_F = {
1414
'PIC': 0x0000001,
15-
'SHA256': 0x0000002,
16-
'PKCS15_RSA2048_SHA256': 0x0000004,
17-
'ECDSA224_SHA256': 0x0000008,
18-
'NON_BOOTABLE': 0x0000010,
19-
'ECDSA256_SHA256': 0x0000020,
20-
'PKCS1_PSS_RSA2048_SHA256': 0x0000040, }
15+
'NON_BOOTABLE': 0x0000010, }
2116

2217
TLV_VALUES = {
18+
'KEYHASH': 0x01,
2319
'SHA256': 0x10,
2420
'RSA2048': 0x20,
2521
'ECDSA224': 0x21,
@@ -106,6 +102,12 @@ def sign(self, key):
106102
tlv.add('SHA256', digest)
107103

108104
if key is not None:
105+
pub = key.get_public_bytes()
106+
sha = hashlib.sha256()
107+
sha.update(pub)
108+
pubbytes = sha.digest()
109+
tlv.add('KEYHASH', pubbytes)
110+
109111
sig = key.sign(self.payload)
110112
tlv.add(key.sig_tlv(), sig)
111113

@@ -120,10 +122,9 @@ def add_header(self, key):
120122
flags = 0
121123
tlvsz = 0
122124
if key is not None:
123-
flags |= IMAGE_F[key.sig_type()]
124125
tlvsz += TLV_HEADER_SIZE + key.sig_len()
125126

126-
flags |= IMAGE_F['SHA256']
127+
tlvsz += 4 + hashlib.sha256().digest_size
127128
tlvsz += 4 + hashlib.sha256().digest_size
128129

129130
fmt = ('<' +

sim/Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sim/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ log = "0.3"
2121
env_logger = "0.4"
2222
simflash = { path = "simflash" }
2323
mcuboot-sys = { path = "mcuboot-sys" }
24-
bitflags = "0.9"
2524
ring = { version = "0.11", features = ["rsa_signing"] }
2625
untrusted = "0.5"
2726
pem = "0.4"

sim/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#[macro_use] extern crate log;
22
extern crate ring;
33
extern crate env_logger;
4-
#[macro_use] extern crate bitflags;
54
extern crate docopt;
65
extern crate libc;
76
extern crate pem;

sim/src/rsa_pub_key-rs.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* Autogenerated by imgtool.py, do not edit. */
2+
static RSA_PUB_KEY: &'static [u8] = &[
3+
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
4+
0x00, 0xd1, 0x06, 0x08, 0x1a, 0x18, 0x44, 0x2c,
5+
0x18, 0xe8, 0xfb, 0xfd, 0xf7, 0x0d, 0xa3, 0x4f,
6+
0x1f, 0xbb, 0xee, 0x5e, 0xf9, 0xaa, 0xd2, 0x4b,
7+
0x18, 0xd3, 0x5a, 0xe9, 0x6d, 0x18, 0x80, 0x19,
8+
0xf9, 0xf0, 0x9c, 0x34, 0x1b, 0xcb, 0xf3, 0xbc,
9+
0x74, 0xdb, 0x42, 0xe7, 0x8c, 0x7f, 0x10, 0x53,
10+
0x7e, 0x43, 0x5e, 0x0d, 0x57, 0x2c, 0x44, 0xd1,
11+
0x67, 0x08, 0x0f, 0x0d, 0xbb, 0x5c, 0xee, 0xec,
12+
0xb3, 0x99, 0xdf, 0xe0, 0x4d, 0x84, 0x0b, 0xaa,
13+
0x77, 0x41, 0x60, 0xed, 0x15, 0x28, 0x49, 0xa7,
14+
0x01, 0xb4, 0x3c, 0x10, 0xe6, 0x69, 0x8c, 0x2f,
15+
0x5f, 0xac, 0x41, 0x4d, 0x9e, 0x5c, 0x14, 0xdf,
16+
0xf2, 0xf8, 0xcf, 0x3d, 0x1e, 0x6f, 0xe7, 0x5b,
17+
0xba, 0xb4, 0xa9, 0xc8, 0x88, 0x7e, 0x47, 0x3c,
18+
0x94, 0xc3, 0x77, 0x67, 0x54, 0x4b, 0xaa, 0x8d,
19+
0x38, 0x35, 0xca, 0x62, 0x61, 0x7e, 0xb7, 0xe1,
20+
0x15, 0xdb, 0x77, 0x73, 0xd4, 0xbe, 0x7b, 0x72,
21+
0x21, 0x89, 0x69, 0x24, 0xfb, 0xf8, 0x65, 0x6e,
22+
0x64, 0x3e, 0xc8, 0x0e, 0xd7, 0x85, 0xd5, 0x5c,
23+
0x4a, 0xe4, 0x53, 0x0d, 0x2f, 0xff, 0xb7, 0xfd,
24+
0xf3, 0x13, 0x39, 0x83, 0x3f, 0xa3, 0xae, 0xd2,
25+
0x0f, 0xa7, 0x6a, 0x9d, 0xf9, 0xfe, 0xb8, 0xce,
26+
0xfa, 0x2a, 0xbe, 0xaf, 0xb8, 0xe0, 0xfa, 0x82,
27+
0x37, 0x54, 0xf4, 0x3e, 0xe1, 0x2b, 0xd0, 0xd3,
28+
0x08, 0x58, 0x18, 0xf6, 0x5e, 0x4c, 0xc8, 0x88,
29+
0x81, 0x31, 0xad, 0x5f, 0xb0, 0x82, 0x17, 0xf2,
30+
0x8a, 0x69, 0x27, 0x23, 0xf3, 0xab, 0x87, 0x3e,
31+
0x93, 0x1a, 0x1d, 0xfe, 0xe8, 0xf8, 0x1a, 0x24,
32+
0x66, 0x59, 0xf8, 0x1c, 0xab, 0xdc, 0xce, 0x68,
33+
0x1b, 0x66, 0x64, 0x35, 0xec, 0xfa, 0x0d, 0x11,
34+
0x9d, 0xaf, 0x5c, 0x3a, 0xa7, 0xd1, 0x67, 0xc6,
35+
0x47, 0xef, 0xb1, 0x4b, 0x2c, 0x62, 0xe1, 0xd1,
36+
0xc9, 0x02, 0x03, 0x01, 0x00, 0x01,
37+
];

0 commit comments

Comments
 (0)