Skip to content

Commit 6fcbb82

Browse files
committed
bootutil: PureEdDSA using ED25519
The commit adds support for PureEdDSA, which validates signature of image rather than hash. This is most secure, available, ED25519 usage in MCUboot, but due to requirement of PureEdDSA to be able to calculate signature at whole message at once, here image, it only works on setups where entire image can be mapped to device address space, so that PSA functions calculating the signature can see the whole image at once. This option is enabled with Kconfig option: CONFIG_BOOT_SIGNATURE_TYPE_PURE when the ED25519 signature type is already selected. Note that the option will enable SHA512 for calculating public key hash. Signed-off-by: Dominik Ermel <[email protected]>
1 parent bc6c610 commit 6fcbb82

File tree

5 files changed

+217
-8
lines changed

5 files changed

+217
-8
lines changed

boot/bootutil/src/bootutil_priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ struct boot_loader_state {
268268
fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
269269
size_t slen, uint8_t key_id);
270270

271+
fih_ret bootutil_verify_img(const uint8_t *img, uint32_t size,
272+
uint8_t *sig, size_t slen, uint8_t key_id);
273+
271274
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n);
272275

273276
int boot_find_status(int image_index, const struct flash_area **fap);

boot/bootutil/src/image_ed25519.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,41 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
105105
FIH_RET(fih_rc);
106106
}
107107

108+
fih_ret
109+
bootutil_verify_img(const uint8_t *img, uint32_t size,
110+
uint8_t *sig, size_t slen, uint8_t key_id)
111+
{
112+
int rc;
113+
FIH_DECLARE(fih_rc, FIH_FAILURE);
114+
uint8_t *pubkey;
115+
uint8_t *end;
116+
117+
if (slen != EDDSA_SIGNATURE_LENGTH) {
118+
FIH_SET(fih_rc, FIH_FAILURE);
119+
goto out;
120+
}
121+
122+
pubkey = (uint8_t *)bootutil_keys[key_id].key;
123+
end = pubkey + *bootutil_keys[key_id].len;
124+
125+
rc = bootutil_import_key(&pubkey, end);
126+
if (rc) {
127+
FIH_SET(fih_rc, FIH_FAILURE);
128+
goto out;
129+
}
130+
131+
rc = ED25519_verify(img, size, sig, pubkey);
132+
133+
if (rc == 0) {
134+
/* if verify returns 0, there was an error. */
135+
FIH_SET(fih_rc, FIH_FAILURE);
136+
goto out;
137+
}
138+
139+
FIH_SET(fih_rc, FIH_SUCCESS);
140+
out:
141+
142+
FIH_RET(fih_rc);
143+
}
144+
108145
#endif /* MCUBOOT_SIGN_ED25519 */

boot/bootutil/src/image_validate.c

Lines changed: 141 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656

5757
#include "bootutil_priv.h"
5858

59+
#ifndef MCUBOOT_SIGN_PURE
5960
/*
6061
* Compute SHA hash over the image.
6162
* (SHA384 if ECDSA-P384 is being used,
@@ -175,6 +176,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index,
175176

176177
return 0;
177178
}
179+
#endif
178180

179181
/*
180182
* Currently, we only support being able to verify one type of
@@ -361,6 +363,35 @@ bootutil_get_img_security_cnt(struct image_header *hdr,
361363
return 0;
362364
}
363365

366+
#if defined(MCUBOOT_SIGN_PURE)
367+
/* Returns:
368+
* 0 -- found
369+
* 1 -- not found
370+
* -1 -- failed for some reason
371+
*
372+
* Value of TLV does not matter, presence decides.
373+
*/
374+
static int bootutil_check_for_pure(const struct image_header *hdr,
375+
const struct flash_area *fap)
376+
{
377+
struct image_tlv_iter it;
378+
uint32_t off;
379+
uint16_t len;
380+
int32_t rc;
381+
382+
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false);
383+
if (rc) {
384+
return rc;
385+
}
386+
387+
/* Search for the TLV */
388+
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
389+
390+
return rc;
391+
}
392+
#endif
393+
394+
364395
#ifndef ALLOW_ROGUE_TLVS
365396
/*
366397
* The following list of TLVs are the only entries allowed in the unprotected
@@ -377,6 +408,9 @@ static const uint16_t allowed_unprot_tlvs[] = {
377408
IMAGE_TLV_ECDSA_SIG,
378409
IMAGE_TLV_RSA3072_PSS,
379410
IMAGE_TLV_ED25519,
411+
#if defined(MCUBOOT_SIGN_PURE)
412+
IMAGE_TLV_SIG_PURE,
413+
#endif
380414
IMAGE_TLV_ENC_RSA2048,
381415
IMAGE_TLV_ENC_KW,
382416
IMAGE_TLV_ENC_EC256,
@@ -399,7 +433,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
399433
uint32_t off;
400434
uint16_t len;
401435
uint16_t type;
402-
int image_hash_valid = 0;
403436
#ifdef EXPECTED_SIG_TLV
404437
FIH_DECLARE(valid_signature, FIH_FAILURE);
405438
#ifndef MCUBOOT_BUILTIN_KEY
@@ -416,7 +449,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
416449
#endif /* EXPECTED_SIG_TLV */
417450
struct image_tlv_iter it;
418451
uint8_t buf[SIG_BUF_SIZE];
452+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
453+
int image_hash_valid = 0;
419454
uint8_t hash[IMAGE_HASH_SIZE];
455+
#endif
420456
int rc = 0;
421457
FIH_DECLARE(fih_rc, FIH_FAILURE);
422458
#ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -425,6 +461,67 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
425461
FIH_DECLARE(security_counter_valid, FIH_FAILURE);
426462
#endif
427463

