/* Run the boot image. */ #include #include #include #include #include #include #include #include #include "../../../boot/bootutil/src/bootutil_priv.h" #include "bootsim.h" #ifdef MCUBOOT_ENCRYPT_RSA #include "mbedtls/rsa.h" #include "mbedtls/asn1.h" #endif #ifdef MCUBOOT_ENCRYPT_KW #include "mbedtls/nist_kw.h" #endif #define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR #include #include "bootutil/crypto/common.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) struct area_desc; extern struct area_desc *sim_get_flash_areas(void); extern void sim_set_flash_areas(struct area_desc *areas); extern void sim_reset_flash_areas(void); struct sim_context; extern struct sim_context *sim_get_context(void); extern void sim_set_context(struct sim_context *ctx); extern void sim_reset_context(void); extern int sim_flash_erase(uint8_t flash_id, uint32_t offset, uint32_t size); extern int sim_flash_read(uint8_t flash_id, uint32_t offset, uint8_t *dest, uint32_t size); extern int sim_flash_write(uint8_t flash_id, uint32_t offset, const uint8_t *src, uint32_t size); extern uint32_t sim_flash_align(uint8_t flash_id); extern uint8_t sim_flash_erased_val(uint8_t flash_id); struct sim_context { int flash_counter; int jumped; uint8_t c_asserts; uint8_t c_catch_asserts; jmp_buf boot_jmpbuf; }; #ifdef MCUBOOT_ENCRYPT_RSA static int parse_pubkey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end) { int rc; size_t len; if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { return -1; } if (*p + len != end) { return -2; } if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { return -3; } *p += len; if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_BIT_STRING)) != 0) { return -4; } if (**p != MBEDTLS_ASN1_PRIMITIVE) { return -5; } *p += 1; if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { return -6; } if (mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0) { return -7; } if (mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0) { return -8; } ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N)); if (*p != end) { return -9; } if (mbedtls_rsa_check_pubkey(ctx) != 0) { return -10; } return 0; } static int fake_rng(void *p_rng, unsigned char *output, size_t len) { size_t i; (void)p_rng; for (i = 0; i < len; i++) { output[i] = (char)i; } return 0; } #endif int mbedtls_platform_set_calloc_free(void * (*calloc_func)(size_t, size_t), void (*free_func)(void *)); int rsa_oaep_encrypt_(const uint8_t *pubkey, unsigned pubkey_len, const uint8_t *seckey, unsigned seckey_len, uint8_t *encbuf) { #ifdef MCUBOOT_ENCRYPT_RSA mbedtls_rsa_context ctx; uint8_t *cp; uint8_t *cpend; int rc; mbedtls_platform_set_calloc_free(calloc, free); #if MBEDTLS_VERSION_NUMBER >= 0x03000000 mbedtls_rsa_init(&ctx); mbedtls_rsa_set_padding(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); #else mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); #endif cp = (uint8_t *)pubkey; cpend = cp + pubkey_len; rc = parse_pubkey(&ctx, &cp, cpend); if (rc) { goto done; } #if MBEDTLS_VERSION_NUMBER >= 0x03000000 rc = mbedtls_rsa_rsaes_oaep_encrypt(&ctx, fake_rng, NULL, NULL, 0, seckey_len, seckey, encbuf); #else rc = mbedtls_rsa_rsaes_oaep_encrypt(&ctx, fake_rng, NULL, MBEDTLS_RSA_PUBLIC, NULL, 0, seckey_len, seckey, encbuf); #endif if (rc) { goto done; } done: mbedtls_rsa_free(&ctx); return rc; #else (void)pubkey; (void)pubkey_len; (void)seckey; (void)seckey_len; (void)encbuf; return 0; #endif } int kw_encrypt_(const uint8_t *kek, const uint8_t *seckey, uint8_t *encbuf) { #ifdef MCUBOOT_ENCRYPT_KW #ifdef MCUBOOT_AES_256 int key_len = 256; int out_size = 40; int in_len = 32; #else int key_len = 128; int out_size = 24; int in_len = 16; #endif mbedtls_nist_kw_context kw; size_t olen; int rc; mbedtls_platform_set_calloc_free(calloc, free); mbedtls_nist_kw_init(&kw); rc = mbedtls_nist_kw_setkey(&kw, MBEDTLS_CIPHER_ID_AES, kek, key_len, 1); if (rc) { goto done; } rc = mbedtls_nist_kw_wrap(&kw, MBEDTLS_KW_MODE_KW, seckey, in_len, encbuf, &olen, out_size); done: mbedtls_nist_kw_free(&kw); return rc; #else (void)kek; (void)seckey; (void)encbuf; return 0; #endif } uint32_t flash_area_align(const struct flash_area *area) { return sim_flash_align(area->fa_device_id); } uint8_t flash_area_erased_val(const struct flash_area *area) { return sim_flash_erased_val(area->fa_device_id); } struct area { struct flash_area whole; struct flash_area *areas; uint32_t num_areas; uint8_t id; }; struct area_desc { struct area slots[16]; uint32_t num_slots; }; int invoke_boot_go(struct sim_context *ctx, struct area_desc *adesc, struct boot_rsp *rsp, int image_id) { int res; struct boot_loader_state *state; #if defined(MCUBOOT_SIGN_RSA) || \ (defined(MCUBOOT_SIGN_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ||\ (defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ||\ (defined(MCUBOOT_ENCRYPT_X25519) && defined(MCUBOOT_USE_MBED_TLS)) mbedtls_platform_set_calloc_free(calloc, free); #endif state = malloc(sizeof(struct boot_loader_state)); sim_set_flash_areas(adesc); sim_set_context(ctx); if (setjmp(ctx->boot_jmpbuf) == 0) { boot_state_clear(state); #if BOOT_IMAGE_NUMBER > 1 if (image_id >= 0) { memset(state->img_mask, 1, sizeof(state->img_mask)); state->img_mask[image_id] = 0; } #else (void) image_id; #endif /* BOOT_IMAGE_NUMBER > 1 */ res = context_boot_go(state, rsp); sim_reset_flash_areas(); sim_reset_context(); free(state); /* printf("boot_go off: %d (0x%08x)\n", res, rsp.br_image_off); */ return res; } else { sim_reset_flash_areas(); sim_reset_context(); free(state); return -0x13579; } } void *os_malloc(size_t size) { // printf("os_malloc 0x%x bytes\n", size); return malloc(size); } int flash_area_id_from_multi_image_slot(int image_index, int slot) { switch (slot) { case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index); case 1: return FLASH_AREA_IMAGE_SECONDARY(image_index); case 2: return FLASH_AREA_IMAGE_SCRATCH; } printf("Image flash area ID not found\n"); return -1; /* flash_area_open will fail on that */ } int flash_area_open(uint8_t id, const struct flash_area **area) { uint32_t i; struct area_desc *flash_areas; flash_areas = sim_get_flash_areas(); for (i = 0; i < flash_areas->num_slots; i++) { if (flash_areas->slots[i].id == id) break; } if (i == flash_areas->num_slots) { printf("Unsupported area\n"); abort(); } /* Unsure if this is right, just returning the first area. */ *area = &flash_areas->slots[i].whole; return 0; } void flash_area_close(const struct flash_area *area) { (void)area; } /* * Read/write/erase. Offset is relative from beginning of flash area. */ int flash_area_read(const struct flash_area *area, uint32_t off, void *dst, uint32_t len) { BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__, area->fa_id, off, len); return sim_flash_read(area->fa_device_id, area->fa_off + off, dst, len); } int flash_area_write(const struct flash_area *area, uint32_t off, const void *src, uint32_t len) { BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__, area->fa_id, off, len); struct sim_context *ctx = sim_get_context(); if (--(ctx->flash_counter) == 0) { ctx->jumped++; longjmp(ctx->boot_jmpbuf, 1); } return sim_flash_write(area->fa_device_id, area->fa_off + off, src, len); } int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len) { BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__, area->fa_id, off, len); struct sim_context *ctx = sim_get_context(); if (--(ctx->flash_counter) == 0) { ctx->jumped++; longjmp(ctx->boot_jmpbuf, 1); } return sim_flash_erase(area->fa_device_id, area->fa_off + off, len); } int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret) { uint32_t i; struct area *slot; struct area_desc *flash_areas; flash_areas = sim_get_flash_areas(); for (i = 0; i < flash_areas->num_slots; i++) { if (flash_areas->slots[i].id == idx) break; } if (i == flash_areas->num_slots) { printf("Unsupported area\n"); abort(); } slot = &flash_areas->slots[i]; if (slot->num_areas > (uint32_t)*cnt) { printf("Too many areas in slot\n"); abort(); } *cnt = slot->num_areas; memcpy(ret, slot->areas, slot->num_areas * sizeof(struct flash_area)); return 0; } int flash_area_get_sectors(int fa_id, uint32_t *count, struct flash_sector *sectors) { uint32_t i; struct area *slot; struct area_desc *flash_areas; flash_areas = sim_get_flash_areas(); for (i = 0; i < flash_areas->num_slots; i++) { if (flash_areas->slots[i].id == fa_id) break; } if (i == flash_areas->num_slots) { printf("Unsupported area\n"); abort(); } slot = &flash_areas->slots[i]; if (slot->num_areas > *count) { printf("Too many areas in slot\n"); abort(); } for (i = 0; i < slot->num_areas; i++) { sectors[i].fs_off = slot->areas[i].fa_off - slot->whole.fa_off; sectors[i].fs_size = slot->areas[i].fa_size; } *count = slot->num_areas; return 0; } int flash_area_id_to_multi_image_slot(int image_index, int area_id) { if (area_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) { return 0; } if (area_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) { return 1; } printf("Unsupported image area ID\n"); abort(); } int flash_area_id_from_image_slot(int slot) { /* For single image cases, just use the first image. */ return flash_area_id_from_multi_image_slot(0, slot); } int flash_area_sector_from_off(uint32_t off, struct flash_sector *sector) { uint32_t i, sec_off, sec_size; struct area *slot; struct area_desc *flash_areas; flash_areas = sim_get_flash_areas(); for (i = 0; i < flash_areas->num_slots; i++) { if (flash_areas->slots[i].id == FLASH_AREA_ID(image_0)) break; } if (i == flash_areas->num_slots) { printf("Unsupported area\n"); abort(); } slot = &flash_areas->slots[i]; for (i = 0; i < slot->num_areas; i++) { sec_off = slot->areas[i].fa_off - slot->whole.fa_off; sec_size = slot->areas[i].fa_size; if (off >= sec_off && off < (sec_off + sec_size)) { sector->fs_off = sec_off; sector->fs_size = sec_size; break; } } return (i < slot->num_areas) ? 0 : -1; } int flash_area_get_sector(const struct flash_area *fa, uint32_t off, struct flash_sector *sector) { uint32_t i, sec_off, sec_size; struct area *slot; struct area_desc *flash_areas; flash_areas = sim_get_flash_areas(); for (i = 0; i < flash_areas->num_slots; i++) { if (&flash_areas->slots[i].whole == fa) break; } if (i == flash_areas->num_slots) { printf("Unsupported area\n"); abort(); } slot = &flash_areas->slots[i]; for (i = 0; i < slot->num_areas; i++) { sec_off = slot->areas[i].fa_off - slot->whole.fa_off; sec_size = slot->areas[i].fa_size; if (off >= sec_off && off < (sec_off + sec_size)) { sector->fs_off = sec_off; sector->fs_size = sec_size; break; } } return (i < slot->num_areas) ? 0 : -1; } void sim_assert(int x, const char *assertion, const char *file, unsigned int line, const char *function) { if (!(x)) { struct sim_context *ctx = sim_get_context(); if (ctx->c_catch_asserts) { ctx->c_asserts++; } else { BOOT_LOG_ERR("%s:%d: %s: Assertion `%s' failed.", file, line, function, assertion); /* NOTE: if the assert below is triggered, the place where it was originally * asserted is printed by the message above... */ assert(x); } } } uint32_t boot_max_align(void) { return BOOT_MAX_ALIGN; } uint32_t boot_magic_sz(void) { return BOOT_MAGIC_ALIGN_SIZE; }