diff --git a/boot/boot_serial/src/boot_serial_encryption.c b/boot/boot_serial/src/boot_serial_encryption.c index 6201e6b69..c4bd7d87b 100644 --- a/boot/boot_serial/src/boot_serial_encryption.c +++ b/boot/boot_serial/src/boot_serial_encryption.c @@ -36,11 +36,7 @@ boot_image_validate_encrypted(const struct flash_area *fa_p, memset(&boot_data, 0, sizeof(struct boot_loader_state)); image_index = BOOT_CURR_IMG(state); if(IS_ENCRYPTED(hdr)) { - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fa_p, bs); - if (rc < 0) { - FIH_RET(fih_rc); - } - rc = flash_area_id_to_multi_image_slot(image_index, flash_area_get_id(fa_p)); + rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fa_p, bs); if (rc < 0) { FIH_RET(fih_rc); } @@ -129,10 +125,11 @@ decrypt_region_inplace(struct boot_loader_state *state, size_t blk_off; uint16_t idx; uint32_t blk_sz; - uint8_t image_index; - + int slot = flash_area_id_to_multi_image_slot(BOOT_CURR_IMG(state), + flash_area_get_id(fap)); uint8_t buf[sz] __attribute__((aligned)); assert(sz <= sizeof buf); + assert(slot >= 0); bytes_copied = 0; while (bytes_copied < sz) { @@ -147,7 +144,6 @@ decrypt_region_inplace(struct boot_loader_state *state, return BOOT_EFLASH; } - image_index = BOOT_CURR_IMG(state); if (IS_ENCRYPTED(hdr)) { blk_sz = chunk_sz; idx = 0; @@ -175,7 +171,7 @@ decrypt_region_inplace(struct boot_loader_state *state, blk_sz = tlv_off - (off + bytes_copied); } } - boot_encrypt(BOOT_CURR_ENC(state), image_index, fap, + boot_enc_decrypt(BOOT_CURR_ENC(state), slot, (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, blk_off, &buf[idx]); } @@ -222,7 +218,6 @@ decrypt_image_inplace(const struct flash_area *fa_p, size_t sect_size; size_t sect_count; size_t sect; - uint8_t image_index; struct flash_sector sector; memset(&boot_data, 0, sizeof(struct boot_loader_state)); @@ -232,8 +227,6 @@ decrypt_image_inplace(const struct flash_area *fa_p, rc = flash_area_get_sector(fa_p, boot_status_off(fa_p), §or); - image_index = BOOT_CURR_IMG(state); - if(IS_ENCRYPTED(hdr)) { #if 0 //Skip this step?, the image will just not boot if it's not decrypted properly static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; @@ -245,7 +238,7 @@ decrypt_image_inplace(const struct flash_area *fa_p, #endif memset(&boot_data, 0, sizeof(struct boot_loader_state)); /* Load the encryption keys into cache */ - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fa_p, bs); + rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fa_p, bs); if (rc < 0) { FIH_RET(fih_rc); } diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h index e69b0372f..fd2416176 100644 --- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h @@ -15,8 +15,8 @@ #include "mcuboot_config/mcuboot_config.h" #if (defined(MCUBOOT_USE_MBED_TLS) + \ - defined(MCUBOOT_USE_TINYCRYPT)) != 1 - #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT" + defined(MCUBOOT_USE_TINYCRYPT) + defined(MCUBOOT_USE_PSA_CRYPTO)) != 1 + #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT or PSA" #endif #if defined(MCUBOOT_USE_MBED_TLS) @@ -38,12 +38,46 @@ #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE #endif /* MCUBOOT_USE_TINYCRYPT */ + +#if defined(MCUBOOT_USE_PSA_CRYPTO) + #include + #include "bootutil/enc_key_public.h" + #define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE + #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16) +#endif + #include #ifdef __cplusplus extern "C" { #endif +#if defined(MCUBOOT_USE_PSA_CRYPTO) +typedef struct { + /* Fixme: This should not be, here, psa_key_id should be passed */ + uint8_t key[BOOT_ENC_KEY_SIZE]; +} bootutil_aes_ctr_context; + +void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx); + +static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) +{ + memset(ctx, 0, sizeof(ctx)); +} + +static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) +{ + memcpy(ctx->key, k, sizeof(ctx->key)); + + return 0; +} + +int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c); +int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m); +#endif + #if defined(MCUBOOT_USE_MBED_TLS) typedef mbedtls_aes_context bootutil_aes_ctr_context; static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) diff --git a/boot/bootutil/include/bootutil/crypto/common.h b/boot/bootutil/include/bootutil/crypto/common.h index c765fe1f3..1fb5c5835 100644 --- a/boot/bootutil/include/bootutil/crypto/common.h +++ b/boot/bootutil/include/bootutil/crypto/common.h @@ -17,4 +17,13 @@ #define MBEDTLS_CONTEXT_MEMBER(X) X #endif +/* Newer versions of Mbed TLS have removed the private accessor requirement for + * the ASN1 fields. + */ +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) && (MBEDTLS_VERSION_NUMBER < 0x03010000) +#define ASN1_CONTEXT_MEMBER(X) MBEDTLS_PRIVATE(X) +#else +#define ASN1_CONTEXT_MEMBER(X) X +#endif + #endif /* __BOOTUTIL_CRYPTO_COMMON_H__ */ diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 450450dc3..85355f20c 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -109,13 +109,13 @@ static int bootutil_import_key(uint8_t **cp, uint8_t *end) return -2; } /* id-ecPublicKey (RFC5480) */ - if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || - memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -3; } /* namedCurve (RFC5480) */ - if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 || - memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { + if (param.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 || + memcmp(param.ASN1_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { return -4; } /* ECPoint (RFC5480) */ @@ -521,12 +521,12 @@ static int bootutil_parse_eckey(bootutil_ecdsa_context *ctx, uint8_t **p, uint8_ if (mbedtls_asn1_get_alg(p, end, &alg, ¶m)) { return -2; } - if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || - memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -3; } - if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1|| - memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { + if (param.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1|| + memcmp(param.ASN1_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { return -4; } diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h index 768dd8e7e..966f2d6a7 100644 --- a/boot/bootutil/include/bootutil/enc_key.h +++ b/boot/bootutil/include/bootutil/enc_key.h @@ -48,19 +48,21 @@ struct enc_key_data { extern const struct bootutil_key bootutil_enc_key; struct boot_status; +/* Decrypt random, symmetric encryption key */ +int boot_decrypt_key(const uint8_t *buf, uint8_t *enckey); + int boot_enc_init(struct enc_key_data *enc_state, uint8_t slot); int boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot); int boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, const struct boot_status *bs); -int boot_enc_load(struct enc_key_data *enc_state, int image_index, +int boot_enc_load(struct enc_key_data *enc_state, int slot, const struct image_header *hdr, const struct flash_area *fap, struct boot_status *bs); -int boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey); -bool boot_enc_valid(struct enc_key_data *enc_state, int image_index, - const struct flash_area *fap); -void boot_encrypt(struct enc_key_data *enc_state, int image_index, - const struct flash_area *fap, uint32_t off, uint32_t sz, - uint32_t blk_off, uint8_t *buf); +bool boot_enc_valid(struct enc_key_data *enc_state, int slot); +void boot_enc_encrypt(struct enc_key_data *enc_state, int slot, + uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf); +void boot_enc_decrypt(struct enc_key_data *enc_state, int slot, + uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf); void boot_enc_zeroize(struct enc_key_data *enc_state); #ifdef __cplusplus diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 87b863507..e06ec83d6 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -283,7 +283,7 @@ boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status } /* Only try to decrypt non-erased TLV metadata */ if (i != BOOT_ENC_TLV_ALIGN_SIZE) { - rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]); + rc = boot_decrypt_key(bs->enctlv[slot], bs->enckey[slot]); } } #else diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c new file mode 100644 index 000000000..3d7274307 --- /dev/null +++ b/boot/bootutil/src/ed25519_psa.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include +#include +#include + +#include +#include "bootutil/bootutil_log.h" + +#include +#include + +BOOT_LOG_MODULE_DECLARE(ed25519_psa); + +#define SHA512_DIGEST_LENGTH 64 +#define EDDSA_KEY_LENGTH 32 +#define EDDSA_SIGNAGURE_LENGTH 64 + +int ED25519_verify(const uint8_t *message, size_t message_len, + const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], + const uint8_t public_key[EDDSA_KEY_LENGTH]) +{ + /* Set to any error */ + psa_status_t status = PSA_ERROR_BAD_STATE; + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t kid; + int ret = 0; /* Fail by default */ + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d\n", status); + return 0; + } + + status = PSA_ERROR_BAD_STATE; + + psa_set_key_type(&key_attr, + PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS)); + psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA); + + status = psa_import_key(&key_attr, public_key, EDDSA_KEY_LENGTH, &kid); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("ED25519 key import failed %d", status); + return 0; + } + + status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, message_len, + signature, EDDSA_SIGNAGURE_LENGTH); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("ED25519 signature verification failed %d", status); + ret = 0; + /* Pass through to destroy key */ + } else { + ret = 1; + /* Pass through to destroy key */ + } + + status = psa_destroy_key(kid); + + if (status != PSA_SUCCESS) { + /* Just for logging */ + BOOT_LOG_WRN("Failed to destroy key %d", status); + } + + return ret; +} diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 39e34dbd3..e794fe66c 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -25,6 +25,7 @@ #include "bootutil/crypto/ecdh_p256.h" #endif +#if !defined(MCUBOOT_USE_PSA_CRYPTO) #if defined(MCUBOOT_ENCRYPT_X25519) #include "bootutil/crypto/ecdh_x25519.h" #endif @@ -35,6 +36,7 @@ #include "mbedtls/oid.h" #include "mbedtls/asn1.h" #endif +#endif #include "bootutil/image.h" #include "bootutil/enc_key.h" @@ -43,6 +45,30 @@ #include "bootutil_priv.h" +#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE + +#if defined(MCUBOOT_ENCRYPT_RSA) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 +#elif defined(MCUBOOT_ENCRYPT_KW) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW +#elif defined(MCUBOOT_ENCRYPT_EC256) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 +# define EC_PUBK_INDEX (0) +# define EC_TAG_INDEX (65) +# define EC_CIPHERKEY_INDEX (65 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-P256 component indexes"); +#elif defined(MCUBOOT_ENCRYPT_X25519) +# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 +# define EC_PUBK_INDEX (0) +# define EC_TAG_INDEX (32) +# define EC_CIPHERKEY_INDEX (32 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-X25519 component indexes"); +#endif + +/* NOUP Fixme: */ +#if !defined(CONFIG_BOOT_ED25519_PSA) #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) #if defined(_compare) static inline int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size) @@ -126,12 +152,12 @@ parse_ec256_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) return -5; } - if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || - memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -6; } - if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 || - memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { + if (param.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 || + memcmp(param.ASN1_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { return -7; } @@ -203,8 +229,8 @@ parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) return -4; } - if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || - memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -5; } @@ -336,60 +362,6 @@ hkdf(uint8_t *ikm, uint16_t ikm_len, uint8_t *info, uint16_t info_len, } #endif -int -boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) -{ - bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); - return 0; -} - -int -boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) -{ - bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); - return 0; -} - -int -boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, - const struct boot_status *bs) -{ - int rc; - - rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); - if (rc != 0) { - boot_enc_drop(enc_state, slot); - enc_state[slot].valid = 0; - return -1; - } - - enc_state[slot].valid = 1; - - return 0; -} - -#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE - -#if defined(MCUBOOT_ENCRYPT_RSA) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 -#elif defined(MCUBOOT_ENCRYPT_KW) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW -#elif defined(MCUBOOT_ENCRYPT_EC256) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (65) -# define EC_CIPHERKEY_INDEX (65 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-P256 component indexes"); -#elif defined(MCUBOOT_ENCRYPT_X25519) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (32) -# define EC_CIPHERKEY_INDEX (32 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-X25519 component indexes"); -#endif - #if ( (defined(MCUBOOT_ENCRYPT_RSA) && defined(MCUBOOT_USE_MBED_TLS) && !defined(MCUBOOT_USE_PSA_CRYPTO)) || \ (defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ) #if MBEDTLS_VERSION_NUMBER >= 0x03000000 @@ -415,7 +387,7 @@ static int fake_rng(void *p_rng, unsigned char *output, size_t len) * @param enckey An AES-128 or AES-256 key sized buffer to store to plain key. */ int -boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey) +boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) { #if defined(MCUBOOT_ENCRYPT_RSA) bootutil_rsa_context rsa; @@ -602,12 +574,13 @@ boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey) return rc; } +#endif /* CONFIG_BOOT_ED25519_PSA */ /* * Load encryption key. */ int -boot_enc_load(struct enc_key_data *enc_state, int image_index, +boot_enc_load(struct enc_key_data *enc_state, int slot, const struct image_header *hdr, const struct flash_area *fap, struct boot_status *bs) { @@ -619,15 +592,8 @@ boot_enc_load(struct enc_key_data *enc_state, int image_index, #else uint8_t buf[EXPECTED_ENC_LEN]; #endif - uint8_t slot; int rc; - rc = flash_area_id_to_multi_image_slot(image_index, flash_area_get_id(fap)); - if (rc < 0) { - return rc; - } - slot = rc; - /* Already loaded... */ if (enc_state[slot].valid) { return 1; @@ -660,36 +626,56 @@ boot_enc_load(struct enc_key_data *enc_state, int image_index, return -1; } - return boot_enc_decrypt(buf, bs->enckey[slot]); + return boot_decrypt_key(buf, bs->enckey[slot]); } -bool -boot_enc_valid(struct enc_key_data *enc_state, int image_index, - const struct flash_area *fap) +int +boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) +{ + bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); + return 0; +} + +int +boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) +{ + bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); + enc_state[slot].valid = 0; + return 0; +} + +int +boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, + const struct boot_status *bs) { int rc; - rc = flash_area_id_to_multi_image_slot(image_index, flash_area_get_id(fap)); - if (rc < 0) { - /* can't get proper slot number - skip encryption, */ - /* postpone the error for a upper layer */ - return false; + rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); + if (rc != 0) { + boot_enc_drop(enc_state, slot); + return -1; } - return enc_state[rc].valid; + enc_state[slot].valid = 1; + + return 0; +} + + +bool +boot_enc_valid(struct enc_key_data *enc_state, int slot) +{ + return enc_state[slot].valid; } void -boot_encrypt(struct enc_key_data *enc_state, int image_index, - const struct flash_area *fap, uint32_t off, uint32_t sz, - uint32_t blk_off, uint8_t *buf) +boot_enc_encrypt(struct enc_key_data *enc_state, int slot, uint32_t off, + uint32_t sz, uint32_t blk_off, uint8_t *buf) { - struct enc_key_data *enc; + struct enc_key_data *enc = &enc_state[slot]; uint8_t nonce[16]; - int rc; - /* boot_copy_region will call boot_encrypt with sz = 0 when skipping over - the TLVs. */ + /* Nothing to do with size == 0 */ if (sz == 0) { return; } @@ -701,15 +687,31 @@ boot_encrypt(struct enc_key_data *enc_state, int image_index, nonce[14] = (uint8_t)(off >> 8); nonce[15] = (uint8_t)off; - rc = flash_area_id_to_multi_image_slot(image_index, flash_area_get_id(fap)); - if (rc < 0) { - assert(0); - return; + assert(enc->valid == 1); + bootutil_aes_ctr_encrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf); +} + +void +boot_enc_decrypt(struct enc_key_data *enc_state, int slot, uint32_t off, + uint32_t sz, uint32_t blk_off, uint8_t *buf) +{ + struct enc_key_data *enc = &enc_state[slot]; + uint8_t nonce[16]; + + /* Nothing to do with size == 0 */ + if (sz == 0) { + return; } - enc = &enc_state[rc]; + memset(nonce, 0, 12); + off >>= 4; + nonce[12] = (uint8_t)(off >> 24); + nonce[13] = (uint8_t)(off >> 16); + nonce[14] = (uint8_t)(off >> 8); + nonce[15] = (uint8_t)off; + assert(enc->valid == 1); - bootutil_aes_ctr_encrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf); + bootutil_aes_ctr_decrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf); } /** diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c new file mode 100644 index 000000000..927ce2d6b --- /dev/null +++ b/boot/bootutil/src/encrypted_psa.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "mcuboot_config/mcuboot_config.h" + +#include +#include +#include + +/* We are not really using the MBEDTLS but need the ASN.1 parsing functions */ +#define MBEDTLS_ASN1_PARSE_C + +#include "bootutil/crypto/sha.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1.h" + +#include "bootutil/image.h" +#include "bootutil/enc_key.h" +#include "bootutil/sign_key.h" +#include "bootutil/crypto/common.h" + +#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); + +#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE +#define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 +#define EC_PUBK_INDEX (0) +#define EC_TAG_INDEX (32) +#define EC_CIPHERKEY_INDEX (32 + 32) +_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, + "Please fix ECIES-X25519 component indexes"); + +#define X25519_OID "\x6e" +static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ + MBEDTLS_OID_ORG_GOV X25519_OID; + +#define SHARED_KEY_LEN 32 +#define PRIV_KEY_LEN 32 + +/* Fixme: This duplicates code from encrypted.c and depends on mbedtls */ +static int +parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) +{ + size_t len; + int version; + mbedtls_asn1_buf alg; + mbedtls_asn1_buf param; + + if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE) != 0) { + return -1; + } + + if (*p + len != end) { + return -2; + } + + version = 0; + if (mbedtls_asn1_get_int(p, end, &version) || version != 0) { + return -3; + } + + if (mbedtls_asn1_get_alg(p, end, &alg, ¶m) != 0) { + return -4; + } + + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { + return -5; + } + + if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) { + return -6; + } + + if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) { + return -7; + } + + if (len != PRIV_KEY_LEN) { + return -8; + } + + memcpy(private_key, *p, PRIV_KEY_LEN); + return 0; +} + +void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) +{ + psa_status_t psa_ret = psa_crypto_init(); + + (void)ctx; + + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES init PSA crypto init failed %d", psa_ret); + assert(0); + } +} + +#if defined(MCUBOOT_ENC_IMAGES) +/* + * Decrypt an encryption key TLV. + * + * @param buf An encryption TLV read from flash (build time fixed length) + * @param enckey An AES-128 or AES-256 key sized buffer to store to plain key. + */ +int +boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) +{ + uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; + uint8_t *cp; + uint8_t *cpend; + uint8_t private_key[PRIV_KEY_LEN]; + size_t len; + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_status_t psa_cleanup_ret = PSA_ERROR_BAD_STATE; + psa_key_id_t kid; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_derivation_operation_t key_do = PSA_KEY_DERIVATION_OPERATION_INIT; + psa_algorithm_t key_do_alg; + int rc = -1; + + cp = (uint8_t *)bootutil_enc_key.key; + cpend = cp + *bootutil_enc_key.len; + + /* The psa_cipher_decrypt needs initialization vector of proper length at + * the beginning of the input buffer. + */ + uint8_t iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR) + + BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE]; + + psa_ret = psa_crypto_init(); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES crypto init failed %d", psa_ret); + return -1; + } + + /* + * Load the stored X25519 decryption private key + */ + rc = parse_x25519_enckey(&cp, cpend, private_key); + if (rc) { + return rc; + } + + psa_set_key_type(&kattr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY)); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&kattr, PSA_ALG_ECDH); + + psa_ret = psa_import_key(&kattr, private_key, sizeof(private_key), &kid); + memset(private_key, 0, sizeof(private_key)); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("Built-in key import failed %d", psa_ret); + return -1; + } + + key_do_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + + psa_ret = psa_key_derivation_setup(&key_do, key_do_alg); + if (psa_ret != PSA_SUCCESS) { + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); + } + BOOT_LOG_ERR("Key derivation setup failed %d", psa_ret); + return -1; + } + + /* Note: PSA 1.1.2 does not have psa_key_agreement that would be useful here + * as it could just add the derived key to the storage and return key id. + * Instead, we have to use the code below to generate derived key and put it + * into storage, to obtain the key id we can then use with psa_mac_* functions. + */ + psa_ret = psa_key_derivation_key_agreement(&key_do, PSA_KEY_DERIVATION_INPUT_SECRET, + kid, &buf[EC_PUBK_INDEX], + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); + } + if (psa_ret != PSA_SUCCESS) { + psa_cleanup_ret = psa_key_derivation_abort(&key_do); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret); + } + + BOOT_LOG_ERR("Key derivation failed %d", psa_ret); + return -1; + } + + /* Only info, no salt */ + psa_ret = psa_key_derivation_input_bytes(&key_do, PSA_KEY_DERIVATION_INPUT_INFO, + "MCUBoot_ECIES_v1", 16); + if (psa_ret != PSA_SUCCESS) { + psa_cleanup_ret = psa_key_derivation_abort(&key_do); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret); + } + BOOT_LOG_ERR("Key derivation failed %d", psa_ret); + return -1; + } + + len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; + psa_ret = psa_key_derivation_output_bytes(&key_do, derived_key, len); + psa_cleanup_ret = psa_key_derivation_abort(&key_do); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("Key derivation cleanup failed %d", psa_ret); + } + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("Key derivation failed %d", psa_ret); + return -1; + } + + /* The derived key consists of BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE bytes + * followed by BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. Both parts will + * be imported at the point where needed and discarded immediately after. + */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_HMAC); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_VERIFY_MESSAGE); + psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + /* Import the MAC tag key part of derived key, that is the part that starts + * after BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE and has length of + * BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. + */ + psa_ret = psa_import_key(&kattr, + &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE], + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, &kid); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + memset(derived_key, 0, sizeof(derived_key)); + BOOT_LOG_ERR("MAC key import failed %d", psa_ret); + return -1; + } + + /* Verify the MAC tag of the random encryption key */ + psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_ALG_SHA_256), + &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE, + &buf[EC_TAG_INDEX], + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("MAC key destruction failed %d", psa_cleanup_ret); + } + if (psa_ret != PSA_SUCCESS) { + memset(derived_key, 0, sizeof(derived_key)); + BOOT_LOG_ERR("MAC verification failed %d", psa_ret); + return -1; + } + + /* The derived key is used in AES decryption of random key */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + /* Import the AES partition of derived key, the first 16 bytes */ + psa_ret = psa_import_key(&kattr, &derived_key[0], + BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &kid); + memset(derived_key, 0, sizeof(derived_key)); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES key import failed %d", psa_ret); + return -1; + } + + /* Decrypt the random AES encryption key with AES and the key obtained + * at derivation. */ + memset(&iv_and_key[0], 0, PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)); + memcpy(&iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)], + &buf[EC_CIPHERKEY_INDEX], + sizeof(iv_and_key) - PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)); + + len = 0; + psa_ret = psa_cipher_decrypt(kid, PSA_ALG_CTR, iv_and_key, sizeof(iv_and_key), + enckey, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &len); + memset(iv_and_key, 0, sizeof(iv_and_key)); + psa_cleanup_ret = psa_destroy_key(kid); + if (psa_cleanup_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("AES key destruction failed %d", psa_cleanup_ret); + } + if (psa_ret != PSA_SUCCESS || len != BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE) { + memset(enckey, 0, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE); + BOOT_LOG_ERR("Random key decryption failed %d", psa_ret); + return -1; + } + + return 0; +} + +int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c) +{ + int ret = 0; + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t kid; + psa_cipher_operation_t psa_op; + size_t elen = 0; /* Decrypted length */ + + /* Fixme: calling psa_crypto_init multiple times is not a problem, + * yet the code here is only present because there is not general + * crypto init. */ + psa_ret = psa_crypto_init(); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); + ret = -1; + goto gone; + } + + psa_op = psa_cipher_operation_init(); + + /* Fixme: Import should happen when key is decrypted, but due to lack + * of key destruction there is no way to destroy key stored by + * psa other way than here. */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc import key failed %d", psa_ret); + ret = -1; + goto gone; + } + + /* This could be done with psa_cipher_decrypt one-shot operation, but + * multi-part operation is used to avoid re-allocating input buffer + * to account for IV in front of data. + */ + psa_ret = psa_cipher_encrypt_setup(&psa_op, kid, PSA_ALG_CTR); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc setup failed %d", psa_ret); + ret = -1; + goto gone_with_key; + } + + /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ + psa_ret = psa_cipher_set_iv(&psa_op, counter, 16); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc IV set failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + + psa_ret = psa_cipher_update(&psa_op, m, mlen, c, mlen, &elen); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES enc encryption failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + +gone_after_setup: + psa_ret = psa_cipher_abort(&psa_op); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("AES enc cipher abort failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone_with_key: + /* Fixme: Should be removed once key is shared by id */ + psa_ret = psa_destroy_key(kid); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("AES enc destroy key failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone: + return ret; +} + +int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m) +{ + int ret = 0; + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t kid; + psa_cipher_operation_t psa_op; + size_t dlen = 0; /* Decrypted length */ + + /* Fixme: the init should already happen before calling the function, but + * somehow it does not, for example when recovering in swap. + */ + psa_ret = psa_crypto_init(); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); + ret = -1; + goto gone; + } + + psa_op = psa_cipher_operation_init(); + + /* Fixme: Import should happen when key is decrypted, but due to lack + * of key destruction there is no way to destroy key stored by + * psa other way than here. */ + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); + psa_reset_key_attributes(&kattr); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec import key failed %d", psa_ret); + ret = -1; + goto gone; + } + + /* This could be done with psa_cipher_decrypt one-shot operation, but + * multi-part operation is used to avoid re-allocating input buffer + * to account for IV in front of data. + */ + psa_ret = psa_cipher_decrypt_setup(&psa_op, kid, PSA_ALG_CTR); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec setup failed %d", psa_ret); + ret = -1; + goto gone_with_key; + } + + /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ + psa_ret = psa_cipher_set_iv(&psa_op, counter, 16); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec IV set failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + + psa_ret = psa_cipher_update(&psa_op, c, clen, m, clen, &dlen); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("AES dec decryption failed %d", psa_ret); + ret = -1; + goto gone_after_setup; + } + +gone_after_setup: + psa_ret = psa_cipher_abort(&psa_op); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("PSA dec abort failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone_with_key: + psa_ret = psa_destroy_key(kid); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("PSA dec key failed %d", psa_ret); + /* Intentionally not changing the ret */ + } +gone: + return ret; +} +#endif /* defined(MCUBOOT_ENC_IMAGES) */ diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index c51fea494..c3e8410f1 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -9,6 +9,11 @@ #include "mcuboot_config/mcuboot_config.h" +#if defined(CONFIG_NRF_SECURITY) +/* We are not really using the MBEDTLS but need the ASN.1 parsing funcitons */ +#define MBEDTLS_ASN1_PARSE_C +#endif + #ifdef MCUBOOT_SIGN_ED25519 #include "bootutil/sign_key.h" @@ -18,12 +23,16 @@ #include "bootutil_priv.h" #include "bootutil/crypto/common.h" +#define SHA512_LEN 64 +#define SHA256_LEN 32 +#define EDDSA_SIGNAGURE_LENGTH 64 + static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; #define NUM_ED25519_BYTES 32 extern int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[64], - const uint8_t public_key[32]); + const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], + const uint8_t public_key[NUM_ED25519_BYTES]); /* * Parse the public key used for signing. @@ -45,8 +54,8 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return -2; } - if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ed25519_pubkey_oid) - 1 || - memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) { + if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ed25519_pubkey_oid) - 1 || + memcmp(alg.ASN1_CONTEXT_MEMBER(p), ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) { return -3; } @@ -73,7 +82,8 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t *pubkey; uint8_t *end; - if (hlen != 32 || slen != 64) { + if (!(hlen == SHA512_LEN || hlen == SHA256_LEN) || + slen != EDDSA_SIGNAGURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -87,7 +97,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, goto out; } - rc = ED25519_verify(hash, 32, sig, pubkey); + rc = ED25519_verify(hash, hlen, sig, pubkey); if (rc == 0) { /* if verify returns 0, there was an error. */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 5043d385a..a6155f7b0 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -105,7 +105,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, #ifdef MCUBOOT_ENC_IMAGES /* Encrypted images only exist in the secondary slot */ if (MUST_DECRYPT(fap, image_index, hdr) && - !boot_enc_valid(enc_state, image_index, fap)) { + !boot_enc_valid(enc_state, 1)) { return -1; } #endif @@ -157,10 +157,13 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, #ifdef MCUBOOT_ENC_IMAGES if (MUST_DECRYPT(fap, image_index, hdr)) { /* Only payload is encrypted (area between header and TLVs) */ + int slot = flash_area_id_to_multi_image_slot(image_index, + flash_area_get_id(fap)); + if (off >= hdr_size && off < tlv_off) { blk_off = (off - hdr_size) & 0xf; - boot_encrypt(enc_state, image_index, fap, off - hdr_size, - blk_sz, blk_off, tmp_buf); + boot_enc_decrypt(enc_state, slot, off - hdr_size, + blk_sz, blk_off, tmp_buf); } } #endif diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index d35b6910c..9f2843a0d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -854,7 +854,6 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, const struct flash_area *fap, struct boot_status *bs) { TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ]; - uint8_t image_index; int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); @@ -865,13 +864,11 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, (void)bs; (void)rc; - image_index = BOOT_CURR_IMG(state); - /* In the case of ram loading the image has already been decrypted as it is * decrypted when copied in ram */ #if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD) - if (MUST_DECRYPT(fap, image_index, hdr)) { - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs); + if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) { + rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fap, bs); if (rc < 0) { FIH_RET(fih_rc); } @@ -881,8 +878,9 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, } #endif - FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index, - hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL); + FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), + BOOT_CURR_IMG(state), hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, + NULL, 0, NULL); FIH_RET(fih_rc); } @@ -1573,13 +1571,26 @@ boot_copy_region(struct boot_loader_state *state, int chunk_sz; int rc; #ifdef MCUBOOT_ENC_IMAGES - uint32_t off; + uint32_t off = off_dst; uint32_t tlv_off; size_t blk_off; struct image_header *hdr; uint16_t idx; uint32_t blk_sz; - uint8_t image_index; + uint8_t image_index = BOOT_CURR_IMG(state); + bool encrypted_src; + bool encrypted_dst; + /* Assuming the secondary slot is source; note that 0 here not only + * means that primary slot is source, but also that there will be + * encryption happening, if it is 1 then there is decryption from + * secondary slot. + */ + int source_slot = 1; + /* In case of encryption enabled, we may have to do more work than + * just copy bytes */ + bool only_copy = false; +#else + (void)state; #endif #ifdef MCUBOOT_DECOMPRESS_IMAGES struct image_header *hdr; @@ -1587,8 +1598,26 @@ boot_copy_region(struct boot_loader_state *state, TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4))); -#if !defined(MCUBOOT_ENC_IMAGES) - (void)state; +#ifdef MCUBOOT_ENC_IMAGES + encrypted_src = (flash_area_get_id(fap_src) != FLASH_AREA_IMAGE_PRIMARY(image_index)); + encrypted_dst = (flash_area_get_id(fap_dst) != FLASH_AREA_IMAGE_PRIMARY(image_index)); + + if (encrypted_src != encrypted_dst) { + if (encrypted_dst) { + /* Need encryption, metadata from the primary slot */ + hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT); + source_slot = 0; + } else { + /* Need decryption, metadata from the secondary slot */ + hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); + source_slot = 1; + } + } else { + /* In case when source and targe is the same area, this means that we + * only have to copy bytes, no encryption or decryption. + */ + only_copy = true; + } #endif #ifdef MCUBOOT_DECOMPRESS_IMAGES @@ -1615,57 +1644,44 @@ boot_copy_region(struct boot_loader_state *state, } #ifdef MCUBOOT_ENC_IMAGES - image_index = BOOT_CURR_IMG(state); - if ((flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) || - flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)) && - !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) && - flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index))) { - /* assume the secondary slot as src, needs decryption */ - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); -#if !defined(MCUBOOT_SWAP_USING_MOVE) - off = off_src; - if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)) { - /* might need encryption (metadata from the primary slot) */ - hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT); - off = off_dst; - } -#else - off = off_dst; - if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)) { - hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT); - } -#endif - if (IS_ENCRYPTED(hdr)) { - uint32_t abs_off = off + bytes_copied; - if (abs_off < hdr->ih_hdr_size) { - /* do not decrypt header */ - if (abs_off + chunk_sz > hdr->ih_hdr_size) { - /* The lower part of the chunk contains header data */ - blk_off = 0; - blk_sz = chunk_sz - (hdr->ih_hdr_size - abs_off); - idx = hdr->ih_hdr_size - abs_off; - } else { - /* The chunk contains exclusively header data */ - blk_sz = 0; /* nothing to decrypt */ - } + /* If only copy, then does not matter if header indicates need for + * encryptio/decryptio, we just copy data. */ + if (!only_copy && IS_ENCRYPTED(hdr)) { + uint32_t abs_off = off + bytes_copied; + if (abs_off < hdr->ih_hdr_size) { + /* do not decrypt header */ + if (abs_off + chunk_sz > hdr->ih_hdr_size) { + /* The lower part of the chunk contains header data */ + blk_off = 0; + blk_sz = chunk_sz - (hdr->ih_hdr_size - abs_off); + idx = hdr->ih_hdr_size - abs_off; } else { - idx = 0; - blk_sz = chunk_sz; - blk_off = (abs_off - hdr->ih_hdr_size) & 0xf; + /* The chunk contains exclusively header data */ + blk_sz = 0; /* nothing to decrypt */ } + } else { + idx = 0; + blk_sz = chunk_sz; + blk_off = (abs_off - hdr->ih_hdr_size) & 0xf; + } - if (blk_sz > 0) - { - tlv_off = BOOT_TLV_OFF(hdr); - if (abs_off + chunk_sz > tlv_off) { - /* do not decrypt TLVs */ - if (abs_off >= tlv_off) { - blk_sz = 0; - } else { - blk_sz = tlv_off - abs_off; - } + if (blk_sz > 0) + { + tlv_off = BOOT_TLV_OFF(hdr); + if (abs_off + chunk_sz > tlv_off) { + /* do not decrypt TLVs */ + if (abs_off >= tlv_off) { + blk_sz = 0; + } else { + blk_sz = tlv_off - abs_off; } - boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src, + } + if (source_slot == 0) { + boot_enc_encrypt(BOOT_CURR_ENC(state), source_slot, + (abs_off + idx) - hdr->ih_hdr_size, blk_sz, + blk_off, &buf[idx]); + } else { + boot_enc_decrypt(BOOT_CURR_ENC(state), source_slot, (abs_off + idx) - hdr->ih_hdr_size, blk_sz, blk_off, &buf[idx]); } @@ -1774,7 +1790,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) { - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, + rc = boot_enc_load(BOOT_CURR_ENC(state), BOOT_SECONDARY_SLOT, boot_img_hdr(state, BOOT_SECONDARY_SLOT), fap_secondary_slot, bs); @@ -1898,7 +1914,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES if (IS_ENCRYPTED(hdr)) { fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT); - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs); + rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fap, bs); assert(rc >= 0); if (rc == 0) { @@ -1922,7 +1938,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); if (IS_ENCRYPTED(hdr)) { fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs); + rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fap, bs); assert(rc >= 0); if (rc == 0) { @@ -3128,13 +3144,11 @@ boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, uint32_t chunk_sz; uint32_t max_sz = 1024; uint16_t idx; - uint8_t image_index; uint8_t * cur_dst; int area_id; int rc; uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst); - image_index = BOOT_CURR_IMG(state); area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); rc = flash_area_open(area_id, &fap_src); if (rc != 0){ @@ -3149,7 +3163,7 @@ boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, goto done; } - rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap_src, &bs); + rc = boot_enc_load(BOOT_CURR_ENC(state), slot, hdr, fap_src, &bs); if (rc < 0) { goto done; } @@ -3170,22 +3184,15 @@ boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, cur_dst = ram_dst + bytes_copied; blk_sz = chunk_sz; idx = 0; + blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf; if (bytes_copied + chunk_sz > tlv_off) { /* Going over TLV section * Part of the chunk is encrypted payload */ - blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf; blk_sz = tlv_off - (bytes_copied); - boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src, + } + boot_enc_decrypt(BOOT_CURR_ENC(state), slot, (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, blk_off, cur_dst); - } else { - /* Image encrypted payload section */ - blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf; - boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src, - (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, - blk_off, cur_dst); - } - bytes_copied += chunk_sz; } rc = 0; diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 5e6723bb6..4dce64425 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -86,7 +86,7 @@ boot_read_image_header(struct boot_loader_state *state, int slot, off = 0; if (bs && !boot_status_is_reset(bs)) { - boot_find_status(BOOT_CURR_IMG(state), &fap); + boot_find_status(BOOT_CURR_IMG(state), &fap); if (fap == NULL || boot_read_swap_size(fap, &swap_size)) { rc = BOOT_EFLASH; goto done; diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index 72a6a8638..d5364d025 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -29,12 +29,18 @@ zephyr_library_link_libraries(MCUBOOT_BOOTUTIL) target_link_libraries(MCUBOOT_BOOTUTIL INTERFACE zephyr_interface) if(CONFIG_BOOT_USE_TINYCRYPT) -target_include_directories(MCUBOOT_BOOTUTIL INTERFACE - ../../../ext/tinycrypt/lib/include -) + target_include_directories(MCUBOOT_BOOTUTIL INTERFACE + ../../../ext/tinycrypt/lib/include + ) +endif() + +if(CONFIG_BOOT_USE_PSA_CRYPTO) + target_include_directories(MCUBOOT_BOOTUTIL INTERFACE + ${ZEPHYR_MBEDTLS_MODULE_DIR}/include + ) endif() -if(CONFIG_BOOT_USE_MBEDTLS) +if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO AND NOT CONFIG_PSA_CORE_OBERON) zephyr_link_libraries(mbedTLS) endif() endif() diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index c26633d11..8a2c97ead 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -51,6 +51,12 @@ if(EXISTS targets/${BOARD}.h) zephyr_library_compile_definitions(MCUBOOT_TARGET_CONFIG="${BOARD}.h") endif() +if(DEFINED CONFIG_MBEDTLS) + zephyr_library_include_directories( + ${ZEPHYR_MBEDTLS_MODULE_DIR}/include + ) +endif() + # Zephyr port-specific sources. zephyr_library_sources( main.c @@ -102,6 +108,10 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) +if(DEFINED CONFIG_BOOT_ENCRYPT_X25519) + zephyr_library_sources(${BOOT_DIR}/bootutil/src/encrypted_psa.c) +endif() + if(DEFINED CONFIG_MEASURED_BOOT OR DEFINED CONFIG_BOOT_SHARE_DATA) zephyr_library_sources( ${BOOT_DIR}/bootutil/src/boot_record.c @@ -230,19 +240,28 @@ elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519 OR CONFIG_BOOT_ENCRYPT_X25519) ${FIAT_DIR}/include/ ) - zephyr_library_sources( - ${FIAT_DIR}/src/curve25519.c - ) + if(NOT CONFIG_BOOT_ED25519_PSA) + zephyr_library_sources( + ${FIAT_DIR}/src/curve25519.c + ) + else() + zephyr_library_sources( + ${MBEDTLS_ASN1_DIR}/src/asn1parse.c + ${BOOT_DIR}/bootutil/src/ed25519_psa.c + ) + endif() endif() -if(CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) - zephyr_library_sources( - ${TINYCRYPT_DIR}/source/aes_encrypt.c - ${TINYCRYPT_DIR}/source/aes_decrypt.c - ${TINYCRYPT_DIR}/source/ctr_mode.c - ${TINYCRYPT_DIR}/source/hmac.c - ${TINYCRYPT_DIR}/source/ecc_dh.c +if(NOT CONFIG_BOOT_ED25519_PSA) + if(CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) + zephyr_library_sources( + ${TINYCRYPT_DIR}/source/aes_encrypt.c + ${TINYCRYPT_DIR}/source/aes_decrypt.c + ${TINYCRYPT_DIR}/source/ctr_mode.c + ${TINYCRYPT_DIR}/source/hmac.c + ${TINYCRYPT_DIR}/source/ecc_dh.c ) + endif() endif() if(CONFIG_BOOT_ENCRYPT_EC256) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 8b35ab18c..264c08241 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -29,7 +29,9 @@ config BOOT_USE_MBEDTLS config BOOT_USE_PSA_CRYPTO bool - # Hidden option + default y if NRF_SECURITY + # This is counter intuitive but that is how PSA heap is enabled. + select MBEDTLS_ENABLE_HEAP help Hidden option set if using PSA crypt for cryptography functionality @@ -66,6 +68,58 @@ config NRF_CC310_BL bool default n +if BOOT_USE_PSA_CRYPTO + +config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES + bool + default y if BOOT_IMG_HASH_ALG_SHA256 + select PSA_WANT_ALG_SHA_256 + help + Dependencies for hashing with SHA256 + +config BOOT_ED25519_PSA_DEPENDENCIES + bool + select PSA_WANT_ALG_SHA_256 + select PSA_WANT_ALG_SHA_512 + select PSA_WANT_ALG_PURE_EDDSA + select PSA_WANT_ECC_TWISTED_EDWARDS_255 + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + help + Dependencies for ed25519 signature + +if BOOT_ENCRYPT_IMAGE + +config BOOT_X25519_PSA_DEPENDENCIES + bool + select PSA_WANT_ALG_ECDH + select PSA_WANT_ALG_HMAC + select PSA_WANT_ALG_HKDF + select PSA_WANT_ALG_CTR + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + select PSA_WANT_KEY_TYPE_DERIVE + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_ECC_MONTGOMERY_255 + help + Dependencies for x25519 shared-random key encryption and AES + encryption. The PSA_WANT_ALG_CTR and PSA_WANT_KEY_TYPE_AES + enable Counter based block cipher and AES key, and algorithm support, + to use with it; the others are used for shared key decryption + and derivation. + +endif # BOOT_ENCRYPT_IMAGE + +if MBEDTLS_ENABLE_HEAP + +config MBEDTLS_HEAP_SIZE + default 2048 if BOOT_USE_PSA_CRYPTO + help + The PSA internals need to be able to allocate memory for operation + and it uses mbedTLS heap for that. + +endif # MBEDTLS_ENABLE_HEAP + +endif # BOOT_USE_PSA_CRYPTO + menu "MCUBoot settings" config SINGLE_APPLICATION_SLOT @@ -124,6 +178,7 @@ endchoice # BOOT_IMG_HASH_ALG choice BOOT_SIGNATURE_TYPE prompt "Signature type" + default BOOT_SIGNATURE_TYPE_ED25519 if BOARD_NRF54L15PDK_NRF54L15_CPUAPP default BOOT_SIGNATURE_TYPE_RSA config BOOT_SIGNATURE_TYPE_NONE @@ -178,13 +233,24 @@ if BOOT_SIGNATURE_TYPE_ED25519 choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" default BOOT_ED25519_TINYCRYPT + config BOOT_ED25519_TINYCRYPT bool "Use tinycrypt" select BOOT_USE_TINYCRYPT + depends on !NRF_SECURITY + config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS select MBEDTLS + depends on !NRF_SECURITY + +config BOOT_ED25519_PSA + bool "Use PSA crypto" + select BOOT_USE_PSA_CRYPTO + select BOOT_ED25519_PSA_DEPENDENCIES + select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE + endchoice endif @@ -223,9 +289,13 @@ config MCUBOOT_CLEANUP_ARM_CORE start-up code which can cause a module fault and potentially make the module irrecoverable. +if MBEDTLS + config MBEDTLS_CFG_FILE default "mcuboot-mbedtls-cfg.h" +endif + config BOOT_HW_KEY bool "Use HW key for image verification" default n diff --git a/boot/zephyr/include/mcuboot-mbedtls-cfg.h b/boot/zephyr/include/mcuboot-mbedtls-cfg.h index 2bab537d7..a46fbb09f 100644 --- a/boot/zephyr/include/mcuboot-mbedtls-cfg.h +++ b/boot/zephyr/include/mcuboot-mbedtls-cfg.h @@ -23,7 +23,7 @@ #if defined(CONFIG_BOOT_SIGNATURE_TYPE_RSA) || defined(CONFIG_BOOT_ENCRYPT_RSA) #include "config-rsa.h" -#elif defined(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) || \ +#elif defined(CONFIG_BOOT_USE_PSA_CRYPTO) || defined(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) || \ defined(CONFIG_BOOT_ENCRYPT_EC256) || \ (defined(CONFIG_BOOT_ENCRYPT_X25519) && !defined(CONFIG_BOOT_SIGNATURE_TYPE_ED25519)) #include "config-asn1.h"