464+
#ifdef MCUBOOT_DECOMPRESS_IMAGES
465+
/* If the image is compressed, the integrity of the image must also be validated */
466+
if (MUST_DECOMPRESS(fap, image_index, hdr)) {
467+
bool found_decompressed_size = false;
468+
bool found_decompressed_sha = false;
469+
bool found_decompressed_signature = false;
470+
471+
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true);
472+
if (rc) {
473+
goto out;
474+
}
475+
476+
if (it.tlv_end > bootutil_max_image_size(fap)) {
477+
rc = -1;
478+
goto out;
479+
}
480+
481+
while (true) {
482+
uint16_t expected_size = 0;
483+
bool *found_flag = NULL;
484+
485+
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
486+
if (rc < 0) {
487+
goto out;
488+
} else if (rc > 0) {
489+
break;
490+
}
491+
492+
switch (type) {
493+
case IMAGE_TLV_DECOMP_SIZE:
494+
expected_size = sizeof(size_t);
495+
found_flag = &found_decompressed_size;
496+
break;
497+
case IMAGE_TLV_DECOMP_SHA:
498+
expected_size = IMAGE_HASH_SIZE;
499+
found_flag = &found_decompressed_sha;
500+
break;
501+
case IMAGE_TLV_DECOMP_SIGNATURE:
502+
expected_size = SIG_BUF_SIZE;
503+
found_flag = &found_decompressed_signature;
504+
break;
505+
default:
506+
continue;
507+
};
508+
509+
if (len != expected_size) {
510+
rc = -1;
511+
goto out;
512+
}
513+
514+
*found_flag = true;
515+
}
516+
517+
rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature);
518+
if (rc) {
519+
goto out;
520+
}
521+
}
522+
#endif
523+
524+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
428525
rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
429526
tmp_buf_sz, hash, seed, seed_len);
430527
if (rc) {
@@ -434,6 +531,15 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
434531
if (out_hash) {
435532
memcpy(out_hash, hash, IMAGE_HASH_SIZE);
436533
}
534+
#endif
535+
536+
#if defined(MCUBOOT_SIGN_PURE)
537+
/* If Pure type signature is expected then it has to be there */
538+
rc = bootutil_check_for_pure(hdr, fap);
539+
if (rc != 0) {
540+
goto out;
541+
}
542+
#endif
437543

438544
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
439545
if (rc) {
@@ -477,8 +583,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
477583
}
478584
}
479585
#endif
480-
481-
if (type == EXPECTED_HASH_TLV) {
586+
switch(type) {
587+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
588+
case EXPECTED_HASH_TLV:
589+
{
482590
/* Verify the image hash. This must always be present. */
483591
if (len != sizeof(hash)) {
484592
rc = -1;
@@ -496,8 +604,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
496604
}
497605

498606
image_hash_valid = 1;
607+
break;
608+
}
609+
#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */
499610
#ifdef EXPECTED_KEY_TLV
500-
} else if (type == EXPECTED_KEY_TLV) {
611+
case EXPECTED_KEY_TLV:
612+
{
501613
/*
502614
* Determine which key we should be checking.
503615
*/
@@ -522,9 +634,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
522634
* The key may not be found, which is acceptable. There
523635
* can be multiple signatures, each preceded by a key.
524636
*/
637+
break;
638+
}
525639
#endif /* EXPECTED_KEY_TLV */
526640
#ifdef EXPECTED_SIG_TLV
527-
} else if (type == EXPECTED_SIG_TLV) {
641+
case EXPECTED_SIG_TLV:
642+
{
528643
/* Ignore this signature if it is out of bounds. */
529644
if (key_id < 0 || key_id >= bootutil_key_cnt) {
530645
key_id = -1;
@@ -538,12 +653,25 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
538653
if (rc) {
539654
goto out;
540655
}
656+
#ifndef MCUBOOT_SIGN_PURE
541657
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
542658
buf, len, key_id);
659+
#else
660+
/* Directly check signature on the image, by using the mapping of
661+
* a device to memory. The pointer is beginning of image in flash,
662+
* so offset of area, the range is header + image + protected tlvs.
663+
*/
664+
FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap),
665+
hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size,
666+
buf, len, key_id);
667+
#endif
543668
key_id = -1;
669+
break;
670+
}
544671
#endif /* EXPECTED_SIG_TLV */
545672
#ifdef MCUBOOT_HW_ROLLBACK_PROT
546-
} else if (type == IMAGE_TLV_SEC_CNT) {
673+
case IMAGE_TLV_SEC_CNT:
674+
{
547675
/*
548676
* Verify the image's security counter.
549677
* This must always be present.
@@ -578,14 +706,21 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
578706

579707
/* The image's security counter has been successfully verified. */
580708
security_counter_valid = fih_rc;
709+
break;
710+
}
581711
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
582712
}
583713
}
584714

