Skip to content

Commit 29bb94b

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 fe5bbcd commit 29bb94b

File tree

6 files changed

+185
-14
lines changed

6 files changed

+185
-14
lines changed

boot/bootutil/src/bootutil_priv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,18 @@ struct boot_loader_state {
265265
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
266266
};
267267

268+
/* The function is intended for verification of image hash against
269+
* provided signature.
270+
*/
268271
fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
269272
size_t slen, uint8_t key_id);
270273

274+
/* The function is intended for direct verification of image
275+
* against provided signature.
276+
*/
277+
fih_ret bootutil_verify_img(uint8_t *img, uint32_t size,
278+
uint8_t *sig, size_t slen, uint8_t key_id);
279+
271280
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n);
272281

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

boot/bootutil/src/image_ed25519.c

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,23 @@ bootutil_import_key(uint8_t **cp, uint8_t *end)
6767
return 0;
6868
}
6969

70-
fih_ret
71-
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
72-
uint8_t key_id)
70+
/* Signature verification base function.
71+
* The function takes buffer of specified length and tries to verify
72+
* it against provided signature.
73+
* The function does key import and checks whether signature is
74+
* of expected length.
75+
*/
76+
static fih_ret
77+
bootutil_verify(uint8_t *buf, uint32_t blen,
78+
uint8_t *sig, size_t slen,
79+
uint8_t key_id)
7380
{
7481
int rc;
7582
FIH_DECLARE(fih_rc, FIH_FAILURE);
7683
uint8_t *pubkey;
7784
uint8_t *end;
7885

79-
if (hlen != IMAGE_HASH_SIZE ||
80-
slen != EDDSA_SIGNATURE_LENGTH) {
86+
if (slen != EDDSA_SIGNATURE_LENGTH) {
8187
FIH_SET(fih_rc, FIH_FAILURE);
8288
goto out;
8389
}
@@ -91,7 +97,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
9197
goto out;
9298
}
9399

94-
rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey);
100+
rc = ED25519_verify(buf, blen, sig, pubkey);
95101

96102
if (rc == 0) {
97103
/* if verify returns 0, there was an error. */
@@ -105,4 +111,45 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
105111
FIH_RET(fih_rc);
106112
}
107113

114+
/* Hash signature verification function.
115+
* Verifies hash against provided signature.
116+
* The function verifies that hash is of expected size and then
117+
* calls bootutil_verify to do the signature verification.
118+
*/
119+
fih_ret
120+
bootutil_verify_sig(uint8_t *hash, uint32_t hlen,
121+
uint8_t *sig, size_t slen,
122+
uint8_t key_id)
123+
{
124+
FIH_DECLARE(fih_rc, FIH_FAILURE);
125+
126+
if (hlen != IMAGE_HASH_SIZE) {
127+
FIH_SET(fih_rc, FIH_FAILURE);
128+
goto out;
129+
}
130+
131+
FIH_CALL(bootutil_verify, fih_rc, hash, IMAGE_HASH_SIZE, sig,
132+
slen, key_id);
133+
134+
out:
135+
FIH_RET(fih_rc);
136+
}
137+
138+
/* Image verification function.
139+
* The function directly calls bootutil_verify to verify signature
140+
* of image.
141+
*/
142+
fih_ret
143+
bootutil_verify_img(uint8_t *img, uint32_t size,
144+
uint8_t *sig, size_t slen,
145+
uint8_t key_id)
146+
{
147+
FIH_DECLARE(fih_rc, FIH_FAILURE);
148+
149+
FIH_CALL(bootutil_verify, fih_rc, img, size, sig,
150+
slen, key_id);
151+
152+
FIH_RET(fih_rc);
153+
}
154+
108155
#endif /* MCUBOOT_SIGN_ED25519 */

boot/bootutil/src/image_validate.c

Lines changed: 89 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,43 @@ 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 or found but not true
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+
if (rc == 0 && len == 1) {
390+
bool val;
391+
392+
rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, 1);
393+
if (rc == 0) {
394+
rc = !val;
395+
}
396+
}
397+
398+
return rc;
399+
}
400+
#endif
401+
402+
364403
#ifndef ALLOW_ROGUE_TLVS
365404
/*
366405
* The following list of TLVs are the only entries allowed in the unprotected
@@ -377,6 +416,9 @@ static const uint16_t allowed_unprot_tlvs[] = {
377416
IMAGE_TLV_ECDSA_SIG,
378417
IMAGE_TLV_RSA3072_PSS,
379418
IMAGE_TLV_ED25519,
419+
#if defined(MCUBOOT_SIGN_PURE)
420+
IMAGE_TLV_SIG_PURE,
421+
#endif
380422
IMAGE_TLV_ENC_RSA2048,
381423
IMAGE_TLV_ENC_KW,
382424
IMAGE_TLV_ENC_EC256,
@@ -399,7 +441,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
399441
uint32_t off;
400442
uint16_t len;
401443
uint16_t type;
402-
int image_hash_valid = 0;
403444
#ifdef EXPECTED_SIG_TLV
404445
FIH_DECLARE(valid_signature, FIH_FAILURE);
405446
#ifndef MCUBOOT_BUILTIN_KEY
@@ -416,7 +457,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
416457
#endif /* EXPECTED_SIG_TLV */
417458
struct image_tlv_iter it;
418459
uint8_t buf[SIG_BUF_SIZE];
460+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
461+
int image_hash_valid = 0;
419462
uint8_t hash[IMAGE_HASH_SIZE];
463+
#endif
420464
int rc = 0;
421465
FIH_DECLARE(fih_rc, FIH_FAILURE);
422466
#ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -425,6 +469,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
425469
FIH_DECLARE(security_counter_valid, FIH_FAILURE);
426470
#endif
427471

