Skip to content

Commit 6c8f526

Browse files
committed
[nrf noup] 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 9d91a87 commit 6c8f526

File tree

6 files changed

+155
-7
lines changed

6 files changed

+155
-7
lines changed

boot/bootutil/include/bootutil/image.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ struct flash_area;
102102
#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */
103103
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
104104
#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */
105+
#define IMAGE_TLV_SIG_PURE 0x25 /* Whatever signature has been selected, it will be used
106+
* as "pure" where signature is verified over entire
107+
* image rather than hash of an image */
105108
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
106109
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/
107110
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */

boot/bootutil/src/bootutil_priv.h

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

265+
fih_ret bootutil_verify_img(const uint8_t *img, uint32_t size,
266+
uint8_t *sig, size_t slen, uint8_t key_id);
267+
265268
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n);
266269

267270
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
@@ -111,4 +111,41 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
111111
FIH_RET(fih_rc);
112112
}
113113

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

boot/bootutil/src/image_validate.c

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ BOOT_LOG_MODULE_DECLARE(mcuboot);
6565

6666
#include "bootutil_priv.h"
6767

68+
#ifndef MCUBOOT_SIGN_PURE
6869
/*
6970
* Compute SHA hash over the image.
7071
* (SHA384 if ECDSA-P384 is being used,
@@ -187,6 +188,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index,
187188

188189
return 0;
189190
}
191+
#endif
190192

191193
/*
192194
* Currently, we only support being able to verify one type of
@@ -373,6 +375,35 @@ bootutil_get_img_security_cnt(struct image_header *hdr,
373375
return 0;
374376
}
375377

378+
#if defined(MCUBOOT_SIGN_PURE)
379+
/* Returns:
380+
* 0 -- found
381+
* 1 -- not found
382+
* -1 -- failed for some reason
383+
*
384+
* Value of TLV does not matter, presence decides.
385+
*/
386+
static int bootutil_check_for_pure(const struct image_header *hdr,
387+
const struct flash_area *fap)
388+
{
389+
struct image_tlv_iter it;
390+
uint32_t off;
391+
uint16_t len;
392+
int32_t rc;
393+
394+
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false);
395+
if (rc) {
396+
return rc;
397+
}
398+
399+
/* Search for the TLV */
400+
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
401+
402+
return rc;
403+
}
404+
#endif
405+
406+
376407
#ifndef ALLOW_ROGUE_TLVS
377408
/*
378409
* The following list of TLVs are the only entries allowed in the unprotected
@@ -389,6 +420,9 @@ static const uint16_t allowed_unprot_tlvs[] = {
389420
IMAGE_TLV_ECDSA_SIG,
390421
IMAGE_TLV_RSA3072_PSS,
391422
IMAGE_TLV_ED25519,
423+
#if defined(MCUBOOT_SIGN_PURE)
424+
IMAGE_TLV_SIG_PURE,
425+
#endif
392426
IMAGE_TLV_ENC_RSA2048,
393427
IMAGE_TLV_ENC_KW,
394428
IMAGE_TLV_ENC_EC256,
@@ -411,7 +445,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
411445
uint32_t off;
412446
uint16_t len;
413447
uint16_t type;
414-
int image_hash_valid = 0;
415448
#ifdef EXPECTED_SIG_TLV
416449
FIH_DECLARE(valid_signature, FIH_FAILURE);
417450
#ifndef MCUBOOT_BUILTIN_KEY
@@ -428,7 +461,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
428461
#endif /* EXPECTED_SIG_TLV */
429462
struct image_tlv_iter it;
430463
uint8_t buf[SIG_BUF_SIZE];
464+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
465+
int image_hash_valid = 0;
431466
uint8_t hash[IMAGE_HASH_SIZE];
467+
#endif
432468
int rc = 0;
433469
FIH_DECLARE(fih_rc, FIH_FAILURE);
434470
#ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -497,6 +533,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
497533
}
498534
#endif
499535