715+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
585716
rc = !image_hash_valid;
586717
if (rc) {
587718
goto out;
588719
}
720+
#elif defined(MCUBOOT_SIGN_PURE)
721+
/* This returns true on EQ, rc is err on non-0 */
722+
rc = !FIH_EQ(valid_signature, FIH_SUCCESS);
723+
#endif
589724
#ifdef EXPECTED_SIG_TLV
590725
FIH_SET(fih_rc, valid_signature);
591726
#endif

boot/zephyr/Kconfig

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ config BOOT_IMG_HASH_ALG_SHA512
135135

136136
endchoice # BOOT_IMG_HASH_ALG
137137

138+
config BOOT_SIGNATURE_TYPE_PURE_ALLOW
139+
bool
140+
help
141+
Hidden option set by configurations that allow Pure variant,
142+
for example ed25519. The pure variant means that image
143+
signature is calculated over entire image instead of hash
144+
of an image.
145+
138146
choice BOOT_SIGNATURE_TYPE
139147
prompt "Signature type"
140148
default BOOT_SIGNATURE_TYPE_RSA
@@ -184,10 +192,32 @@ endif
184192

185193
config BOOT_SIGNATURE_TYPE_ED25519
186194
bool "Edwards curve digital signatures using ed25519"
187-
select BOOT_ENCRYPTION_SUPPORT
188-
select BOOT_IMG_HASH_ALG_SHA256_ALLOW
195+
select BOOT_ENCRYPTION_SUPPORT if !BOOT_SIGNATURE_TYPE_PURE
196+
select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !BOOT_SIGNATURE_TYPE_PURE
197+
# The SHA is used only for key hashing, not for images.
198+
select BOOT_IMG_HASH_ALG_SHA512_ALLOW
199+
select BOOT_SIGNATURE_TYPE_PURE_ALLOW
200+
help
201+
This is ed25519 signature calculated over SHA512 of SHA256 of application
202+
image; that is not completely correct approach as the SHA512 should be
203+
rather directly calculated over an image.
204+
Select BOOT_SIGNATURE_TYPE_PURE to have a PureEdDSA calculating image
205+
signature directly on image, rather than hash of the image.
189206

190207
if BOOT_SIGNATURE_TYPE_ED25519
208+
209+
config BOOT_SIGNATURE_TYPE_PURE
210+
bool "Use Pure signature of image"
211+
depends on BOOT_SIGNATURE_TYPE_PURE_ALLOW
212+
help
213+
The Pure signature is calculated directly over image rather than
214+
hash of an image.
215+
This is more secure signature, specifically if hardware can do the
216+
verification without need to share key.
217+
Note that this requires that all slots for which signature is to be
218+
verified need to be accessible through memory address space that
219+
cryptography can access.
220+
191221
choice BOOT_ED25519_IMPLEMENTATION
192222
prompt "Ecdsa implementation"
193223
default BOOT_ED25519_TINYCRYPT

boot/zephyr/include/mcuboot_config/mcuboot_config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@
148148
#define MCUBOOT_HASH_STORAGE_DIRECTLY
149149
#endif
150150

151+
#ifdef CONFIG_BOOT_SIGNATURE_TYPE_PURE
152+
#define MCUBOOT_SIGN_PURE
153+
#endif
154+
151155
#ifdef CONFIG_BOOT_BOOTSTRAP
152156
#define MCUBOOT_BOOTSTRAP 1
153157
#endif

0 commit comments

Comments
 (0)