trusted-firmware-m/bl1/bl1_2/main.c

213 lines
6.5 KiB
C

/*
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "crypto.h"
#include "otp.h"
#include "boot_hal.h"
#include "uart_stdout.h"
#include "fih.h"
#include "util.h"
#include "log.h"
#include "image.h"
#include "region_defs.h"
extern uint32_t platform_code_is_bl1_2;
static fih_int image_hash_check(struct bl1_2_image_t *img)
{
uint8_t computed_bl2_hash[BL2_HASH_SIZE];
uint8_t stored_bl2_hash[BL2_HASH_SIZE];
fih_int fih_rc = FIH_FAILURE;
FIH_CALL(bl1_sha256_compute, fih_rc, (uint8_t *)&img->protected_values,
sizeof(img->protected_values),
computed_bl2_hash);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_RET(fih_rc);
}
FIH_CALL(bl1_otp_read_bl2_image_hash, fih_rc, stored_bl2_hash);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_RET(fih_rc);
}
FIH_CALL(bl_secure_memeql, fih_rc, computed_bl2_hash, stored_bl2_hash,
BL2_HASH_SIZE);
FIH_RET(fih_rc);
}
static fih_int is_image_security_counter_valid(struct bl1_2_image_t *img)
{
uint32_t security_counter;
fih_int fih_rc;
FIH_CALL(bl1_otp_read_nv_counter, fih_rc, BL1_NV_COUNTER_ID_BL2_IMAGE,
&security_counter);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_RET(FIH_FAILURE);
}
/* Encodes 0 to true and 1 to false, so the actual comparison is flipped */
FIH_RET(
fih_int_encode_zero_equality(security_counter
> img->protected_values.security_counter));
}
static fih_int is_image_signature_valid(struct bl1_2_image_t *img)
{
fih_int fih_rc = FIH_FAILURE;
#ifdef TFM_BL1_PQ_CRYPTO
/* TODO */
#else
FIH_CALL(image_hash_check, fih_rc, img);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_RET(FIH_FAILURE);
}
#endif /* TFM_BL1_PQ_CRYPTO */
FIH_RET(fih_rc);
}
fih_int validate_image_at_addr(struct bl1_2_image_t *image)
{
fih_int fih_rc = FIH_FAILURE;
FIH_CALL(is_image_signature_valid, fih_rc, image);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BL1_LOG("[ERR] BL2 image signature failed to validate\r\n");
FIH_RET(FIH_FAILURE);
}
FIH_CALL(is_image_security_counter_valid, fih_rc, image);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BL1_LOG("[ERR] BL2 image security_counter failed to validate\r\n");
FIH_RET(FIH_FAILURE);
}
/* TODO work out if the image actually boots before updating the counter */
FIH_CALL(bl1_otp_write_nv_counter, fih_rc, BL1_NV_COUNTER_ID_BL2_IMAGE,
image->protected_values.security_counter);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BL1_LOG("[ERR] NV counter update failed\r\n");
FIH_RET(FIH_FAILURE);
}
FIH_RET(FIH_SUCCESS);
}
fih_int copy_and_decrypt_image(uint32_t image_id)
{
int rc;
#ifdef TFM_BL1_MEMORY_MAPPED_FLASH
fih_int fih_rc;
#endif /* TFM_BL1_MEMORY_MAPPED_FLASH */
struct bl1_2_image_t *image_to_decrypt;
struct bl1_2_image_t *image_after_decrypt =
(struct bl1_2_image_t *)BL2_IMAGE_START;
#ifdef TFM_BL1_MEMORY_MAPPED_FLASH
/* If we have memory-mapped flash, we can do the decrypt directly from the
* flash and output to the SRAM. This is significantly faster if the AES
* invocation calls through to a crypto accelerator with a DMA, and slightly
* faster otherwise.
*/
image_to_decrypt = (struct bl1_2_image_t *)(FLASH_BASE_ADDRESS +
bl1_image_get_flash_offset(image_id));
/* Copy everything that isn't encrypted, to prevent TOCTOU attacks and
* simplify logic.
*/
FIH_CALL(bl_secure_memcpy, fih_rc, image_after_decrypt,
image_to_decrypt,
sizeof(struct bl1_2_image_t) -
sizeof(image_after_decrypt->protected_values.encrypted_data));
#else
/* If the flash isn't memory-mapped, defer to the flash driver to copy the
* entire block in to SRAM. We'll then do the decrypt in-place.
*/
bl1_image_copy_to_sram(image_id, (uint8_t *)BL2_IMAGE_START);
image_to_decrypt = (struct bl1_2_image_t *)BL2_IMAGE_START;
#endif /* TFM_BL1_MEMORY_MAPPED_FLASH */
rc = bl1_aes_256_ctr_decrypt(TFM_BL1_KEY_BL2_ENCRYPTION,
image_to_decrypt->header.ctr_iv,
(uint8_t *)&image_to_decrypt->protected_values.encrypted_data,
sizeof(image_after_decrypt->protected_values.encrypted_data),
(uint8_t *)&image_after_decrypt->protected_values.encrypted_data);
if (rc) {
FIH_RET(fih_int_encode_zero_equality(rc));
}
if (image_after_decrypt->protected_values.encrypted_data.decrypt_magic
!= BL1_2_IMAGE_DECRYPT_MAGIC_EXPECTED) {
FIH_RET(FIH_FAILURE);
}
FIH_RET(FIH_SUCCESS);
}
static fih_int validate_image(uint32_t image_id)
{
fih_int fih_rc = FIH_FAILURE;
struct bl1_2_image_t *image;
FIH_CALL(copy_and_decrypt_image, fih_rc, image_id);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BL1_LOG("[ERR] BL2 image failed to decrypt\r\n");
FIH_RET(FIH_FAILURE);
}
image = (struct bl1_2_image_t *)BL2_IMAGE_START;
BL1_LOG("[INF] BL2 image decrypted successfully\r\n");
FIH_CALL(validate_image_at_addr, fih_rc, image);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BL1_LOG("[ERR] BL2 image failed to validate\r\n");
FIH_RET(FIH_FAILURE);
}
BL1_LOG("[INF] BL2 image validated successfully\r\n");
FIH_RET(FIH_SUCCESS);
}
int main(void)
{
platform_code_is_bl1_2 = 1;
fih_int fih_rc = FIH_FAILURE;
fih_rc = fih_int_encode_zero_equality(boot_platform_init());
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_PANIC;
}
BL1_LOG("[INF] starting TF-M bl1_2\r\n");
fih_rc = fih_int_encode_zero_equality(boot_platform_post_init());
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_PANIC;
}
#ifdef TEST_BL1_2
run_bl1_2_testsuite();
#endif /* TEST_BL1_2 */
BL1_LOG("[INF] Attempting to boot image 0\r\n");
FIH_CALL(validate_image, fih_rc, 0);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BL1_LOG("[INF] Attempting to boot image 1\r\n");
FIH_CALL(validate_image, fih_rc, 1);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
FIH_PANIC;
}
}
BL1_LOG("[INF] Jumping to BL2\r\n");
boot_platform_quit((struct boot_arm_vector_table *)BL2_CODE_START);
FIH_PANIC;
}