536+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
500537
rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
501538
tmp_buf_sz, hash, seed, seed_len);
502539
if (rc) {
@@ -506,6 +543,15 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
506543
if (out_hash) {
507544
memcpy(out_hash, hash, IMAGE_HASH_SIZE);
508545
}
546+
#endif
547+
548+
#if defined(MCUBOOT_SIGN_PURE)
549+
/* If Pure type signature is expected then it has to be there */
550+
rc = bootutil_check_for_pure(hdr, fap);
551+
if (rc != 0) {
552+
goto out;
553+
}
554+
#endif
509555

510556
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
511557
if (rc) {
@@ -549,8 +595,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
549595
}
550596
}
551597
#endif
552-
553-
if (type == EXPECTED_HASH_TLV) {
598+
switch(type) {
599+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
600+
case EXPECTED_HASH_TLV:
601+
{
554602
/* Verify the image hash. This must always be present. */
555603
if (len != sizeof(hash)) {
556604
rc = -1;
@@ -568,8 +616,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
568616
}
569617

570618
image_hash_valid = 1;
619+
break;
620+
}
621+
#endif /*def EXPECTED_HASH_TLV */
571622
#ifdef EXPECTED_KEY_TLV
572-
} else if (type == EXPECTED_KEY_TLV) {
623+
case EXPECTED_KEY_TLV:
624+
{
573625
/*
574626
* Determine which key we should be checking.
575627
*/
@@ -594,9 +646,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
594646
* The key may not be found, which is acceptable. There
595647
* can be multiple signatures, each preceded by a key.
596648
*/
649+
break;
650+
}
597651
#endif /* EXPECTED_KEY_TLV */
598652
#ifdef EXPECTED_SIG_TLV
599-
} else if (type == EXPECTED_SIG_TLV) {
653+
case EXPECTED_SIG_TLV:
654+
{
600655
/* Ignore this signature if it is out of bounds. */
601656
if (key_id < 0 || key_id >= bootutil_key_cnt) {
602657
key_id = -1;
@@ -610,12 +665,25 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
610665
if (rc) {
611666
goto out;
612667
}
668+
#ifndef MCUBOOT_SIGN_PURE
613669
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
614670
buf, len, key_id);
671+
#else
672+
/* Directly check signature on the image, by using the mapping of
673+
* a device to memory. The pointer is beginning of image in flash,
674+
* so offset of area, the range is header + image + protected tlvs.
675+
*/
676+
FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap),
677+
hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size,
678+
buf, len, key_id);
679+
#endif
615680
key_id = -1;
681+
break;
682+
}
616683
#endif /* EXPECTED_SIG_TLV */
617684
#ifdef MCUBOOT_HW_ROLLBACK_PROT
618-
} else if (type == IMAGE_TLV_SEC_CNT) {
685+
case IMAGE_TLV_SEC_CNT:
686+
{
619687
/*
620688
* Verify the image's security counter.
621689
* This must always be present.
@@ -650,14 +718,21 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
650718

651719
/* The image's security counter has been successfully verified. */
652720
security_counter_valid = fih_rc;
721+
break;
722+
}
653723
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
654724
}
655725
}
656726

727+
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
657728
rc = !image_hash_valid;
658729
if (rc) {
659730
goto out;
660731
}
732+
#elif defined(MCUBOOT_SIGN_PURE)
733+
/* This returns true on EQ, rc is err on non-0 */
734+
rc = !FIH_EQ(valid_signature, FIH_SUCCESS);
735+
#endif
661736
#ifdef EXPECTED_SIG_TLV
662737
FIH_SET(fih_rc, valid_signature);
663738
#endif

boot/zephyr/Kconfig

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ config BOOT_IMG_HASH_ALG_SHA512
194194

195195
endchoice # BOOT_IMG_HASH_ALG
196196

197+
config BOOT_SIGNATURE_TYPE_PURE_ALLOW
198+
bool
199+
help
200+
Hidden option set by configurations that allow Pure variant,
201+
for example ed25519. The pure variant means that image
202+
signature is calculated over entire image instead of hash
203+
of an image.
204+
197205
choice BOOT_SIGNATURE_TYPE
198206
prompt "Signature type"
199207
default BOOT_SIGNATURE_TYPE_ED25519 if BOARD_NRF54L15PDK_NRF54L15_CPUAPP
@@ -248,11 +256,29 @@ config BOOT_SIGNATURE_TYPE_ED25519
248256
This is ed25519 signature calculated over SHA512 of SHA256 of application
249257
image; that is not completely correct approach as the SHA512 should be
250258
rather directly calculated over an image.
259+
Select BOOT_SIGNATURE_TYPE_PURE to have a PureEdDSA calculating image
260+
signature directly on image, rather than hash of the image.
251261
select BOOT_ENCRYPTION_SUPPORT
252-
select BOOT_IMG_HASH_ALG_SHA256_ALLOW
262+
select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !BOOT_SIGNATURE_TYPE_PURE
263+
# The SHA is used only for key hashing, not for images.
253264
select BOOT_IMG_HASH_ALG_SHA512_ALLOW
265+
select BOOT_SIGNATURE_TYPE_PURE_ALLOW
254266

255267
if BOOT_SIGNATURE_TYPE_ED25519
268+
269+
config BOOT_SIGNATURE_TYPE_PURE
270+
bool "Use Pure signature of image"
271+
help
272+
The Pure signature is calculated directly over image rather than
273+
hash of an image.
274+
This is more secure signature, specifically if hardware can do the
275+
verification without need to share key.
276+
Note that this requires that all slots for which signature is to be
277+
verified need to be accessible through memory address space that
278+
cryptography can access.
279+
select BOOT_ENCRYPTION_SUPPORT
280+
depends on BOOT_SIGNATURE_TYPE_PURE_ALLOW
281+
256282
choice BOOT_ED25519_IMPLEMENTATION
257283
prompt "Ecdsa implementation"
258284
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
@@ -150,6 +150,10 @@
150150
#define MCUBOOT_HASH_STORAGE_DIRECTLY
151151
#endif
152152

153+
#ifdef CONFIG_BOOT_SIGNATURE_TYPE_PURE
154+
#define MCUBOOT_SIGN_PURE
155+
#endif
156+
153157
#ifdef CONFIG_BOOT_BOOTSTRAP
154158
#define MCUBOOT_BOOTSTRAP 1
155159
#endif

0 commit comments

Comments
 (0)