472+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
428473
rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
429474
tmp_buf_sz, hash, seed, seed_len);
430475
if (rc) {
@@ -434,6 +479,15 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
434479
if (out_hash) {
435480
memcpy(out_hash, hash, IMAGE_HASH_SIZE);
436481
}
482+
#endif
483+
484+
#if defined(MCUBOOT_SIGN_PURE)
485+
/* If Pure type signature is expected then it has to be there */
486+
rc = bootutil_check_for_pure(hdr, fap);
487+
if (rc != 0) {
488+
goto out;
489+
}
490+
#endif
437491

438492
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
439493
if (rc) {
@@ -477,8 +531,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
477531
}
478532
}
479533
#endif
480-
481-
if (type == EXPECTED_HASH_TLV) {
534+
switch(type) {
535+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
536+
case EXPECTED_HASH_TLV:
537+
{
482538
/* Verify the image hash. This must always be present. */
483539
if (len != sizeof(hash)) {
484540
rc = -1;
@@ -496,8 +552,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
496552
}
497553

498554
image_hash_valid = 1;
555+
break;
556+
}
557+
#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */
499558
#ifdef EXPECTED_KEY_TLV
500-
} else if (type == EXPECTED_KEY_TLV) {
559+
case EXPECTED_KEY_TLV:
560+
{
501561
/*
502562
* Determine which key we should be checking.
503563
*/
@@ -522,9 +582,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
522582
* The key may not be found, which is acceptable. There
523583
* can be multiple signatures, each preceded by a key.
524584
*/
585+
break;
586+
}
525587
#endif /* EXPECTED_KEY_TLV */
526588
#ifdef EXPECTED_SIG_TLV
527-
} else if (type == EXPECTED_SIG_TLV) {
589+
case EXPECTED_SIG_TLV:
590+
{
528591
/* Ignore this signature if it is out of bounds. */
529592
if (key_id < 0 || key_id >= bootutil_key_cnt) {
530593
key_id = -1;
@@ -538,12 +601,25 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
538601
if (rc) {
539602
goto out;
540603
}
604+
#ifndef MCUBOOT_SIGN_PURE
541605
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
542606
buf, len, key_id);
607+
#else
608+
/* Directly check signature on the image, by using the mapping of
609+
* a device to memory. The pointer is beginning of image in flash,
610+
* so offset of area, the range is header + image + protected tlvs.
611+
*/
612+
FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap),
613+
hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size,
614+
buf, len, key_id);
615+
#endif
543616
key_id = -1;
617+
break;
618+
}
544619
#endif /* EXPECTED_SIG_TLV */
545620
#ifdef MCUBOOT_HW_ROLLBACK_PROT
546-
} else if (type == IMAGE_TLV_SEC_CNT) {
621+
case IMAGE_TLV_SEC_CNT:
622+
{
547623
/*
548624
* Verify the image's security counter.
549625
* This must always be present.
@@ -578,14 +654,21 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
578654

579655
/* The image's security counter has been successfully verified. */
580656
security_counter_valid = fih_rc;
657+
break;
658+
}
581659
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
582660
}
583661
}
584662

663+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
585664
rc = !image_hash_valid;
586665
if (rc) {
587666
goto out;
588667
}
668+
#elif defined(MCUBOOT_SIGN_PURE)
669+
/* This returns true on EQ, rc is err on non-0 */
670+
rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS);
671+
#endif
589672
#ifdef EXPECTED_SIG_TLV
590673
FIH_SET(fih_rc, valid_signature);
591674
#endif

boot/zephyr/Kconfig

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ config BOOT_IMG_HASH_ALG_SHA512
134134

135135
endchoice # BOOT_IMG_HASH_ALG
136136

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

184192
config BOOT_SIGNATURE_TYPE_ED25519
185193
bool "Edwards curve digital signatures using ed25519"
186-
select BOOT_ENCRYPTION_SUPPORT
187-
select BOOT_IMG_HASH_ALG_SHA256_ALLOW
194+
select BOOT_ENCRYPTION_SUPPORT if !BOOT_SIGNATURE_TYPE_PURE
195+
select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !BOOT_SIGNATURE_TYPE_PURE
196+
# The SHA is used only for key hashing, not for images.
197+
select BOOT_SIGNATURE_TYPE_PURE_ALLOW
198+
help
199+
This is ed25519 signature calculated over SHA512 of SHA256 of application
200+
image.
201+
To check signature over entire image directly, rather than hash,
202+
select BOOT_SIGNATURE_TYPE_PURE.
188203

189204
if BOOT_SIGNATURE_TYPE_ED25519
205+
206+
config BOOT_SIGNATURE_TYPE_PURE
207+
bool "Use Pure signature of image"
208+
depends on BOOT_SIGNATURE_TYPE_PURE_ALLOW
209+
help
210+
The Pure signature is calculated directly over image rather than
211+
hash of an image, as the BOOT_SIGNATURE_TYPE_ED25519 does by
212+
default.
213+
Image to be verified needs to be accessible through memory address
214+
space that cryptography functions can access via pointers.
215+
190216
choice BOOT_ED25519_IMPLEMENTATION
191217
prompt "Ecdsa implementation"
192218
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

docs/design.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ struct image_tlv {
111111
#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */
112112
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
113113
#define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */
114+
#define IMAGE_TLV_SIG_PURE 0x25 /* If true then any signature found has been
115+
* calculated over image directly. */
114116
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
115117
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW-128 or
116118
256 */

0 commit comments

Comments
 (0)