Initial commit
Initial commit.
This commit is contained in:
57
CMakeLists.txt
Normal file
57
CMakeLists.txt
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
|
project(cyber_scope)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
||||||
|
# APP
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
target_sources(app PRIVATE src/app/app_cli.c)
|
||||||
|
target_sources(app PRIVATE src/app/app.c)
|
||||||
|
target_sources(app PRIVATE src/app/ble.c)
|
||||||
|
target_sources(app PRIVATE src/app/bubble.c)
|
||||||
|
target_sources(app PRIVATE src/app/fiber.c)
|
||||||
|
target_sources(app PRIVATE src/app/fsm.c)
|
||||||
|
target_sources(app PRIVATE src/app/event.c)
|
||||||
|
target_sources(app PRIVATE src/app/light_sensor.c)
|
||||||
|
target_sources(app PRIVATE src/app/motion.c)
|
||||||
|
target_sources(app PRIVATE src/app/pin.c)
|
||||||
|
target_sources(app PRIVATE src/app/scope_ring.c)
|
||||||
|
target_sources(app PRIVATE src/app/shot_storage.c)
|
||||||
|
target_sources(app PRIVATE src/app/shot_capture.c)
|
||||||
|
|
||||||
|
# BSP
|
||||||
|
target_sources(app PRIVATE src/bsp/als.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/battery.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/button.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/imu.h)
|
||||||
|
target_sources(app PRIVATE src/bsp/imu.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/led_ring.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/led.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/mcu.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/nvm_ext.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/power.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/rtc.c)
|
||||||
|
target_sources(app PRIVATE src/bsp/wdt.c)
|
||||||
|
|
||||||
|
# LIB
|
||||||
|
target_sources(app PRIVATE src/lib/cli.c)
|
||||||
|
target_sources(app PRIVATE src/lib/crc.c)
|
||||||
|
if(CONFIG_DBG_STATS)
|
||||||
|
target_sources(app PRIVATE src/lib/debug.c)
|
||||||
|
endif()
|
||||||
|
target_sources(app PRIVATE src/lib/errno.c)
|
||||||
|
target_sources(app PRIVATE src/lib/fs.c)
|
||||||
|
target_sources(app PRIVATE src/lib/gamma.c)
|
||||||
|
target_sources(app PRIVATE src/lib/print.c)
|
||||||
|
target_sources(app PRIVATE src/lib/rgb.c)
|
||||||
|
target_sources(app PRIVATE src/lib/virtual_led_ring.c)
|
||||||
|
|
||||||
|
# WRAPPERS
|
||||||
|
target_sources(app PRIVATE src/wrappers/adc.c)
|
||||||
|
target_sources(app PRIVATE src/wrappers/gpio.c)
|
||||||
|
target_sources(app PRIVATE src/wrappers/i2c.c)
|
||||||
|
target_sources(app PRIVATE src/wrappers/pwm.c)
|
||||||
|
target_sources(app PRIVATE src/wrappers/spi.c)
|
||||||
|
target_sources(app PRIVATE src/wrappers/uart.c)
|
||||||
13
Kconfig
Normal file
13
Kconfig
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (C) Morgan Advanced Programmable Systems, Inc.
|
||||||
|
|
||||||
|
mainmenu "Cyber Scope Application"
|
||||||
|
|
||||||
|
config DBG_STATS
|
||||||
|
bool "Enable debug statistics"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable debug statistics variables for development and debugging.
|
||||||
|
When enabled, counters for I2C transfers, FIFO reads, shot captures,
|
||||||
|
etc. are tracked. When disabled, no code or RAM is used.
|
||||||
|
|
||||||
|
source "Kconfig.zephyr"
|
||||||
5
VERSION
Normal file
5
VERSION
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
VERSION_MAJOR = 0
|
||||||
|
VERSION_MINOR = 0
|
||||||
|
PATCHLEVEL = 0
|
||||||
|
VERSION_TWEAK = 0
|
||||||
|
EXTRAVERSION = 0
|
||||||
2
boards/MAPS/cyber_nrf52840/Kconfig.cyber_nrf52840
Normal file
2
boards/MAPS/cyber_nrf52840/Kconfig.cyber_nrf52840
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
config BOARD_CYBER_NRF52840
|
||||||
|
select SOC_NRF52840_QIAA
|
||||||
6
boards/MAPS/cyber_nrf52840/Kconfig.defconfig
Normal file
6
boards/MAPS/cyber_nrf52840/Kconfig.defconfig
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
if BOARD_CYBER_NRF52840
|
||||||
|
|
||||||
|
config BT_CTLR
|
||||||
|
default BT
|
||||||
|
|
||||||
|
endif # BOARD_CYBER_NRF52840
|
||||||
9
boards/MAPS/cyber_nrf52840/board.cmake
Normal file
9
boards/MAPS/cyber_nrf52840/board.cmake
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
board_runner_args(jlink "--device=nRF52840_xxAA" "--speed=4000")
|
||||||
|
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
|
||||||
|
|
||||||
|
set(OPENOCD_NRF5_SUBFAMILY "nrf52")
|
||||||
|
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
|
||||||
|
include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
|
||||||
|
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
|
||||||
|
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
|
||||||
|
include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)
|
||||||
5
boards/MAPS/cyber_nrf52840/board.yml
Normal file
5
boards/MAPS/cyber_nrf52840/board.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
board:
|
||||||
|
name: cyber_nrf52840
|
||||||
|
vendor: MAPS
|
||||||
|
socs:
|
||||||
|
- name: nrf52840
|
||||||
123
boards/MAPS/cyber_nrf52840/cyber_nrf52840-pinctrl.dtsi
Normal file
123
boards/MAPS/cyber_nrf52840/cyber_nrf52840-pinctrl.dtsi
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
&pinctrl {
|
||||||
|
i2c0_default: i2c0_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(TWIM_SCL, 0, 8)>,
|
||||||
|
<NRF_PSEL(TWIM_SDA, 0, 6)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c0_sleep: i2c0_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(TWIM_SCL, 0, 8)>,
|
||||||
|
<NRF_PSEL(TWIM_SDA, 0, 6)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c1_default: i2c1_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
|
||||||
|
<NRF_PSEL(TWIM_SCL, 0, 27)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c1_sleep: i2c1_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
|
||||||
|
<NRF_PSEL(TWIM_SCL, 0, 27)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2s0_default: i2s0_default {
|
||||||
|
group1 {
|
||||||
|
/* Using i2s SDOUT to drive LED ring. SCK and LRCK not needed but Zephyr driver will not
|
||||||
|
* drive SDOUT without them. Workaround : Burn up 2 unused GPIO for SCK and LRCK.
|
||||||
|
*/
|
||||||
|
psels = <NRF_PSEL(I2S_SCK_M, 0, 14)>,
|
||||||
|
<NRF_PSEL(I2S_LRCK_M, 1, 14)>,
|
||||||
|
<NRF_PSEL(I2S_SDOUT, 0, 7)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2s0_sleep: i2s0_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(I2S_SCK_M, 0, 14)>,
|
||||||
|
<NRF_PSEL(I2S_LRCK_M, 1, 14)>,
|
||||||
|
<NRF_PSEL(I2S_SDOUT, 0, 7)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pwm0_default: pwm0_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(PWM_OUT0, 0, 9)>,
|
||||||
|
<NRF_PSEL(PWM_OUT1, 0, 3)>,
|
||||||
|
<NRF_PSEL(PWM_OUT2, 1, 15)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pwm0_sleep: pwm0_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(PWM_OUT0, 0, 9)>,
|
||||||
|
<NRF_PSEL(PWM_OUT1, 0, 3)>,
|
||||||
|
<NRF_PSEL(PWM_OUT2, 1, 15)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
qspi_default: qspi_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(QSPI_SCK, 0, 19)>,
|
||||||
|
<NRF_PSEL(QSPI_CSN, 0, 20)>,
|
||||||
|
<NRF_PSEL(QSPI_IO0, 0, 23)>,
|
||||||
|
<NRF_PSEL(QSPI_IO1, 1, 0)>,
|
||||||
|
<NRF_PSEL(QSPI_IO2, 0, 22)>,
|
||||||
|
<NRF_PSEL(QSPI_IO3, 0, 21)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
qspi_sleep: qspi_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(QSPI_SCK, 0, 19)>,
|
||||||
|
<NRF_PSEL(QSPI_CSN, 0, 20)>,
|
||||||
|
<NRF_PSEL(QSPI_IO0, 0, 23)>,
|
||||||
|
<NRF_PSEL(QSPI_IO1, 1, 0)>,
|
||||||
|
<NRF_PSEL(QSPI_IO2, 0, 22)>,
|
||||||
|
<NRF_PSEL(QSPI_IO3, 0, 21)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
spi2_default: spi2_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(SPIM_SCK, 0, 19)>,
|
||||||
|
<NRF_PSEL(SPIM_MOSI, 0, 23)>,
|
||||||
|
<NRF_PSEL(SPIM_MISO, 1, 0)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
spi2_sleep: spi2_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(SPIM_SCK, 0, 19)>,
|
||||||
|
<NRF_PSEL(SPIM_MOSI, 0, 23)>,
|
||||||
|
<NRF_PSEL(SPIM_MISO, 1, 0)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
uart0_default: uart0_default {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(UART_TX, 1, 12)>,
|
||||||
|
<NRF_PSEL(UART_RX, 1, 11)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
uart0_sleep: uart0_sleep {
|
||||||
|
group1 {
|
||||||
|
psels = <NRF_PSEL(UART_TX, 1, 12)>,
|
||||||
|
<NRF_PSEL(UART_RX, 1, 11)>;
|
||||||
|
low-power-enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
243
boards/MAPS/cyber_nrf52840/cyber_nrf52840.dts
Normal file
243
boards/MAPS/cyber_nrf52840/cyber_nrf52840.dts
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
#include <nordic/nrf52840_qiaa.dtsi>
|
||||||
|
#include "cyber_nrf52840-pinctrl.dtsi"
|
||||||
|
/* For use with WS2812 LEDs. */
|
||||||
|
#include <zephyr/dt-bindings/led/led.h>
|
||||||
|
|
||||||
|
/ {
|
||||||
|
model = "MAPS - Cyber NRF52840 Board";
|
||||||
|
compatible = "MAPS,cyber-nrf52840";
|
||||||
|
|
||||||
|
chosen {
|
||||||
|
zephyr,sram = &sram0;
|
||||||
|
zephyr,flash = &flash0;
|
||||||
|
zephyr,code-partition = &slot0_partition;
|
||||||
|
zephyr,console = &uart0;
|
||||||
|
};
|
||||||
|
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
mcuboot-led = &mcuboot_led;
|
||||||
|
left-button = &left_button;
|
||||||
|
center-button = ¢er_button;
|
||||||
|
right-button = &right_button;
|
||||||
|
pwr-5v-enable = &pwr_5v_enable;
|
||||||
|
led-ring-pwr = &led_ring_pwr;
|
||||||
|
led-ring-level-shift-enable = &led_ring_level_shift_enable;
|
||||||
|
led-ring-din = &led_ring_din;
|
||||||
|
battery-check-enable = &battery_check_enable;
|
||||||
|
imu-int = &imu_int;
|
||||||
|
|
||||||
|
|
||||||
|
bubble-led = &bubble_led;
|
||||||
|
pin-led = &pin_led;
|
||||||
|
fiber-led = &fiber_led;
|
||||||
|
|
||||||
|
led-ring = &led_ring;
|
||||||
|
|
||||||
|
watchdog0 = &wdt0;
|
||||||
|
|
||||||
|
// spi-flash0 = &mx25r64;
|
||||||
|
// bootloader-led0 = &bubble_led;
|
||||||
|
// mcuboot-button0 = ¢er_button;
|
||||||
|
// mcuboot-led0 = &bubble_led;
|
||||||
|
};
|
||||||
|
|
||||||
|
// GPIO enable assumes true is whatever the logic level is set to. Set everything to active high here so we can control in code.
|
||||||
|
gpios {
|
||||||
|
compatible = "gpio-keys";
|
||||||
|
mcuboot_led: mcuboot_led {
|
||||||
|
gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
left_button: left_button {
|
||||||
|
gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
center_button: center_button {
|
||||||
|
gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
right_button: right_button {
|
||||||
|
gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
pwr_5v_enable: pwr_5v_enable {
|
||||||
|
gpios = <&gpio0 12 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
|
||||||
|
};
|
||||||
|
led_ring_pwr: led_ring_pwr {
|
||||||
|
gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
led_ring_level_shift_enable: led_ring_level_shift_enable {
|
||||||
|
gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
led_ring_din: led_ring_din {
|
||||||
|
gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
battery_check_enable: battery_check_enable {
|
||||||
|
gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
imu_int: imu_int {
|
||||||
|
gpios = <&gpio0 11 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
|
||||||
|
};
|
||||||
|
charger_status: charger_status {
|
||||||
|
gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
pwmleds: pwmleds {
|
||||||
|
compatible = "pwm-leds";
|
||||||
|
|
||||||
|
bubble_led: bubble_led {
|
||||||
|
pwms = <&pwm0 0 PWM_USEC(4000) PWM_POLARITY_NORMAL>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pin_led: pin_led {
|
||||||
|
pwms = <&pwm0 1 PWM_USEC(4000) PWM_POLARITY_NORMAL>;
|
||||||
|
};
|
||||||
|
|
||||||
|
fiber_led: fiber_led {
|
||||||
|
pwms = <&pwm0 2 PWM_USEC(4000) PWM_POLARITY_NORMAL>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&flash0 {
|
||||||
|
partitions {
|
||||||
|
compatible = "fixed-partitions";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
boot_partition: partition@0 {
|
||||||
|
label = "mcuboot";
|
||||||
|
reg = <0x00000000 DT_SIZE_K(48)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
slot0_partition: partition@c000 {
|
||||||
|
label = "image-0";
|
||||||
|
reg = <0x0000c000 DT_SIZE_K(472)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
slot1_partition: partition@82000 {
|
||||||
|
label = "image-1";
|
||||||
|
reg = <0x00082000 DT_SIZE_K(472)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
storage_partition: partition@f8000 {
|
||||||
|
label = "storage";
|
||||||
|
reg = <0x000f8000 DT_SIZE_K(32)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&uicr {
|
||||||
|
/* Pins P0.09 and P0.10 are defaulted to be used with NFC, need to configure for standard GPIO
|
||||||
|
* https://devzone.nordicsemi.com/f/nordic-q-a/35505/nrf52-enabling-gpio-on-nfc-pins
|
||||||
|
*/
|
||||||
|
nfct-pins-as-gpios;
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc {
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1_6";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,input-positive = <NRF_SAADC_AIN0>; /* P0.02 */
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&gpio0 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&gpio1 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&gpiote {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2c0 {
|
||||||
|
compatible = "nordic,nrf-twi";
|
||||||
|
status = "okay";
|
||||||
|
clock-frequency = <I2C_BITRATE_FAST>;
|
||||||
|
pinctrl-0 = <&i2c0_default>;
|
||||||
|
pinctrl-1 = <&i2c0_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
};
|
||||||
|
|
||||||
|
&i2c1 {
|
||||||
|
compatible = "nordic,nrf-twim";
|
||||||
|
status = "okay";
|
||||||
|
clock-frequency = <I2C_BITRATE_FAST>;
|
||||||
|
pinctrl-0 = <&i2c1_default>;
|
||||||
|
pinctrl-1 = <&i2c1_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
};
|
||||||
|
|
||||||
|
i2s_led: &i2s0 {
|
||||||
|
status = "okay";
|
||||||
|
pinctrl-0 = <&i2s0_default>;
|
||||||
|
pinctrl-1 = <&i2s0_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
|
||||||
|
led_ring: ws2812 {
|
||||||
|
compatible = "worldsemi,ws2812-i2s";
|
||||||
|
|
||||||
|
i2s-dev = < &i2s_led >;
|
||||||
|
chain-length = <24>;
|
||||||
|
color-mapping = <LED_COLOR_ID_GREEN
|
||||||
|
LED_COLOR_ID_RED
|
||||||
|
LED_COLOR_ID_BLUE>;
|
||||||
|
// out-active-low;
|
||||||
|
reset-delay = <120>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&spi2 {
|
||||||
|
compatible = "nordic,nrf-spim";
|
||||||
|
status = "okay";
|
||||||
|
pinctrl-0 = <&spi2_default>;
|
||||||
|
pinctrl-1 = <&spi2_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
cs-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
|
||||||
|
};
|
||||||
|
|
||||||
|
&uart0 {
|
||||||
|
status = "okay";
|
||||||
|
pinctrl-0 = <&uart0_default>;
|
||||||
|
pinctrl-1 = <&uart0_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
current-speed = <115200>;
|
||||||
|
};
|
||||||
|
|
||||||
|
&pwm0 {
|
||||||
|
status = "okay";
|
||||||
|
pinctrl-0 = <&pwm0_default>;
|
||||||
|
pinctrl-1 = <&pwm0_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
};
|
||||||
|
|
||||||
|
&qspi {
|
||||||
|
status = "disabled";
|
||||||
|
pinctrl-0 = <&qspi_default>;
|
||||||
|
pinctrl-1 = <&qspi_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
|
};
|
||||||
|
|
||||||
|
&rtc2 {
|
||||||
|
status = "okay";
|
||||||
|
clock-frequency = <32768>;
|
||||||
|
prescaler = <4095>; /* +1 for prescaler */
|
||||||
|
};
|
||||||
|
|
||||||
|
&wdt0 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
11
boards/MAPS/cyber_nrf52840/cyber_nrf52840.yml
Normal file
11
boards/MAPS/cyber_nrf52840/cyber_nrf52840.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
identifier: cyber_nrf52840/nrf52840
|
||||||
|
name: Custom Board auto generated by nRF Connect for VS Code
|
||||||
|
vendor: MAPS
|
||||||
|
type: mcu
|
||||||
|
arch: arm
|
||||||
|
ram: 256
|
||||||
|
flash: 1024
|
||||||
|
toolchain:
|
||||||
|
- zephyr
|
||||||
|
supported:
|
||||||
|
- gpio
|
||||||
12
boards/MAPS/cyber_nrf52840/cyber_nrf52840_defconfig
Normal file
12
boards/MAPS/cyber_nrf52840/cyber_nrf52840_defconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Enable MPU
|
||||||
|
CONFIG_ARM_MPU=y
|
||||||
|
|
||||||
|
# Enable hardware stack protection
|
||||||
|
CONFIG_HW_STACK_PROTECTION=y
|
||||||
|
|
||||||
|
# Enable uart driver
|
||||||
|
CONFIG_SERIAL=y
|
||||||
|
|
||||||
|
# Enable console
|
||||||
|
CONFIG_CONSOLE=y
|
||||||
|
CONFIG_UART_CONSOLE=y
|
||||||
2
boards/MAPS/cyber_nrf52840/pre_dt_board.cmake
Normal file
2
boards/MAPS/cyber_nrf52840/pre_dt_board.cmake
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Suppress "unique_unit_address_if_enabled" to handle some overlaps
|
||||||
|
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
|
||||||
30
bootloader/mcuboot/.gitignore
vendored
Normal file
30
bootloader/mcuboot/.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
outdir/
|
||||||
|
.*.swp
|
||||||
|
target.sh
|
||||||
|
*.pyc
|
||||||
|
tags
|
||||||
|
rusty-tags.*
|
||||||
|
|
||||||
|
# mynewt
|
||||||
|
/repos/
|
||||||
|
/project.state
|
||||||
|
/bin/
|
||||||
|
/targets/
|
||||||
|
**/build/**/*
|
||||||
|
|
||||||
|
#Eclipse project files
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
|
||||||
|
# Compiled python modules.
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Setuptools distribution folder.
|
||||||
|
/scripts/dist/
|
||||||
|
|
||||||
|
# Python egg metadata, regenerated from source files by setuptools.
|
||||||
|
/scripts/*.egg-info
|
||||||
|
/scripts/*.egg
|
||||||
|
|
||||||
|
# The target directory from Rust development
|
||||||
|
/target/
|
||||||
21
bootloader/mcuboot/.gitmodules
vendored
Normal file
21
bootloader/mcuboot/.gitmodules
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[submodule "sim/mbedtls"]
|
||||||
|
path = ext/mbedtls
|
||||||
|
url = https://github.com/ARMmbed/mbedtls
|
||||||
|
[submodule "boot/cypress/libs/mtb-pdl-cat1"]
|
||||||
|
path = boot/cypress/libs/mtb-pdl-cat1
|
||||||
|
url = https://github.com/cypresssemiconductorco/mtb-pdl-cat1.git
|
||||||
|
[submodule "boot/cypress/libs/pdl/psoc6pdl"]
|
||||||
|
path = boot/cypress/libs/pdl/psoc6pdl
|
||||||
|
url = https://github.com/cypresssemiconductorco/psoc6pdl.git
|
||||||
|
[submodule "boot/cypress/libs/retarget-io"]
|
||||||
|
path = boot/cypress/libs/retarget-io
|
||||||
|
url = https://github.com/cypresssemiconductorco/retarget-io.git
|
||||||
|
[submodule "boot/cypress/libs/core-lib"]
|
||||||
|
path = boot/cypress/libs/core-lib
|
||||||
|
url = https://github.com/cypresssemiconductorco/core-lib.git
|
||||||
|
[submodule "boot/cypress/libs/psoc6hal"]
|
||||||
|
path = boot/cypress/libs/psoc6hal
|
||||||
|
url = https://github.com/cypresssemiconductorco/psoc6hal.git
|
||||||
|
[submodule "boot/cypress/libs/cy-mbedtls-acceleration"]
|
||||||
|
path = boot/cypress/libs/cy-mbedtls-acceleration
|
||||||
|
url = https://github.com/cypresssemiconductorco/cy-mbedtls-acceleration.git
|
||||||
20
bootloader/mcuboot/.mbedignore
Normal file
20
bootloader/mcuboot/.mbedignore
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
boot/boot_serial/*
|
||||||
|
boot/mynewt/*
|
||||||
|
boot/zephyr/*
|
||||||
|
boot/cypress/*
|
||||||
|
boot/espressif/*
|
||||||
|
boot/nuttx/*
|
||||||
|
ci/*
|
||||||
|
docs/*
|
||||||
|
ptest/*
|
||||||
|
samples/*
|
||||||
|
scripts/*
|
||||||
|
sim/*
|
||||||
|
testplan/*
|
||||||
|
ext/fiat/*
|
||||||
|
ext/mbedtls/*
|
||||||
|
ext/mbedtls-asn1/*
|
||||||
|
ext/nrf/*
|
||||||
|
ext/tinycrypt/tests/*
|
||||||
|
ext/tinycrypt/*
|
||||||
|
ext/tinycrypt-sha512/*
|
||||||
81
bootloader/mcuboot/.travis.yml-disabled
Normal file
81
bootloader/mcuboot/.travis.yml-disabled
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# Travis configuration. Run FI hardening tests.
|
||||||
|
|
||||||
|
language: minimal
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=RELEASE SKIP_SIZE=2,4,6,8,10 TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=RELEASE SKIP_SIZE=2,4,6,8,10 FIH_LEVEL=LOW TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=RELEASE SKIP_SIZE=2,4,6,8,10 FIH_LEVEL=MEDIUM TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 FIH_LEVEL=LOW TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 FIH_LEVEL=MEDIUM TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=8,10 TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=8,10 FIH_LEVEL=LOW TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
language: minimal
|
||||||
|
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=8,10 FIH_LEVEL=MEDIUM TEST=fih-tests DAMAGE_TYPE=SIGNATURE
|
||||||
|
|
||||||
|
## Corrupt image hash is not tested as it is in the unprotected TLV section
|
||||||
|
## and is easy to calculate a valid hash for a changed image
|
||||||
|
#- os: linux
|
||||||
|
# language: minimal
|
||||||
|
# env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 TEST=fih-tests DAMAGE_TYPE=IMAGE_HASH
|
||||||
|
|
||||||
|
## Max profile is not tested as it requires HW entropy source which is not
|
||||||
|
## present in the QEMU system being used for the tests.
|
||||||
|
#- os: linux
|
||||||
|
# language: minimal
|
||||||
|
# env: FIH_LEVEL=MAX TEST=fih-tests
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
||||||
|
./ci/check-signed-off-by.sh
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
install:
|
||||||
|
- ./ci/${TEST}_install.sh
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./ci/${TEST}_run.sh
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
slack:
|
||||||
|
rooms:
|
||||||
|
- secure: "Tg9ZvJfb6e4QSEsxUvwW2MIqbuNRxD4nAOkgs8eopj/fRtqN6Zk06NVSeMmYcZunDFJXUSzYANBsF98OtaaUlm4WVt2T0ZFBJZrOYfIv18/zXCjYa04sDxur57F1ZYTYKyRpdUkfzPd/rGE4jKLQNcia+r/BTQbJkcZbXeg5/6cUeMP1so8/o0oMhSQP+GH0fLbyLzx3VPE8zu6+j2fCFC7R3idxtfO9VtsKlubfi3HgPgXTs+DEAAA8aoOku2esjFSFXTtdUFGz90YzyShZvtMcRg3Grp9+PZAsJwWk4eKSonKCO0DScfPUlMZbJcV7VsmyTxYKLLsGRZae6ZBH+XLfx5XeqgtgCor3FYx2dUXYfV9y8VvERDdossB0gZ/V2OUGePctDefiORytV6dMa7X3AfSdosgs/tjG4kbf+PMaVULzwF6dd3CdsxdClSl68UQPWA6wC2TEyo1EQea8jgZU6heLustZaQZhBkFkr/6j75XeGBjPw2fgVRkgg/OnTOYmo7N8181wOU+xORIEO1BtYmgRpc0cgpm4H9457diSHG1D2SoNy4tiQPCW2enN00QNGK5pZSL/FGA/ReUcALgAW0QcOljjU2bUSGPxo/VAi5ZyljWgVAGQ5qHJ4jgdfPf7VJUzCVH64G1S5+0gZPpO6vvvPdZtqeXrfBZMOBw="
|
||||||
|
on_success: always
|
||||||
134
bootloader/mcuboot/CODE_OF_CONDUCT.md
Normal file
134
bootloader/mcuboot/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, caste, color, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
mcuboot@groups.io.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by
|
||||||
|
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
|
||||||
|
at [https://www.contributor-covenant.org/translations][translations].
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||||
|
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||||
|
[FAQ]: https://www.contributor-covenant.org/faq
|
||||||
|
[translations]: https://www.contributor-covenant.org/translations
|
||||||
|
|
||||||
542
bootloader/mcuboot/Cargo.lock
generated
Normal file
542
bootloader/mcuboot/Cargo.lock
generated
Normal file
@@ -0,0 +1,542 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
"ctr",
|
||||||
|
"opaque-debug",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bootsim"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"base64",
|
||||||
|
"byteorder",
|
||||||
|
"cipher",
|
||||||
|
"docopt",
|
||||||
|
"env_logger",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"mcuboot-sys",
|
||||||
|
"pem",
|
||||||
|
"rand",
|
||||||
|
"ring",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"simflash",
|
||||||
|
"typenum",
|
||||||
|
"untrusted 0.9.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctr"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "docopt"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.122"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mcuboot-sys"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"simflash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.16.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"spin",
|
||||||
|
"untrusted 0.7.1",
|
||||||
|
"web-sys",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.136"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.136"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simflash"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"rand",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.91"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-sys"
|
||||||
|
version = "0.3.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
14
bootloader/mcuboot/Cargo.toml
Normal file
14
bootloader/mcuboot/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["sim"]
|
||||||
|
exclude = ["ptest"]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
|
# The simulator runs very slowly without optimization. A value of 1
|
||||||
|
# compiles in about half the time, but runs about 5-6 times slower. 2
|
||||||
|
# and 3 are hardly different in either compile time or performance.
|
||||||
|
# Use 2 in case that makes the code slightly more debuggable.
|
||||||
|
[profile.test]
|
||||||
|
opt-level = 2
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 2
|
||||||
206
bootloader/mcuboot/LICENSE
Normal file
206
bootloader/mcuboot/LICENSE
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
This product bundles tinycrypt, which is available under the "3-clause BSD"
|
||||||
|
license. For details, and bundled files see:
|
||||||
|
* ext/tinycrypt/LICENSE
|
||||||
|
* ext/tinycrypt
|
||||||
11
bootloader/mcuboot/NOTICE
Normal file
11
bootloader/mcuboot/NOTICE
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Apache Mynewt
|
||||||
|
Copyright 2015-2017 The Apache Software Foundation
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
The Apache Software Foundation (http://www.apache.org/).
|
||||||
|
|
||||||
|
Portions of this software were developed at
|
||||||
|
Runtime Inc, copyright 2015.
|
||||||
|
|
||||||
|
Portions of this software were developed at
|
||||||
|
Arm Limited, copyright 2019-2021.
|
||||||
85
bootloader/mcuboot/README.md
Normal file
85
bootloader/mcuboot/README.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# [MCUboot](http://mcuboot.com/)
|
||||||
|
|
||||||
|
[][pypi]
|
||||||
|
[][coverity]
|
||||||
|
[][sim]
|
||||||
|
[][mynewt]
|
||||||
|
[][espressif]
|
||||||
|
[][imgtool]
|
||||||
|
[][travis]
|
||||||
|
[][license]
|
||||||
|
|
||||||
|
[pypi]: https://pypi.org/project/imgtool/
|
||||||
|
[coverity]: https://scan.coverity.com/projects/mcuboot
|
||||||
|
[sim]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Sim
|
||||||
|
[mynewt]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Mynewt
|
||||||
|
[espressif]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Espressif
|
||||||
|
[imgtool]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:imgtool
|
||||||
|
[travis]: https://travis-ci.org/mcu-tools/mcuboot
|
||||||
|
[license]: https://github.com/mcu-tools/mcuboot/blob/main/LICENSE
|
||||||
|
|
||||||
|
This is MCUboot version 2.1.0
|
||||||
|
|
||||||
|
MCUboot is a secure bootloader for 32-bits microcontrollers. It defines a
|
||||||
|
common infrastructure for the bootloader and the system flash layout on
|
||||||
|
microcontroller systems, and provides a secure bootloader that enables easy
|
||||||
|
software upgrade.
|
||||||
|
|
||||||
|
MCUboot is not dependent on any specific operating system and hardware and
|
||||||
|
relies on hardware porting layers from the operating system it works with.
|
||||||
|
Currently, MCUboot works with the following operating systems and SoCs:
|
||||||
|
- [Zephyr](https://www.zephyrproject.org/)
|
||||||
|
- [Apache Mynewt](https://mynewt.apache.org/)
|
||||||
|
- [Apache NuttX](https://nuttx.apache.org/)
|
||||||
|
- [RIOT](https://www.riot-os.org/)
|
||||||
|
- [Mbed OS](https://os.mbed.com/)
|
||||||
|
- [Espressif](https://www.espressif.com/)
|
||||||
|
- [Cypress/Infineon](https://www.cypress.com/)
|
||||||
|
|
||||||
|
RIOT is supported only as a boot target. We will accept any new
|
||||||
|
port contributed by the community once it is good enough.
|
||||||
|
|
||||||
|
## MCUboot How-tos
|
||||||
|
|
||||||
|
See the following pages for instructions on using MCUboot with different
|
||||||
|
operating systems and SoCs:
|
||||||
|
- [Zephyr](docs/readme-zephyr.md)
|
||||||
|
- [Apache Mynewt](docs/readme-mynewt.md)
|
||||||
|
- [Apache NuttX](docs/readme-nuttx.md)
|
||||||
|
- [RIOT](docs/readme-riot.md)
|
||||||
|
- [Mbed OS](docs/readme-mbed.md)
|
||||||
|
- [Espressif](docs/readme-espressif.md)
|
||||||
|
- [Cypress/Infineon](boot/cypress/README.md)
|
||||||
|
|
||||||
|
There are also instructions for the [Simulator](sim/README.rst).
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
The issues being planned and worked on are tracked using GitHub issues. To
|
||||||
|
give your input, visit [MCUboot GitHub
|
||||||
|
Issues](https://github.com/mcu-tools/mcuboot/issues).
|
||||||
|
|
||||||
|
## Source files
|
||||||
|
|
||||||
|
You can find additional documentation on the bootloader in the source files.
|
||||||
|
For more information, use the following links:
|
||||||
|
- [boot/bootutil](https://github.com/mcu-tools/mcuboot/tree/main/boot/bootutil) - The core of the bootloader itself.
|
||||||
|
- [boot/boot\_serial](https://github.com/mcu-tools/mcuboot/tree/main/boot/boot_serial) - Support for serial upgrade within the bootloader itself.
|
||||||
|
- [boot/zephyr](https://github.com/mcu-tools/mcuboot/tree/main/boot/zephyr) - Port of the bootloader to Zephyr.
|
||||||
|
- [boot/mynewt](https://github.com/mcu-tools/mcuboot/tree/main/boot/mynewt) - Bootloader application for Apache Mynewt.
|
||||||
|
- [boot/nuttx](https://github.com/mcu-tools/mcuboot/tree/main/boot/nuttx) - Bootloader application and port of MCUboot interfaces for Apache NuttX.
|
||||||
|
- [boot/mbed](https://github.com/mcu-tools/mcuboot/tree/main/boot/mbed) - Port of the bootloader to Mbed OS.
|
||||||
|
- [boot/espressif](https://github.com/mcu-tools/mcuboot/tree/main/boot/espressif) - Bootloader application and MCUboot port for Espressif SoCs.
|
||||||
|
- [boot/cypress](https://github.com/mcu-tools/mcuboot/tree/main/boot/cypress) - Bootloader application and MCUboot port for Cypress/Infineon SoCs.
|
||||||
|
- [imgtool](https://github.com/mcu-tools/mcuboot/tree/main/scripts/imgtool.py) - A tool to securely sign firmware images for booting by MCUboot.
|
||||||
|
- [sim](https://github.com/mcu-tools/mcuboot/tree/main/sim) - A bootloader simulator for testing and regression.
|
||||||
|
|
||||||
|
## Joining the project
|
||||||
|
|
||||||
|
Developers are welcome!
|
||||||
|
|
||||||
|
Use the following links to join or see more about the project:
|
||||||
|
|
||||||
|
* [Our developer mailing list](https://groups.io/g/MCUBoot)
|
||||||
|
* [Our Discord channel](https://discord.com/channels/1106321706588577904/1106322802308550716) <br />
|
||||||
|
Get [your invite](https://discord.com/invite/5PpXhvda5p)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOT_SERIAL_H__
|
||||||
|
#define __BOOT_SERIAL_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function pointers to read/write data from uart.
|
||||||
|
* read returns the number of bytes read, str points to buffer to fill,
|
||||||
|
* cnt is the number of bytes to fill within buffer, *newline will be
|
||||||
|
* set if newline is the last character.
|
||||||
|
* write takes as it's arguments pointer to data to write, and the count
|
||||||
|
* of bytes.
|
||||||
|
*/
|
||||||
|
struct boot_uart_funcs {
|
||||||
|
int (*read)(char *str, int cnt, int *newline);
|
||||||
|
void (*write)(const char *ptr, int cnt);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start processing newtmgr commands for uploading image0 over serial.
|
||||||
|
* Assumes serial port is open and waits for download command.
|
||||||
|
*/
|
||||||
|
void boot_serial_start(const struct boot_uart_funcs *f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start processing newtmgr commands for uploading image0 over serial.
|
||||||
|
* Assumes serial port is open and waits for download command.
|
||||||
|
* This function will return if there is no mcumgr command received within
|
||||||
|
* the given timeout. If a command is received within this timeout, the
|
||||||
|
* function is similar to boot_serial_start
|
||||||
|
*/
|
||||||
|
void boot_serial_check_start(const struct boot_uart_funcs *f, int timeout_in_ms);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOT_SERIAL_H__ */
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOT_SERIAL_ENCRYPTION_
|
||||||
|
#define H_BOOT_SERIAL_ENCRYPTION_
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate hash of a primary boot image doing on the fly decryption as well
|
||||||
|
*
|
||||||
|
* @param[in] fa_p flash area pointer
|
||||||
|
* @param[in] hdr boot image header pointer
|
||||||
|
* @param[in] buf buffer which is used for validating data
|
||||||
|
* @param[in] buf_size size of input buffer
|
||||||
|
*
|
||||||
|
* @return FIH_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
fih_ret
|
||||||
|
boot_image_validate_encrypted(const struct flash_area *fa_p,
|
||||||
|
struct image_header *hdr, uint8_t *buf,
|
||||||
|
uint16_t buf_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an encrypted firmware in the main flash.
|
||||||
|
* This will decrypt the image inplace
|
||||||
|
*/
|
||||||
|
int boot_handle_enc_fw(const struct flash_area *flash_area);
|
||||||
|
|
||||||
|
#endif
|
||||||
38
bootloader/mcuboot/boot/boot_serial/pkg.yml
Normal file
38
bootloader/mcuboot/boot/boot_serial/pkg.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
pkg.name: boot/boot_serial
|
||||||
|
pkg.description: The boot_serial library is used when downloading image over serial port.
|
||||||
|
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||||
|
pkg.homepage: "http://mynewt.apache.org/"
|
||||||
|
pkg.keywords:
|
||||||
|
- boot
|
||||||
|
- bootloader
|
||||||
|
|
||||||
|
pkg.deps:
|
||||||
|
- "@apache-mynewt-core/hw/hal"
|
||||||
|
- "@apache-mynewt-core/kernel/os"
|
||||||
|
- "@apache-mynewt-core/encoding/base64"
|
||||||
|
- "@mcuboot/boot/mynewt/flash_map_backend"
|
||||||
|
- "@mcuboot/boot/mynewt/boot_uart"
|
||||||
|
- "@mcuboot/boot/zcbor"
|
||||||
|
- "@apache-mynewt-core/util/crc"
|
||||||
|
|
||||||
|
pkg.req_apis:
|
||||||
|
- bootloader
|
||||||
1498
bootloader/mcuboot/boot/boot_serial/src/boot_serial.c
Normal file
1498
bootloader/mcuboot/boot/boot_serial/src/boot_serial.c
Normal file
File diff suppressed because it is too large
Load Diff
308
bootloader/mcuboot/boot/boot_serial/src/boot_serial_encryption.c
Normal file
308
bootloader/mcuboot/boot/boot_serial/src/boot_serial_encryption.c
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2020 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include <../src/bootutil_priv.h>
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
#include "bootutil/bootutil_public.h"
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
#include "bootutil/enc_key.h"
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(serial_encryption);
|
||||||
|
|
||||||
|
fih_ret
|
||||||
|
boot_image_validate_encrypted(const struct flash_area *fa_p,
|
||||||
|
struct image_header *hdr, uint8_t *buf,
|
||||||
|
uint16_t buf_size)
|
||||||
|
{
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
|
||||||
|
struct boot_loader_state boot_data;
|
||||||
|
struct boot_loader_state *state = &boot_data;
|
||||||
|
struct boot_status _bs;
|
||||||
|
struct boot_status *bs = &_bs;
|
||||||
|
uint8_t image_index;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
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), 1, hdr, fa_p, bs);
|
||||||
|
if (rc < 0) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
|
||||||
|
if (rc < 0) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index,
|
||||||
|
hdr, fa_p, buf, buf_size, NULL, 0, NULL);
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the total size of the given image. Includes the size of
|
||||||
|
* the TLVs.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
read_image_size(const struct flash_area *fa_p,
|
||||||
|
struct image_header *hdr,
|
||||||
|
uint32_t *size)
|
||||||
|
{
|
||||||
|
struct image_tlv_info info;
|
||||||
|
uint32_t off;
|
||||||
|
uint32_t protect_tlv_size;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
off = BOOT_TLV_OFF(hdr);
|
||||||
|
|
||||||
|
if (flash_area_read(fa_p, off, &info, sizeof(info))) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
protect_tlv_size = hdr->ih_protect_tlv_size;
|
||||||
|
if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
|
||||||
|
if (protect_tlv_size != info.it_tlv_tot) {
|
||||||
|
rc = BOOT_EBADIMAGE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flash_area_read(fa_p, off + info.it_tlv_tot, &info, sizeof(info))) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else if (protect_tlv_size != 0) {
|
||||||
|
rc = BOOT_EBADIMAGE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
|
||||||
|
rc = BOOT_EBADIMAGE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = off + protect_tlv_size + info.it_tlv_tot;
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads, decrypts in RAM & write back the decrypted image in the same region
|
||||||
|
* This function is NOT power failsafe since the image is decrypted in the RAM
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* @param flash_area The ID of the source flash area.
|
||||||
|
* @param off_src The offset within the flash area to
|
||||||
|
* copy from.
|
||||||
|
* @param sz The number of bytes to copy. should match erase sector
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
decrypt_region_inplace(struct boot_loader_state *state,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
struct image_header *hdr,
|
||||||
|
uint32_t off, uint32_t sz)
|
||||||
|
{
|
||||||
|
uint32_t bytes_copied;
|
||||||
|
int chunk_sz;
|
||||||
|
int rc;
|
||||||
|
uint32_t tlv_off;
|
||||||
|
size_t blk_off;
|
||||||
|
uint16_t idx;
|
||||||
|
uint32_t blk_sz;
|
||||||
|
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) {
|
||||||
|
if (sz - bytes_copied > sizeof buf) {
|
||||||
|
chunk_sz = sizeof buf;
|
||||||
|
} else {
|
||||||
|
chunk_sz = sz - bytes_copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = flash_area_read(fap, off + bytes_copied, buf, chunk_sz);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ENCRYPTED(hdr)) {
|
||||||
|
blk_sz = chunk_sz;
|
||||||
|
idx = 0;
|
||||||
|
if (off + bytes_copied < hdr->ih_hdr_size) {
|
||||||
|
/* do not decrypt header */
|
||||||
|
if (hdr->ih_hdr_size > (off + bytes_copied + chunk_sz)) {
|
||||||
|
/* all bytes in header, skip decryption */
|
||||||
|
blk_sz = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
blk_sz = off + bytes_copied + chunk_sz - hdr->ih_hdr_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
blk_off = 0;
|
||||||
|
idx = hdr->ih_hdr_size;
|
||||||
|
} else {
|
||||||
|
blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
|
||||||
|
}
|
||||||
|
tlv_off = BOOT_TLV_OFF(hdr);
|
||||||
|
if (off + bytes_copied + chunk_sz > tlv_off) {
|
||||||
|
/* do not decrypt TLVs */
|
||||||
|
if (off + bytes_copied >= tlv_off) {
|
||||||
|
blk_sz = 0;
|
||||||
|
} else {
|
||||||
|
blk_sz = tlv_off - (off + bytes_copied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boot_enc_decrypt(BOOT_CURR_ENC(state), slot,
|
||||||
|
(off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
|
||||||
|
blk_off, &buf[idx]);
|
||||||
|
}
|
||||||
|
rc = flash_area_erase(fap, off + bytes_copied, chunk_sz);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
rc = flash_area_write(fap, off + bytes_copied, buf, chunk_sz);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_copied += chunk_sz;
|
||||||
|
|
||||||
|
MCUBOOT_WATCHDOG_FEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a image was encrypted into the first slot, and decrypt it
|
||||||
|
* in place. this operation is not power failsafe.
|
||||||
|
*
|
||||||
|
* The operation is done by checking the last flash sector, and using it as a
|
||||||
|
* temporarely scratch partition. The
|
||||||
|
*
|
||||||
|
* @param[in] fa_p flash area pointer
|
||||||
|
* @param[in] hdr boot image header pointer
|
||||||
|
*
|
||||||
|
* @return FIH_SUCCESS on success, error code otherwise
|
||||||
|
*/
|
||||||
|
inline static fih_ret
|
||||||
|
decrypt_image_inplace(const struct flash_area *fa_p,
|
||||||
|
struct image_header *hdr)
|
||||||
|
{
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
int rc;
|
||||||
|
struct boot_loader_state boot_data;
|
||||||
|
struct boot_loader_state *state = &boot_data;
|
||||||
|
struct boot_status _bs;
|
||||||
|
struct boot_status *bs = &_bs;
|
||||||
|
size_t size;
|
||||||
|
size_t sect_size;
|
||||||
|
size_t sect_count;
|
||||||
|
size_t sect;
|
||||||
|
struct flash_sector sector;
|
||||||
|
|
||||||
|
memset(&boot_data, 0, sizeof(struct boot_loader_state));
|
||||||
|
memset(&_bs, 0, sizeof(struct boot_status));
|
||||||
|
|
||||||
|
/* Get size from last sector to know page/sector erase size */
|
||||||
|
rc = flash_area_get_sector(fa_p, boot_status_off(fa_p), §or);
|
||||||
|
|
||||||
|
|
||||||
|
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];
|
||||||
|
/* First check if the encrypted image is a good image before decrypting */
|
||||||
|
FIH_CALL(boot_image_validate_encrypted,fih_rc,fa_p,&_hdr,tmpbuf,BOOT_TMPBUF_SZ);
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
memset(&boot_data, 0, sizeof(struct boot_loader_state));
|
||||||
|
/* Load the encryption keys into cache */
|
||||||
|
rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fa_p, bs);
|
||||||
|
if (rc < 0) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs)) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Expected encrypted image! */
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t src_size = 0;
|
||||||
|
rc = read_image_size(fa_p,hdr, &src_size);
|
||||||
|
if (rc != 0) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: This assumes every sector has an equal size, should instead use
|
||||||
|
* flash_area_get_sectors() to get the size of each sector and iterate
|
||||||
|
* over it.
|
||||||
|
*/
|
||||||
|
sect_size = sector.fs_size;
|
||||||
|
sect_count = fa_p->fa_size / sect_size;
|
||||||
|
for (sect = 0, size = 0; size < src_size && sect < sect_count; sect++) {
|
||||||
|
rc = decrypt_region_inplace(state, fa_p,hdr, size, sect_size);
|
||||||
|
if (rc != 0) {
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
size += sect_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fih_rc = FIH_SUCCESS;
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_handle_enc_fw(const struct flash_area *flash_area)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
struct image_header _hdr = { 0 };
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
|
||||||
|
rc = boot_image_load_header(flash_area, &_hdr);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ENCRYPTED(&_hdr)) {
|
||||||
|
//encrypted, we need to decrypt in place
|
||||||
|
FIH_CALL(decrypt_image_inplace,fih_rc,flash_area,&_hdr);
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
106
bootloader/mcuboot/boot/boot_serial/src/boot_serial_priv.h
Normal file
106
bootloader/mcuboot/boot/boot_serial/src/boot_serial_priv.h
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_SERIAL_PRIV_H__
|
||||||
|
#define __BOOTUTIL_SERIAL_PRIV_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From shell.h
|
||||||
|
*/
|
||||||
|
#define SHELL_NLIP_PKT_START1 6
|
||||||
|
#define SHELL_NLIP_PKT_START2 9
|
||||||
|
|
||||||
|
#define SHELL_NLIP_DATA_START1 4
|
||||||
|
#define SHELL_NLIP_DATA_START2 20
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From newtmgr.h
|
||||||
|
*/
|
||||||
|
#define MGMT_ERR_OK 0
|
||||||
|
#define MGMT_ERR_EUNKNOWN 1
|
||||||
|
#define MGMT_ERR_ENOMEM 2
|
||||||
|
#define MGMT_ERR_EINVAL 3
|
||||||
|
#define MGMT_ERR_ENOENT 5
|
||||||
|
#define MGMT_ERR_ENOTSUP 8
|
||||||
|
#define MGMT_ERR_EBUSY 10
|
||||||
|
|
||||||
|
#define NMGR_OP_READ 0
|
||||||
|
#define NMGR_OP_WRITE 2
|
||||||
|
|
||||||
|
#define MGMT_GROUP_ID_DEFAULT 0
|
||||||
|
#define MGMT_GROUP_ID_IMAGE 1
|
||||||
|
#define MGMT_GROUP_ID_PERUSER 64
|
||||||
|
|
||||||
|
#define NMGR_ID_ECHO 0
|
||||||
|
#define NMGR_ID_CONS_ECHO_CTRL 1
|
||||||
|
#define NMGR_ID_RESET 5
|
||||||
|
|
||||||
|
#ifndef __packed
|
||||||
|
#define __packed __attribute__((__packed__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct nmgr_hdr {
|
||||||
|
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||||
|
uint8_t _res1:3;
|
||||||
|
uint8_t nh_version:2;
|
||||||
|
uint8_t nh_op:3; /* NMGR_OP_XXX */
|
||||||
|
#else
|
||||||
|
uint8_t nh_op:3; /* NMGR_OP_XXX */
|
||||||
|
uint8_t nh_version:2;
|
||||||
|
uint8_t _res1:3;
|
||||||
|
#endif
|
||||||
|
uint8_t nh_flags;
|
||||||
|
uint16_t nh_len; /* length of the payload */
|
||||||
|
uint16_t nh_group; /* NMGR_GROUP_XXX */
|
||||||
|
uint8_t nh_seq; /* sequence number */
|
||||||
|
uint8_t nh_id; /* message ID within group */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From imgmgr.h
|
||||||
|
*/
|
||||||
|
#define IMGMGR_NMGR_ID_STATE 0
|
||||||
|
#define IMGMGR_NMGR_ID_UPLOAD 1
|
||||||
|
#define IMGMGR_NMGR_ID_SLOT_INFO 6
|
||||||
|
|
||||||
|
void boot_serial_input(char *buf, int len);
|
||||||
|
extern const struct boot_uart_funcs *boot_uf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Selects direct image to upload according to the "image"
|
||||||
|
* parameter of the mcumgr update frame.
|
||||||
|
*
|
||||||
|
* @param[in] image_id the value of the "image" parameter of the
|
||||||
|
* mcumgr update frame to be translated.
|
||||||
|
*
|
||||||
|
* @return flash area ID for the image if defined;
|
||||||
|
* -EINVAL when flash area for given image number has not been
|
||||||
|
* defined.
|
||||||
|
*/
|
||||||
|
extern int flash_area_id_from_direct_image(int image_id);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_SERIAL_PRIV_H__ */
|
||||||
69
bootloader/mcuboot/boot/boot_serial/src/zcbor_bulk.c
Normal file
69
bootloader/mcuboot/boot/boot_serial/src/zcbor_bulk.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "zcbor_bulk.h"
|
||||||
|
|
||||||
|
int zcbor_map_decode_bulk(zcbor_state_t *zsd, struct zcbor_map_decode_key_val *map,
|
||||||
|
size_t map_size, size_t *matched)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
struct zcbor_map_decode_key_val *dptr = map;
|
||||||
|
|
||||||
|
if (!zcbor_map_start_decode(zsd)) {
|
||||||
|
return -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
*matched = 0;
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct zcbor_string key;
|
||||||
|
bool found = false;
|
||||||
|
size_t map_count = 0;
|
||||||
|
|
||||||
|
ok = zcbor_tstr_decode(zsd, &key);
|
||||||
|
|
||||||
|
while (ok && map_count < map_size) {
|
||||||
|
if (dptr >= (map + map_size)) {
|
||||||
|
dptr = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.len == dptr->key.len &&
|
||||||
|
memcmp(key.value, dptr->key.value, key.len) == 0) {
|
||||||
|
|
||||||
|
if (dptr->found) {
|
||||||
|
return -EADDRINUSE;
|
||||||
|
}
|
||||||
|
if (!dptr->decoder(zsd, dptr->value_ptr)) {
|
||||||
|
/* Failure to decode value matched to key
|
||||||
|
* means that either decoder has been
|
||||||
|
* incorrectly assigned or SMP payload
|
||||||
|
* is broken anyway.
|
||||||
|
*/
|
||||||
|
return -ENOMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
dptr->found = true;
|
||||||
|
found = true;
|
||||||
|
++dptr;
|
||||||
|
++(*matched);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++dptr;
|
||||||
|
++map_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found && ok) {
|
||||||
|
ok = zcbor_any_skip(zsd, NULL);
|
||||||
|
}
|
||||||
|
} while (ok);
|
||||||
|
|
||||||
|
return zcbor_map_end_decode(zsd) ? 0 : -EBADMSG;
|
||||||
|
}
|
||||||
116
bootloader/mcuboot/boot/boot_serial/src/zcbor_bulk.h
Normal file
116
bootloader/mcuboot/boot/boot_serial/src/zcbor_bulk.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#ifndef H_ZCBOR_BULK_PRIV_
|
||||||
|
#define H_ZCBOR_BULK_PRIV_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ZEPHYR__
|
||||||
|
#include <zcbor_common.h>
|
||||||
|
#include <zcbor_decode.h>
|
||||||
|
#else
|
||||||
|
#include "zcbor_common.h"
|
||||||
|
#include "zcbor_decode.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @cond INTERNAL_HIDDEN */
|
||||||
|
|
||||||
|
struct zcbor_map_decode_key_val {
|
||||||
|
struct zcbor_string key; /* Map key string */
|
||||||
|
zcbor_decoder_t *decoder; /* Key corresponding decoder */
|
||||||
|
void *value_ptr;
|
||||||
|
bool found;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Define single key-decoder mapping
|
||||||
|
*
|
||||||
|
* The macro creates a single zcbor_map_decode_key_val type object.
|
||||||
|
*
|
||||||
|
* @param k key is "" enclosed string representing key;
|
||||||
|
* @param dec decoder function; this should be zcbor_decoder_t
|
||||||
|
* type function from zcbor or a user provided implementation
|
||||||
|
* compatible with the type.
|
||||||
|
* @param vp non-NULL pointer for result of decoding; should correspond
|
||||||
|
* to type served by decoder function for the mapping.
|
||||||
|
*/
|
||||||
|
#define ZCBOR_MAP_DECODE_KEY_DECODER(k, dec, vp) \
|
||||||
|
{ \
|
||||||
|
{ \
|
||||||
|
.value = (uint8_t *)k, \
|
||||||
|
.len = sizeof(k) - 1, \
|
||||||
|
}, \
|
||||||
|
.decoder = (zcbor_decoder_t *)dec, \
|
||||||
|
.value_ptr = vp, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Define single key-value decode mapping
|
||||||
|
*
|
||||||
|
* ZCBOR_MAP_DECODE_KEY_DECODER should be used instead of this macro as,
|
||||||
|
* this macro does not allow keys with whitespaces embeeded, which CBOR
|
||||||
|
* does allow.
|
||||||
|
*
|
||||||
|
* The macro creates a single zcbor_map_decode_key_val type object.
|
||||||
|
*
|
||||||
|
* @param k key; the @p k will be stringified so should be given
|
||||||
|
* without "";
|
||||||
|
* @param dec decoder function; this should be zcbor_decoder_t
|
||||||
|
* type function from zcbor or a user provided implementation
|
||||||
|
* compatible with the type.
|
||||||
|
* @param vp non-NULL pointer for result of decoding; should correspond
|
||||||
|
* to type served by decoder function for the mapping.
|
||||||
|
*/
|
||||||
|
#define ZCBOR_MAP_DECODE_KEY_VAL(k, dec, vp) \
|
||||||
|
ZCBOR_MAP_DECODE_KEY_DECODER(STRINGIFY(k), dec, vp)
|
||||||
|
|
||||||
|
/** @brief Decodes single level map according to a provided key-decode map.
|
||||||
|
*
|
||||||
|
* The function takes @p map of key to decoder array defined as:
|
||||||
|
*
|
||||||
|
* struct zcbor_map_decode_key_val map[] = {
|
||||||
|
* ZCBOR_MAP_DECODE_KEY_DECODER("key0", decode_fun0, val_ptr0),
|
||||||
|
* ZCBOR_MAP_DECODE_KEY_DECODER("key1", decode_fun1, val_ptr1),
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* where "key?" is string representing key; the decode_fun? is
|
||||||
|
* zcbor_decoder_t compatible function, either from zcbor or defined by
|
||||||
|
* user; val_ptr? are pointers to variables where decoder function for
|
||||||
|
* a given key will place a decoded value - they have to agree in type
|
||||||
|
* with decoder function.
|
||||||
|
*
|
||||||
|
* Failure to decode any of values will cause the function to return
|
||||||
|
* negative error, and leave the map open: map is broken anyway or key-decoder
|
||||||
|
* mapping is broken, and we can not really decode the map.
|
||||||
|
*
|
||||||
|
* Note that the function opens map by itself and will fail if map
|
||||||
|
* is already opened.
|
||||||
|
*
|
||||||
|
* @param zsd zcbor decoder state;
|
||||||
|
* @param map key-decoder mapping list;
|
||||||
|
* @param map_size size of maps, both maps have to have the same size;
|
||||||
|
* @param matched pointer to the counter of matched keys, zeroed upon
|
||||||
|
* successful map entry and incremented only for successful
|
||||||
|
* decoded fields.
|
||||||
|
* @return 0 when the whole map has been parsed, there have been
|
||||||
|
* no decoding errors, and map has been closed successfully;
|
||||||
|
* -ENOMSG when given decoder function failed to decode
|
||||||
|
* value;
|
||||||
|
* -EADDRINUSE when key appears twice within map, map is then
|
||||||
|
* parsed up to they key that has appeared twice;
|
||||||
|
* -EBADMSG when failed to close map.
|
||||||
|
*/
|
||||||
|
int zcbor_map_decode_bulk(zcbor_state_t *zsd, struct zcbor_map_decode_key_val *map,
|
||||||
|
size_t map_size, size_t *matched);
|
||||||
|
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* H_ZCBOR_BULK_PRIV_ */
|
||||||
96
bootloader/mcuboot/boot/boot_serial/syscfg.yml
Normal file
96
bootloader/mcuboot/boot/boot_serial/syscfg.yml
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
syscfg.defs:
|
||||||
|
BOOT_SERIAL_DETECT_PIN:
|
||||||
|
description: >
|
||||||
|
Start the serial boot loader if this pin is asserted at boot time.
|
||||||
|
value: '-1'
|
||||||
|
restrictions:
|
||||||
|
- '(BOOT_SERIAL_DETECT_PIN != -1) ||
|
||||||
|
(BOOT_SERIAL_DETECT_TIMEOUT != 0) ||
|
||||||
|
(BOOT_SERIAL_NVREG_INDEX != -1)'
|
||||||
|
|
||||||
|
BOOT_SERIAL_DETECT_PIN_CFG:
|
||||||
|
description: >
|
||||||
|
GPIO configuration for the serial boot loader detect pin.
|
||||||
|
value: 'HAL_GPIO_PULL_UP'
|
||||||
|
|
||||||
|
BOOT_SERIAL_DETECT_PIN_VAL:
|
||||||
|
description: >
|
||||||
|
The value the detect pin must be set to for the serial boot loader
|
||||||
|
to start.
|
||||||
|
value: 0
|
||||||
|
|
||||||
|
BOOT_SERIAL_DETECT_TIMEOUT:
|
||||||
|
description: >
|
||||||
|
The duration, in milliseconds, to listen on the UART for the
|
||||||
|
management string (BOOT_SERIAL_DETECT_STRING). If the management
|
||||||
|
string is detected during this period, the serial boot loader is
|
||||||
|
started. If the period expires without the management string being
|
||||||
|
received, the boot loader runs in the normal (non-serial) mode.
|
||||||
|
Specify 0 to disable listening on the UART for the management
|
||||||
|
string.
|
||||||
|
value: 0
|
||||||
|
restrictions:
|
||||||
|
- '(BOOT_SERIAL_DETECT_PIN != -1) ||
|
||||||
|
(BOOT_SERIAL_DETECT_TIMEOUT != 0) ||
|
||||||
|
(BOOT_SERIAL_NVREG_INDEX != -1)'
|
||||||
|
|
||||||
|
BOOT_SERIAL_DETECT_STRING:
|
||||||
|
description: >
|
||||||
|
The string to listen for on the UART. If this management string is
|
||||||
|
detected during the timeout period, the serial boot loader is
|
||||||
|
started. If the period expires without this string being received,
|
||||||
|
the boot loader runs in the normal (non-serial) mode. This setting
|
||||||
|
has no effect if BOOT_SERIAL_DETECT_TIMEOUT is set to 0.
|
||||||
|
value: '"nmgr"'
|
||||||
|
|
||||||
|
BOOT_SERIAL_REPORT_PIN:
|
||||||
|
description: >
|
||||||
|
The GPIO to toggle while the serial boot loader is running. Set to
|
||||||
|
-1 to disable reporting.
|
||||||
|
value: 'LED_BLINK_PIN'
|
||||||
|
|
||||||
|
BOOT_SERIAL_REPORT_FREQ:
|
||||||
|
description: >
|
||||||
|
The toggle rate, in Hz, of the serial boot loader report pin.
|
||||||
|
value: 4
|
||||||
|
|
||||||
|
BOOT_SERIAL_NVREG_MAGIC:
|
||||||
|
description: >
|
||||||
|
Magic number, to be saved in a retained (reset-surviving) register.
|
||||||
|
If the value in the register matches, the serial bootloader will
|
||||||
|
load. Value must not be 0.
|
||||||
|
value: 0xB7
|
||||||
|
restrictions:
|
||||||
|
- '(BOOT_SERIAL_NVREG_MAGIC != 0)'
|
||||||
|
|
||||||
|
BOOT_SERIAL_NVREG_INDEX:
|
||||||
|
description: >
|
||||||
|
Index of retained register to use (using hal_nvreg_read) for reading
|
||||||
|
magic value.
|
||||||
|
value: -1
|
||||||
|
restrictions:
|
||||||
|
- '(BOOT_SERIAL_DETECT_PIN != -1) ||
|
||||||
|
(BOOT_SERIAL_DETECT_TIMEOUT != 0) ||
|
||||||
|
(BOOT_SERIAL_NVREG_INDEX != -1)'
|
||||||
|
|
||||||
|
BOOT_SERIAL_MGMT_ECHO:
|
||||||
|
description: If enabled, support for the mcumgr echo command is being added.
|
||||||
|
value: 0
|
||||||
35
bootloader/mcuboot/boot/boot_serial/test/pkg.yml
Normal file
35
bootloader/mcuboot/boot/boot_serial/test/pkg.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
pkg.name: boot/boot_serial/test
|
||||||
|
pkg.type: unittest
|
||||||
|
pkg.description: "Boot serial unit tests."
|
||||||
|
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||||
|
pkg.homepage: "http://mynewt.apache.org/"
|
||||||
|
pkg.keywords:
|
||||||
|
|
||||||
|
pkg.deps:
|
||||||
|
- "@mcuboot/boot/boot_serial"
|
||||||
|
- "@mcuboot/boot/bootutil"
|
||||||
|
- "@apache-mynewt-core/sys/log/stub"
|
||||||
|
- "@apache-mynewt-core/test/testutil"
|
||||||
|
|
||||||
|
pkg.deps.SELFTEST:
|
||||||
|
- "@apache-mynewt-core/sys/console/stub"
|
||||||
|
|
||||||
|
pkg.cflags:
|
||||||
|
- '-DMCUBOOT_MYNEWT=1'
|
||||||
85
bootloader/mcuboot/boot/boot_serial/test/src/boot_test.c
Normal file
85
bootloader/mcuboot/boot/boot_serial/test/src/boot_test.c
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "syscfg/syscfg.h"
|
||||||
|
#include "sysflash/sysflash.h"
|
||||||
|
#include "os/endian.h"
|
||||||
|
#include "base64/base64.h"
|
||||||
|
#include "crc/crc16.h"
|
||||||
|
#include "testutil/testutil.h"
|
||||||
|
#include "hal/hal_flash.h"
|
||||||
|
#include "flash_map_backend/flash_map_backend.h"
|
||||||
|
|
||||||
|
#include "boot_serial/boot_serial.h"
|
||||||
|
#include "boot_serial_priv.h"
|
||||||
|
|
||||||
|
TEST_CASE_DECL(boot_serial_setup)
|
||||||
|
TEST_CASE_DECL(boot_serial_empty_msg)
|
||||||
|
TEST_CASE_DECL(boot_serial_empty_img_msg)
|
||||||
|
TEST_CASE_DECL(boot_serial_img_msg)
|
||||||
|
TEST_CASE_DECL(boot_serial_upload_bigger_image)
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_uart_write(const char *str, int len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct boot_uart_funcs test_uart = {
|
||||||
|
.write = test_uart_write
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
tx_msg(void *src, int len)
|
||||||
|
{
|
||||||
|
boot_serial_input(src, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_SUITE(boot_serial_suite)
|
||||||
|
{
|
||||||
|
boot_serial_setup();
|
||||||
|
boot_serial_empty_msg();
|
||||||
|
boot_serial_empty_img_msg();
|
||||||
|
boot_serial_img_msg();
|
||||||
|
boot_serial_upload_bigger_image();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_serial_test(void)
|
||||||
|
{
|
||||||
|
boot_uf = &test_uart;
|
||||||
|
boot_serial_suite();
|
||||||
|
return tu_any_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MYNEWT_VAL(SELFTEST)
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
sysinit();
|
||||||
|
|
||||||
|
boot_serial_test();
|
||||||
|
|
||||||
|
return tu_any_failed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
50
bootloader/mcuboot/boot/boot_serial/test/src/boot_test.h
Normal file
50
bootloader/mcuboot/boot/boot_serial/test/src/boot_test.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
#ifndef _BOOT_TEST_H
|
||||||
|
#define _BOOT_TEST_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "syscfg/syscfg.h"
|
||||||
|
#include "sysflash/sysflash.h"
|
||||||
|
#include "os/endian.h"
|
||||||
|
#include "base64/base64.h"
|
||||||
|
#include "crc/crc16.h"
|
||||||
|
#include "testutil/testutil.h"
|
||||||
|
#include "hal/hal_flash.h"
|
||||||
|
#include "flash_map_backend/flash_map_backend.h"
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
|
||||||
|
#include "boot_serial_priv.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void tx_msg(void *src, int len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _BOOT_TEST_H */
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
#include "boot_test.h"
|
||||||
|
|
||||||
|
TEST_CASE(boot_serial_empty_img_msg)
|
||||||
|
{
|
||||||
|
char buf[sizeof(struct nmgr_hdr) + 32];
|
||||||
|
struct nmgr_hdr *hdr;
|
||||||
|
|
||||||
|
hdr = (struct nmgr_hdr *)buf;
|
||||||
|
memset(hdr, 0, sizeof(*hdr));
|
||||||
|
hdr->nh_op = NMGR_OP_WRITE;
|
||||||
|
hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
|
||||||
|
hdr->nh_id = IMGMGR_NMGR_ID_UPLOAD;
|
||||||
|
hdr->nh_len = htons(2);
|
||||||
|
strcpy((char *)(hdr + 1), "{}");
|
||||||
|
|
||||||
|
tx_msg(buf, sizeof(*hdr) + 2);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
#include "boot_test.h"
|
||||||
|
|
||||||
|
TEST_CASE(boot_serial_empty_msg)
|
||||||
|
{
|
||||||
|
char buf[4];
|
||||||
|
struct nmgr_hdr hdr;
|
||||||
|
|
||||||
|
tx_msg(buf, 0);
|
||||||
|
|
||||||
|
strcpy(buf, "--");
|
||||||
|
tx_msg(buf, 2);
|
||||||
|
|
||||||
|
memset(&hdr, 0, sizeof(hdr));
|
||||||
|
tx_msg(&hdr, sizeof(hdr));
|
||||||
|
|
||||||
|
hdr.nh_op = NMGR_OP_WRITE;
|
||||||
|
|
||||||
|
tx_msg(&hdr, sizeof(hdr));
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "boot_test.h"
|
||||||
|
|
||||||
|
TEST_CASE(boot_serial_img_msg)
|
||||||
|
{
|
||||||
|
char img[16];
|
||||||
|
char enc_img[BASE64_ENCODE_SIZE(sizeof(img)) + 1];
|
||||||
|
char buf[sizeof(struct nmgr_hdr) + sizeof(enc_img) + 32];
|
||||||
|
int len;
|
||||||
|
int rc;
|
||||||
|
struct nmgr_hdr *hdr;
|
||||||
|
const struct flash_area *fap;
|
||||||
|
|
||||||
|
/* 00000000 a3 64 64 61 74 61 58 10 |.ddataX.|
|
||||||
|
* 00000008 a5 a5 a5 a5 a5 a5 a5 a5 |........|
|
||||||
|
* 00000010 a5 a5 a5 a5 a5 a5 a5 a5 |........|
|
||||||
|
* 00000018 63 6c 65 6e 1a 00 01 14 |clen....|
|
||||||
|
* 00000020 e8 63 6f 66 66 00 |.coff.|
|
||||||
|
*/
|
||||||
|
static const uint8_t payload[] = {
|
||||||
|
0xa3, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x10,
|
||||||
|
/* 16 bytes of image data starts here. */
|
||||||
|
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
|
||||||
|
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
|
||||||
|
0x63, 0x6c, 0x65, 0x6e, 0x1a, 0x00, 0x01, 0x14,
|
||||||
|
0xe8, 0x63, 0x6f, 0x66, 0x66, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
memset(img, 0xa5, sizeof(img));
|
||||||
|
|
||||||
|
hdr = (struct nmgr_hdr *)buf;
|
||||||
|
memset(hdr, 0, sizeof(*hdr));
|
||||||
|
hdr->nh_op = NMGR_OP_WRITE;
|
||||||
|
hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
|
||||||
|
hdr->nh_id = IMGMGR_NMGR_ID_UPLOAD;
|
||||||
|
|
||||||
|
memcpy(hdr + 1, payload, sizeof payload);
|
||||||
|
hdr->nh_len = htons(sizeof payload);
|
||||||
|
|
||||||
|
len = sizeof(*hdr) + sizeof payload;
|
||||||
|
tx_msg(buf, len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate contents inside the primary slot
|
||||||
|
*/
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = flash_area_read(fap, 0, enc_img, sizeof(img));
|
||||||
|
assert(rc == 0);
|
||||||
|
assert(!memcmp(enc_img, img, sizeof(img)));
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
#include "boot_test.h"
|
||||||
|
|
||||||
|
TEST_CASE(boot_serial_setup)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <flash_map_backend/flash_map_backend.h>
|
||||||
|
|
||||||
|
#include "boot_test.h"
|
||||||
|
#include "zcbor_common.h"
|
||||||
|
|
||||||
|
TEST_CASE(boot_serial_upload_bigger_image)
|
||||||
|
{
|
||||||
|
char img[256];
|
||||||
|
char enc_img[64];
|
||||||
|
char buf[sizeof(struct nmgr_hdr) + 128];
|
||||||
|
int len;
|
||||||
|
int off;
|
||||||
|
int rc;
|
||||||
|
struct nmgr_hdr *hdr;
|
||||||
|
const struct flash_area *fap;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
const int payload_off = sizeof *hdr;
|
||||||
|
const int img_data_off = payload_off + 8;
|
||||||
|
|
||||||
|
/* 00000000 a3 64 64 61 74 61 58 20 |.ddataX.|
|
||||||
|
* 00000008 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000010 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000018 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000020 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000028 63 6c 65 6e 1a 00 01 14 |clen....|
|
||||||
|
* 00000030 e8 63 6f 66 66 00 |.coff.|
|
||||||
|
*/
|
||||||
|
static const uint8_t payload_first[] = {
|
||||||
|
0xa3, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x20,
|
||||||
|
/* 32 bytes of image data starts here. */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x63, 0x6c, 0x65, 0x6e, 0x1a, 0x00, 0x01, 0x14,
|
||||||
|
0xe8, 0x63, 0x6f, 0x66, 0x66, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 00000000 a3 64 64 61 74 61 58 20 |.ddataX.|
|
||||||
|
* 00000008 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000010 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000018 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000020 00 00 00 00 00 00 00 00 |........|
|
||||||
|
* 00000028 63 6f 66 66 00 00 |coff..|
|
||||||
|
*/
|
||||||
|
static const uint8_t payload_next[] = {
|
||||||
|
0xa2, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x20,
|
||||||
|
/* 32 bytes of image data starts here. */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x63, 0x6f, 0x66, 0x66,
|
||||||
|
/* 2 bytes of offset value starts here. */
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(img); i++) {
|
||||||
|
img[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (off = 0; off < sizeof(img); off += 32) {
|
||||||
|
hdr = (struct nmgr_hdr *)buf;
|
||||||
|
memset(hdr, 0, sizeof(*hdr));
|
||||||
|
hdr->nh_op = NMGR_OP_WRITE;
|
||||||
|
hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
|
||||||
|
hdr->nh_id = IMGMGR_NMGR_ID_UPLOAD;
|
||||||
|
|
||||||
|
if (off) {
|
||||||
|
memcpy(buf + payload_off, payload_next, sizeof payload_next);
|
||||||
|
len = sizeof payload_next;
|
||||||
|
buf[payload_off + len - 2] = ZCBOR_VALUE_IS_1_BYTE;
|
||||||
|
buf[payload_off + len - 1] = off;
|
||||||
|
} else {
|
||||||
|
memcpy(buf + payload_off, payload_first, sizeof payload_first);
|
||||||
|
len = sizeof payload_first;
|
||||||
|
}
|
||||||
|
memcpy(buf + img_data_off, img + off, 32);
|
||||||
|
hdr->nh_len = htons(len);
|
||||||
|
|
||||||
|
len = sizeof(*hdr) + len;
|
||||||
|
|
||||||
|
tx_msg(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate contents inside the primary slot
|
||||||
|
*/
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
for (off = 0; off < sizeof(img); off += sizeof(enc_img)) {
|
||||||
|
rc = flash_area_read(fap, off, enc_img, sizeof(enc_img));
|
||||||
|
assert(rc == 0);
|
||||||
|
assert(!memcmp(enc_img, &img[off], sizeof(enc_img)));
|
||||||
|
}
|
||||||
|
}
|
||||||
23
bootloader/mcuboot/boot/boot_serial/test/syscfg.yml
Normal file
23
bootloader/mcuboot/boot/boot_serial/test/syscfg.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Package: boot/boot_serial/test
|
||||||
|
|
||||||
|
syscfg.vals:
|
||||||
|
# This is here to work around the $notnull syscfg restriction.
|
||||||
|
BOOT_SERIAL_DETECT_PIN: 0
|
||||||
35
bootloader/mcuboot/boot/bootutil/CMakeLists.txt
Normal file
35
bootloader/mcuboot/boot/bootutil/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) 2020-2023, Arm Limited. All rights reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
add_library(bootutil STATIC)
|
||||||
|
|
||||||
|
target_include_directories(bootutil
|
||||||
|
PUBLIC
|
||||||
|
include
|
||||||
|
PRIVATE
|
||||||
|
src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(bootutil
|
||||||
|
PRIVATE
|
||||||
|
src/boot_record.c
|
||||||
|
src/bootutil_misc.c
|
||||||
|
src/bootutil_public.c
|
||||||
|
src/caps.c
|
||||||
|
src/encrypted.c
|
||||||
|
src/fault_injection_hardening.c
|
||||||
|
src/fault_injection_hardening_delay_rng_mbedtls.c
|
||||||
|
src/image_ecdsa.c
|
||||||
|
src/image_ed25519.c
|
||||||
|
src/image_rsa.c
|
||||||
|
src/image_validate.c
|
||||||
|
src/loader.c
|
||||||
|
src/swap_misc.c
|
||||||
|
src/swap_move.c
|
||||||
|
src/swap_scratch.c
|
||||||
|
src/tlv.c
|
||||||
|
)
|
||||||
68
bootloader/mcuboot/boot/bootutil/include/bootutil/bench.h
Normal file
68
bootloader/mcuboot/boot/bootutil/include/bootutil/bench.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Linaro Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_BENCH_H__
|
||||||
|
#define H_BOOTUTIL_BENCH_H__
|
||||||
|
|
||||||
|
#include "ignore.h"
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_USE_BENCH
|
||||||
|
|
||||||
|
/* The platform-specific benchmark code should define a
|
||||||
|
* `bench_state_t` type that holds the information needed for the
|
||||||
|
* benchmark. This is generally something small, such as an integer
|
||||||
|
* holding the state. This should also define plat_bench_start and
|
||||||
|
* plat_bench_end, which likely have to be macros so that log messages
|
||||||
|
* come from the right place in the code. */
|
||||||
|
#include <platform-bench.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are simple barrier-type benchmarks. If a platform has
|
||||||
|
* benchmarks that are enabled, calling `boot_bench_start()` before a
|
||||||
|
* block of code and `boot_bench_stop()` after that block of code will
|
||||||
|
* present this information in some manner (usually through logging).
|
||||||
|
* The details of what is measured and how it is printed are specific
|
||||||
|
* to the platform and the implementation. A pointer to the
|
||||||
|
* platform-specific state should be passed in.
|
||||||
|
*/
|
||||||
|
#define boot_bench_start(_state) do { \
|
||||||
|
plat_bench_start(_state); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define boot_bench_stop(_state) do { \
|
||||||
|
plat_bench_stop(_state); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else /* not MCUBOOT_USE_BENCH */
|
||||||
|
|
||||||
|
/* The type needs to take space. As long as it remains unused, the C
|
||||||
|
* compiler should eliminate this value entirely. */
|
||||||
|
typedef int bench_state_t;
|
||||||
|
|
||||||
|
/* Without benchmarking enabled, these are just empty. */
|
||||||
|
#define boot_bench_start(_state) do { \
|
||||||
|
IGNORE(_state); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define boot_bench_stop(_state) do { \
|
||||||
|
IGNORE(_state); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif /* not MCUBOOT_USE_BENCH */
|
||||||
|
|
||||||
|
#endif /* not H_BOOTUTIL_BENCH_H__ */
|
||||||
181
bootloader/mcuboot/boot/bootutil/include/bootutil/boot_hooks.h
Normal file
181
bootloader/mcuboot/boot/bootutil/include/bootutil/boot_hooks.h
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Hooks definition implementation API
|
||||||
|
*
|
||||||
|
* This file contains API interface definition for hooks which can be
|
||||||
|
* implemented to overide or to amend some of MCUboot's native routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_HOOKS
|
||||||
|
#define H_BOOTUTIL_HOOKS
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_IMAGE_ACCESS_HOOKS
|
||||||
|
|
||||||
|
#define BOOT_HOOK_CALL(f, ret_default, ...) f(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \
|
||||||
|
do { \
|
||||||
|
FIH_CALL(f, fih_rc, __VA_ARGS__); \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define BOOT_HOOK_CALL(f, ret_default, ...) ret_default
|
||||||
|
|
||||||
|
#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \
|
||||||
|
do { \
|
||||||
|
fih_rc = fih_ret_default; \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Hook for provide image header data.
|
||||||
|
*
|
||||||
|
* This Hook may be used to overide image header read implementation or doing
|
||||||
|
* a custom action before.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param slot slot number
|
||||||
|
* @param img_head image header structure to be populated
|
||||||
|
*
|
||||||
|
* @retval 0: header was read/populated, skip direct header data read
|
||||||
|
* BOOT_HOOK_REGULAR: follow the normal execution path,
|
||||||
|
* otherwise an error-code value.
|
||||||
|
*/
|
||||||
|
int boot_read_image_header_hook(int img_index, int slot,
|
||||||
|
struct image_header *img_head);
|
||||||
|
|
||||||
|
/** Hook for Validate image hash/signature
|
||||||
|
*
|
||||||
|
* This Hook may be used to overide image validation procedure or doing
|
||||||
|
* a custom action before.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param slot slot number
|
||||||
|
*
|
||||||
|
* @retval FIH_SUCCESS: image is valid, skip direct validation
|
||||||
|
* FIH_FAILURE: image is invalid, skip direct validation
|
||||||
|
* FIH_BOOT_HOOK_REGULAR: follow the normal execution path.
|
||||||
|
*/
|
||||||
|
fih_ret boot_image_check_hook(int img_index, int slot);
|
||||||
|
|
||||||
|
/** Hook for implement image update
|
||||||
|
*
|
||||||
|
* This hook is for for implementing an alternative mechanism of image update or
|
||||||
|
* doing a custom action before.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param img_head the image header of the secondary image
|
||||||
|
* @param area the flash area of the secondary image.
|
||||||
|
*
|
||||||
|
* @retval 0: update was done, skip performing the update
|
||||||
|
* BOOT_HOOK_REGULAR: follow the normal execution path,
|
||||||
|
* otherwise an error-code value.
|
||||||
|
*/
|
||||||
|
int boot_perform_update_hook(int img_index, struct image_header *img_head,
|
||||||
|
const struct flash_area *area);
|
||||||
|
|
||||||
|
/** Hook for implement image's post copying action
|
||||||
|
*
|
||||||
|
* This hook is for implement action which might be done right after image was
|
||||||
|
* copied to the primary slot. This hook is called in MCUBOOT_OVERWRITE_ONLY
|
||||||
|
* mode only.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param area the flash area of the primary image.
|
||||||
|
* @param size size of copied image.
|
||||||
|
*
|
||||||
|
* @retval 0: success, mcuboot will follow normal code execution flow after
|
||||||
|
* execution of this call.
|
||||||
|
* non-zero: an error, mcuboot will return from
|
||||||
|
* boot_copy_image() with error.
|
||||||
|
* Update will be undone so might be resume on the next boot.
|
||||||
|
*/
|
||||||
|
int boot_copy_region_post_hook(int img_index, const struct flash_area *area,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
/** Hook for implement image's post recovery upload action
|
||||||
|
*
|
||||||
|
* This hook is for implement action which might be done right after image was
|
||||||
|
* copied to the primary slot. This hook is called in serial recovery upload
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param area the flash area of the primary image.
|
||||||
|
* @param size size of copied image.
|
||||||
|
*
|
||||||
|
* @retval 0: success, mcuboot will follow normal code execution flow after
|
||||||
|
* execution of this call.
|
||||||
|
* non-zero: an error, will be transferred as part of comand response
|
||||||
|
* as "rc" entry.
|
||||||
|
*/
|
||||||
|
int boot_serial_uploaded_hook(int img_index, const struct flash_area *area,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
/** Hook for implement the image's slot installation status fetch operation for
|
||||||
|
* the MGMT custom command.
|
||||||
|
*
|
||||||
|
* The image's slot installation status is custom property. It's detailed
|
||||||
|
* definition depends on user implementation. It is only defined that the status
|
||||||
|
* will be set to 0 if this hook not provides another value.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param slot slot number
|
||||||
|
* @param img_install_stat the image installation status to be populated
|
||||||
|
*
|
||||||
|
* @retval 0: the installaton status was fetched successfully,
|
||||||
|
* BOOT_HOOK_REGULAR: follow the normal execution path, status will be
|
||||||
|
* set to 0
|
||||||
|
* otherwise an error-code value. Error-code is ignored, but it is up to
|
||||||
|
* the implementation to reflect this error in img_install_stat.
|
||||||
|
*/
|
||||||
|
int boot_img_install_stat_hook(int image_index, int slot,
|
||||||
|
int *img_install_stat);
|
||||||
|
|
||||||
|
/** Hook will be invoked when boot_serial requests device reset.
|
||||||
|
* The hook may be used to prevent device reset.
|
||||||
|
*
|
||||||
|
* @param force set to true when request tries to force reset.
|
||||||
|
*
|
||||||
|
* @retval 0 when reset should be performed;
|
||||||
|
* BOOT_RESET_REQUEST_HOOK_BUSY when some processing is still in
|
||||||
|
* progress;
|
||||||
|
* BOOT_RESET_REQUEST_HOOK_TIMEOUT internal process timed out;
|
||||||
|
* BOOT_RESET_REQUEST_HOOK_CHECK_FAILED internal code failed to
|
||||||
|
* obtian status;
|
||||||
|
* BOOT_RESET_REQUEST_HOOK_INTERNAL_ERROR unspecified internal
|
||||||
|
* error while checking status.
|
||||||
|
*/
|
||||||
|
int boot_reset_request_hook(bool force);
|
||||||
|
|
||||||
|
#define BOOT_RESET_REQUEST_HOOK_BUSY 1
|
||||||
|
#define BOOT_RESET_REQUEST_HOOK_TIMEOUT 2
|
||||||
|
#define BOOT_RESET_REQUEST_HOOK_CHECK_FAILED 3
|
||||||
|
#define BOOT_RESET_REQUEST_HOOK_INTERNAL_ERROR 4
|
||||||
|
|
||||||
|
#endif /*H_BOOTUTIL_HOOKS*/
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Hooks definition implementation API
|
||||||
|
*
|
||||||
|
* This file contains API interface definition for hooks which can be
|
||||||
|
* implemented for overide some of MCUboot's native routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_PUBLIC_HOOKS
|
||||||
|
#define H_BOOTUTIL_PUBLIC_HOOKS
|
||||||
|
|
||||||
|
#include "bootutil/boot_hooks.h"
|
||||||
|
|
||||||
|
/** Hook for provide primary image swap state.
|
||||||
|
*
|
||||||
|
* @param img_index the index of the image pair
|
||||||
|
* @param state image swap state structure to be populated
|
||||||
|
*
|
||||||
|
* @retval 0: header was read/populated
|
||||||
|
* FIH_FAILURE: image is invalid,
|
||||||
|
* BOOT_HOOK_REGULAR if hook not implemented for the image-slot,
|
||||||
|
* othervise an error-code value.
|
||||||
|
*/
|
||||||
|
int boot_read_swap_state_primary_slot_hook(int image_index,
|
||||||
|
struct boot_swap_state *state);
|
||||||
|
|
||||||
|
#endif /*H_BOOTUTIL_PUBLIC_HOOKS*/
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2021 Arm Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOT_RECORD_H__
|
||||||
|
#define __BOOT_RECORD_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Error codes for using the shared memory area. */
|
||||||
|
enum shared_memory_status {
|
||||||
|
SHARED_MEMORY_OK = 0,
|
||||||
|
SHARED_MEMORY_OVERFLOW,
|
||||||
|
SHARED_MEMORY_OVERWRITE,
|
||||||
|
SHARED_MEMORY_GEN_ERROR,
|
||||||
|
SHARED_MEMORY_WRITE_ERROR,
|
||||||
|
SHARED_MEMORY_READ_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a data item to the shared data area between bootloader and
|
||||||
|
* runtime SW
|
||||||
|
*
|
||||||
|
* @param[in] major_type TLV major type, identify consumer
|
||||||
|
* @param[in] minor_type TLV minor type, identify TLV type
|
||||||
|
* @param[in] size length of added data
|
||||||
|
* @param[in] data pointer to data
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_add_data_to_shared_area(uint8_t major_type,
|
||||||
|
uint16_t minor_type,
|
||||||
|
size_t size,
|
||||||
|
const uint8_t *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an image's all boot status information to the shared memory area
|
||||||
|
* between the bootloader and runtime SW.
|
||||||
|
*
|
||||||
|
* @param[in] sw_module Identifier of the SW component.
|
||||||
|
* @param[in] hdr Pointer to the image header stored in RAM.
|
||||||
|
* @param[in] fap Pointer to the flash area where image is stored.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_save_boot_status(uint8_t sw_module,
|
||||||
|
const struct image_header *hdr,
|
||||||
|
const struct flash_area *fap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add application specific data to the shared memory area between the
|
||||||
|
* bootloader and runtime SW.
|
||||||
|
*
|
||||||
|
* @param[in] hdr Pointer to the image header stored in RAM.
|
||||||
|
* @param[in] fap Pointer to the flash area where image is stored.
|
||||||
|
* @param[in] slot The currently active slot being booted.
|
||||||
|
* @param[in] max_app_sizes The maximum sizes of images that can be loaded.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_save_shared_data(const struct image_header *hdr,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
const uint8_t active_slot,
|
||||||
|
const struct image_max_size *max_app_sizes);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOT_RECORD_H__ */
|
||||||
188
bootloader/mcuboot/boot/bootutil/include/bootutil/boot_status.h
Normal file
188
bootloader/mcuboot/boot/bootutil/include/bootutil/boot_status.h
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Arm Limited
|
||||||
|
* Copyright (c) 2020 Linaro Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOT_STATUS_H__
|
||||||
|
#define __BOOT_STATUS_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The shared data between boot loader and runtime SW is TLV encoded. The
|
||||||
|
* shared data is stored in a well known location in memory and this is a
|
||||||
|
* contract between boot loader and runtime SW.
|
||||||
|
*
|
||||||
|
* The structure of shared data must be the following:
|
||||||
|
* - At the beginning there must be a header: struct shared_data_tlv_header
|
||||||
|
* This contains a magic number and a size field which covers the entire
|
||||||
|
* size of the shared data area including this header.
|
||||||
|
* - After the header there come the entries which are composed from an entry
|
||||||
|
* header structure: struct shared_data_tlv_entry and the data. In the entry
|
||||||
|
* header is a type field (tly_type) which identify the consumer of the
|
||||||
|
* entry in the runtime SW and specify the subtype of that data item. There
|
||||||
|
* is a size field (tlv_len) which covers the size of the the data. After
|
||||||
|
* this structure comes the actual data.
|
||||||
|
*
|
||||||
|
* - Arbitrary number and size of data entry can be in the shared memory area.
|
||||||
|
*
|
||||||
|
* This table gives of overview about the tlv_type field in the entry header.
|
||||||
|
* The tlv_type always composed from a major and minor number. Major number
|
||||||
|
* identifies the addressee in runtime SW, who should process the data entry.
|
||||||
|
* Minor number used to encode more info about the data entry. The actual
|
||||||
|
* definition of minor number could change per major number.
|
||||||
|
*
|
||||||
|
* In case of boot status data, which can be processed by an attestation
|
||||||
|
* service the minor number is split further to two part: sw_module and claim.
|
||||||
|
* The sw_module identifies the SW component in the system which the data item
|
||||||
|
* belongs to and the claim part identifies the exact type of the data.
|
||||||
|
*
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | tlv_type (16) |
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | tlv_major(4)| tlv_minor(12) |
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | MAJOR_IAS | sw_module(6) | claim(6) |
|
||||||
|
* |---------------------------------------|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* General macros to handle TLV type */
|
||||||
|
#define MAJOR_MASK 0xF /* 4 bit */
|
||||||
|
#define MAJOR_POS 12 /* 12 bit */
|
||||||
|
#define MINOR_MASK 0xFFF /* 12 bit */
|
||||||
|
|
||||||
|
#define SET_TLV_TYPE(major, minor) \
|
||||||
|
(((uint16_t)((major) & MAJOR_MASK) << MAJOR_POS) \
|
||||||
|
| ((minor) & MINOR_MASK))
|
||||||
|
#define GET_MAJOR(tlv_type) ((uint16_t)(tlv_type) >> MAJOR_POS)
|
||||||
|
#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK)
|
||||||
|
|
||||||
|
/* Magic value which marks the beginning of shared data area in memory */
|
||||||
|
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
|
||||||
|
|
||||||
|
/* Initial attestation specific macros */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Major numbers (4 bit) to identify the
|
||||||
|
* consumer of shared data in runtime SW.
|
||||||
|
*/
|
||||||
|
#define TLV_MAJOR_IAS 0x1
|
||||||
|
#define TLV_MAJOR_BLINFO 0x2
|
||||||
|
|
||||||
|
/* Initial attestation: Claim per SW components / SW modules */
|
||||||
|
/* Bits: 0-2 */
|
||||||
|
#define SW_VERSION 0x00
|
||||||
|
#define SW_SIGNER_ID 0x01
|
||||||
|
/* Reserved 0x02 */
|
||||||
|
#define SW_TYPE 0x03
|
||||||
|
/* Bits: 3-5 */
|
||||||
|
#define SW_MEASURE_VALUE 0x08
|
||||||
|
#define SW_MEASURE_TYPE 0x09
|
||||||
|
#define SW_BOOT_RECORD 0x3F
|
||||||
|
|
||||||
|
#define MODULE_POS 6 /* 6 bit */
|
||||||
|
#define CLAIM_MASK 0x3F /* 6 bit */
|
||||||
|
#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */
|
||||||
|
|
||||||
|
#define GET_IAS_MODULE(tlv_type) ((uint16_t)GET_MINOR(tlv_type) >> MODULE_POS)
|
||||||
|
#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
|
||||||
|
#define SET_IAS_MINOR(sw_module, claim) \
|
||||||
|
(((uint16_t)(sw_module) << MODULE_POS) | (claim))
|
||||||
|
|
||||||
|
/* Bootloader information */
|
||||||
|
#define BLINFO_MODE 0x00
|
||||||
|
#define BLINFO_SIGNATURE_TYPE 0x01
|
||||||
|
#define BLINFO_RECOVERY 0x02
|
||||||
|
#define BLINFO_RUNNING_SLOT 0x03
|
||||||
|
#define BLINFO_BOOTLOADER_VERSION 0x04
|
||||||
|
#define BLINFO_MAX_APPLICATION_SIZE 0x05 /* Same as BLINFO_MAX_APPLICATION_SIZE_IMAGE_0, legacy name */
|
||||||
|
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_0 BLINFO_MAX_APPLICATION_SIZE
|
||||||
|
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_1 0x06
|
||||||
|
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_2 0x07
|
||||||
|
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_3 0x08
|
||||||
|
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_4 0x09
|
||||||
|
|
||||||
|
enum mcuboot_mode {
|
||||||
|
MCUBOOT_MODE_SINGLE_SLOT,
|
||||||
|
MCUBOOT_MODE_SWAP_USING_SCRATCH,
|
||||||
|
MCUBOOT_MODE_UPGRADE_ONLY,
|
||||||
|
MCUBOOT_MODE_SWAP_USING_MOVE,
|
||||||
|
MCUBOOT_MODE_DIRECT_XIP,
|
||||||
|
MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT,
|
||||||
|
MCUBOOT_MODE_RAM_LOAD,
|
||||||
|
MCUBOOT_MODE_FIRMWARE_LOADER
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mcuboot_signature_type {
|
||||||
|
MCUBOOT_SIGNATURE_TYPE_NONE,
|
||||||
|
MCUBOOT_SIGNATURE_TYPE_RSA,
|
||||||
|
MCUBOOT_SIGNATURE_TYPE_ECDSA_P256,
|
||||||
|
MCUBOOT_SIGNATURE_TYPE_ED25519
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mcuboot_recovery_mode {
|
||||||
|
MCUBOOT_RECOVERY_MODE_NONE,
|
||||||
|
MCUBOOT_RECOVERY_MODE_SERIAL_RECOVERY,
|
||||||
|
MCUBOOT_RECOVERY_MODE_DFU,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared data TLV header. All fields in little endian.
|
||||||
|
*
|
||||||
|
* -----------------------------------
|
||||||
|
* | tlv_magic(16) | tlv_tot_len(16) |
|
||||||
|
* -----------------------------------
|
||||||
|
*/
|
||||||
|
struct shared_data_tlv_header {
|
||||||
|
uint16_t tlv_magic;
|
||||||
|
uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared data TLV entry header format. All fields in little endian.
|
||||||
|
*
|
||||||
|
* -------------------------------
|
||||||
|
* | tlv_type(16) | tlv_len(16) |
|
||||||
|
* -------------------------------
|
||||||
|
* | Raw data |
|
||||||
|
* -------------------------------
|
||||||
|
*/
|
||||||
|
struct shared_data_tlv_entry {
|
||||||
|
uint16_t tlv_type;
|
||||||
|
uint16_t tlv_len; /* TLV data length (not including this header). */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry)
|
||||||
|
#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE)
|
||||||
|
|
||||||
|
/* Structure to store the boot data for the runtime SW. */
|
||||||
|
struct shared_boot_data {
|
||||||
|
struct shared_data_tlv_header header;
|
||||||
|
uint8_t data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOT_STATUS_H__ */
|
||||||
104
bootloader/mcuboot/boot/bootutil/include/bootutil/bootutil.h
Normal file
104
bootloader/mcuboot/boot/bootutil/include/bootutil/bootutil.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2021 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_
|
||||||
|
#define H_BOOTUTIL_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
#include "bootutil/bootutil_public.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_IMAGE_NUMBER
|
||||||
|
#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
|
||||||
|
#else
|
||||||
|
#define BOOT_IMAGE_NUMBER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_Static_assert(BOOT_IMAGE_NUMBER > 0, "Invalid value for BOOT_IMAGE_NUMBER");
|
||||||
|
|
||||||
|
struct image_header;
|
||||||
|
/**
|
||||||
|
* A response object provided by the boot loader code; indicates where to jump
|
||||||
|
* to execute the main image.
|
||||||
|
*/
|
||||||
|
struct boot_rsp {
|
||||||
|
/** A pointer to the header of the image to be executed. */
|
||||||
|
const struct image_header *br_hdr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flash offset of the image to execute. Indicates the position of
|
||||||
|
* the image header within its flash device.
|
||||||
|
*/
|
||||||
|
uint8_t br_flash_dev_id;
|
||||||
|
uint32_t br_image_off;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is not actually used by mcuboot's code but can be used by apps
|
||||||
|
* when attempting to read/write a trailer.
|
||||||
|
*/
|
||||||
|
struct image_trailer {
|
||||||
|
uint8_t swap_type;
|
||||||
|
uint8_t pad1[BOOT_MAX_ALIGN - 1];
|
||||||
|
uint8_t copy_done;
|
||||||
|
uint8_t pad2[BOOT_MAX_ALIGN - 1];
|
||||||
|
uint8_t image_ok;
|
||||||
|
uint8_t pad3[BOOT_MAX_ALIGN - 1];
|
||||||
|
#if BOOT_MAX_ALIGN > BOOT_MAGIC_SZ
|
||||||
|
uint8_t pad4[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ];
|
||||||
|
#endif
|
||||||
|
uint8_t magic[BOOT_MAGIC_SZ];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct image_max_size {
|
||||||
|
bool calculated;
|
||||||
|
uint32_t max_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* you must have pre-allocated all the entries within this structure */
|
||||||
|
fih_ret boot_go(struct boot_rsp *rsp);
|
||||||
|
fih_ret boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id);
|
||||||
|
|
||||||
|
struct boot_loader_state;
|
||||||
|
void boot_state_clear(struct boot_loader_state *state);
|
||||||
|
fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
|
||||||
|
const struct image_max_size *boot_get_max_app_size(void);
|
||||||
|
|
||||||
|
#define SPLIT_GO_OK (0)
|
||||||
|
#define SPLIT_GO_NON_MATCHING (-1)
|
||||||
|
#define SPLIT_GO_ERR (-2)
|
||||||
|
|
||||||
|
fih_ret split_go(int loader_slot, int split_slot, void **entry);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Linaro Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_LOG_H_
|
||||||
|
#define H_BOOTUTIL_LOG_H_
|
||||||
|
|
||||||
|
#include "ignore.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mcuboot_config/mcuboot_config.h>
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_HAVE_LOGGING
|
||||||
|
#include <mcuboot_config/mcuboot_logging.h>
|
||||||
|
|
||||||
|
#define BOOT_LOG_ERR(...) MCUBOOT_LOG_ERR(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_WRN(...) MCUBOOT_LOG_WRN(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_INF(...) MCUBOOT_LOG_INF(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_DBG(...) MCUBOOT_LOG_DBG(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_SIM(...) MCUBOOT_LOG_SIM(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define BOOT_LOG_MODULE_DECLARE(module) MCUBOOT_LOG_MODULE_DECLARE(module)
|
||||||
|
#define BOOT_LOG_MODULE_REGISTER(module) MCUBOOT_LOG_MODULE_REGISTER(module)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define BOOT_LOG_ERR(...) IGNORE(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_WRN(...) IGNORE(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_INF(...) IGNORE(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_DBG(...) IGNORE(__VA_ARGS__)
|
||||||
|
#define BOOT_LOG_SIM(...) IGNORE(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define BOOT_LOG_MODULE_DECLARE(module)
|
||||||
|
#define BOOT_LOG_MODULE_REGISTER(module)
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_HAVE_LOGGING */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2021 Arm Limited
|
||||||
|
* Copyright (c) 2020-2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Public MCUBoot interface API
|
||||||
|
*
|
||||||
|
* This file contains API which can be combined with the application in order
|
||||||
|
* to interact with the MCUBoot bootloader. This API are shared code-base betwen
|
||||||
|
* MCUBoot and the application which controls DFU process.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_PUBLIC
|
||||||
|
#define H_BOOTUTIL_PUBLIC
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <flash_map_backend/flash_map_backend.h>
|
||||||
|
#include <mcuboot_config/mcuboot_config.h>
|
||||||
|
#include <bootutil/image.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ALIGN_UP
|
||||||
|
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ALIGN_DOWN
|
||||||
|
#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Attempt to boot the contents of the primary slot. */
|
||||||
|
#define BOOT_SWAP_TYPE_NONE 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap to the secondary slot.
|
||||||
|
* Absent a confirm command, revert back on next boot.
|
||||||
|
*/
|
||||||
|
#define BOOT_SWAP_TYPE_TEST 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap to the secondary slot,
|
||||||
|
* and permanently switch to booting its contents.
|
||||||
|
*/
|
||||||
|
#define BOOT_SWAP_TYPE_PERM 3
|
||||||
|
|
||||||
|
/** Swap back to alternate slot. A confirm changes this state to NONE. */
|
||||||
|
#define BOOT_SWAP_TYPE_REVERT 4
|
||||||
|
|
||||||
|
/** Swap failed because image to be run is not valid */
|
||||||
|
#define BOOT_SWAP_TYPE_FAIL 5
|
||||||
|
|
||||||
|
/** Swapping encountered an unrecoverable error */
|
||||||
|
#define BOOT_SWAP_TYPE_PANIC 0xff
|
||||||
|
|
||||||
|
#define BOOT_MAGIC_SZ 16
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_BOOT_MAX_ALIGN
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
|
||||||
|
_Static_assert(MCUBOOT_BOOT_MAX_ALIGN >= 8 && MCUBOOT_BOOT_MAX_ALIGN <= 32,
|
||||||
|
"Unsupported value for MCUBOOT_BOOT_MAX_ALIGN for SWAP upgrade modes");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOT_MAX_ALIGN MCUBOOT_BOOT_MAX_ALIGN
|
||||||
|
#define BOOT_MAGIC_ALIGN_SIZE ALIGN_UP(BOOT_MAGIC_SZ, BOOT_MAX_ALIGN)
|
||||||
|
#else
|
||||||
|
#define BOOT_MAX_ALIGN 8
|
||||||
|
#define BOOT_MAGIC_ALIGN_SIZE BOOT_MAGIC_SZ
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOT_MAGIC_GOOD 1
|
||||||
|
#define BOOT_MAGIC_BAD 2
|
||||||
|
#define BOOT_MAGIC_UNSET 3
|
||||||
|
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
|
||||||
|
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash!
|
||||||
|
*/
|
||||||
|
#define BOOT_FLAG_SET 1
|
||||||
|
#define BOOT_FLAG_BAD 2
|
||||||
|
#define BOOT_FLAG_UNSET 3
|
||||||
|
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
|
||||||
|
|
||||||
|
#define BOOT_EFLASH 1
|
||||||
|
#define BOOT_EFILE 2
|
||||||
|
#define BOOT_EBADIMAGE 3
|
||||||
|
#define BOOT_EBADVECT 4
|
||||||
|
#define BOOT_EBADSTATUS 5
|
||||||
|
#define BOOT_ENOMEM 6
|
||||||
|
#define BOOT_EBADARGS 7
|
||||||
|
#define BOOT_EBADVERSION 8
|
||||||
|
#define BOOT_EFLASH_SEC 9
|
||||||
|
|
||||||
|
#define BOOT_HOOK_REGULAR 1
|
||||||
|
/*
|
||||||
|
* Extract the swap type and image number from image trailers's swap_info
|
||||||
|
* filed.
|
||||||
|
*/
|
||||||
|
#define BOOT_GET_SWAP_TYPE(swap_info) ((swap_info) & 0x0F)
|
||||||
|
#define BOOT_GET_IMAGE_NUM(swap_info) ((swap_info) >> 4)
|
||||||
|
|
||||||
|
/* Construct the swap_info field from swap type and image number */
|
||||||
|
#define BOOT_SET_SWAP_INFO(swap_info, image, type) { \
|
||||||
|
assert((image) < 0xF); \
|
||||||
|
assert((type) < 0xF); \
|
||||||
|
(swap_info) = (image) << 4 \
|
||||||
|
| (type); \
|
||||||
|
}
|
||||||
|
#ifdef MCUBOOT_HAVE_ASSERT_H
|
||||||
|
#include "mcuboot_config/mcuboot_assert.h"
|
||||||
|
#else
|
||||||
|
#include <assert.h>
|
||||||
|
#ifndef ASSERT
|
||||||
|
#define ASSERT assert
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct boot_swap_state {
|
||||||
|
uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
|
||||||
|
uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */
|
||||||
|
uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
|
||||||
|
uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
|
||||||
|
uint8_t image_num; /* Boot status belongs to this image */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determines the action, if any, that mcuboot will take on a image pair.
|
||||||
|
*
|
||||||
|
* @param image_index Image pair index.
|
||||||
|
*
|
||||||
|
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
|
||||||
|
* fail.
|
||||||
|
*/
|
||||||
|
int boot_swap_type_multi(int image_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determines the action, if any, that mcuboot will take.
|
||||||
|
*
|
||||||
|
* Works the same as a boot_swap_type_multi(0) call;
|
||||||
|
*
|
||||||
|
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
|
||||||
|
* fail.
|
||||||
|
*/
|
||||||
|
int boot_swap_type(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with the given index in the secondary slot as pending. On the
|
||||||
|
* next reboot, the system will perform a one-time boot of the the secondary
|
||||||
|
* slot image.
|
||||||
|
*
|
||||||
|
* @param image_index Image pair index.
|
||||||
|
*
|
||||||
|
* @param permanent Whether the image should be used permanently or
|
||||||
|
* only tested once:
|
||||||
|
* 0=run image once, then confirm or revert.
|
||||||
|
* 1=run image forever.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_set_pending_multi(int image_index, int permanent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with index 0 in the secondary slot as pending. On the next
|
||||||
|
* reboot, the system will perform a one-time boot of the the secondary slot
|
||||||
|
* image. Note that this API is kept for compatibility. The
|
||||||
|
* boot_set_pending_multi() API is recommended.
|
||||||
|
*
|
||||||
|
* @param permanent Whether the image should be used permanently or
|
||||||
|
* only tested once:
|
||||||
|
* 0=run image once, then confirm or revert.
|
||||||
|
* 1=run image forever.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_set_pending(int permanent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with the given index in the primary slot as confirmed. The
|
||||||
|
* system will continue booting into the image in the primary slot until told to
|
||||||
|
* boot from a different slot.
|
||||||
|
*
|
||||||
|
* @param image_index Image pair index.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_set_confirmed_multi(int image_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with index 0 in the primary slot as confirmed. The system
|
||||||
|
* will continue booting into the image in the primary slot until told to boot
|
||||||
|
* from a different slot. Note that this API is kept for compatibility. The
|
||||||
|
* boot_set_confirmed_multi() API is recommended.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_set_confirmed(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get offset of the swap info field in the image trailer.
|
||||||
|
*
|
||||||
|
* @param fap Flash are for which offset is determined.
|
||||||
|
*
|
||||||
|
* @retval offset of the swap info field.
|
||||||
|
*/
|
||||||
|
uint32_t boot_swap_info_off(const struct flash_area *fap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get value of image-ok flag of the image.
|
||||||
|
*
|
||||||
|
* If called from chin-loaded image the image-ok flag value can be used to check
|
||||||
|
* whether application itself is already confirmed.
|
||||||
|
*
|
||||||
|
* @param fap Flash area of the image.
|
||||||
|
* @param image_ok[out] image-ok value.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the image swap state
|
||||||
|
*
|
||||||
|
* @param flash_area_id id of flash partition from which state will be read;
|
||||||
|
* @param state pointer to structure for storing swap state.
|
||||||
|
*
|
||||||
|
* @return 0 on success; non-zero error code on failure;
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the image swap state
|
||||||
|
*
|
||||||
|
* @param fa pointer to flash_area object;
|
||||||
|
* @param state pointer to structure for storing swap state.
|
||||||
|
*
|
||||||
|
* @return 0 on success; non-zero error code on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_read_swap_state(const struct flash_area *fa,
|
||||||
|
struct boot_swap_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set next image application slot by flash area pointer
|
||||||
|
*
|
||||||
|
* @param fa pointer to flash_area representing image to set for next boot;
|
||||||
|
* @param active should be true if @fa points to currently running image
|
||||||
|
* slot, false otherwise;
|
||||||
|
* @param confirm confirms image; when @p active is true, this is considered
|
||||||
|
* true, regardless of passed value.
|
||||||
|
*
|
||||||
|
* It is users responsibility to identify whether @p fa provided as parameter
|
||||||
|
* is currently running/active image and provide proper value to @p active.
|
||||||
|
* Failing to do so may render device non-upgradeable.
|
||||||
|
*
|
||||||
|
* Note that in multi-image setup running/active application is the one
|
||||||
|
* that is currently being executed by any MCU core, from the pair of
|
||||||
|
* slots dedicated to that MCU core. As confirming application currently
|
||||||
|
* running on a given slot should be, preferably, done after functional
|
||||||
|
* tests prove application to function correctly, it may not be a good idea
|
||||||
|
* to cross-confirm running images.
|
||||||
|
* An application should only confirm slots designated to MCU core it is
|
||||||
|
* running on.
|
||||||
|
*
|
||||||
|
* @return 0 on success; non-zero error code on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_set_next(const struct flash_area *fa, bool active, bool confirm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to load image header from flash; verifies flash header fields.
|
||||||
|
*
|
||||||
|
* @param[in] fa_p flash area pointer
|
||||||
|
* @param[out] hdr buffer for image header
|
||||||
|
*
|
||||||
|
* @return 0 on success, error code otherwise
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_image_load_header(const struct flash_area *fa_p,
|
||||||
|
struct image_header *hdr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_TEST_
|
||||||
|
#define H_BOOTUTIL_TEST_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int boot_test_all(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
67
bootloader/mcuboot/boot/bootutil/include/bootutil/caps.h
Normal file
67
bootloader/mcuboot/boot/bootutil/include/bootutil/caps.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Linaro Limited
|
||||||
|
* Copyright (c) 2021-2023 Arm Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_CAPS_H_
|
||||||
|
#define H_BOOTUTIL_CAPS_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The bootloader can be compile with different capabilities selected
|
||||||
|
* at compile time. This function provides runtime access to these
|
||||||
|
* capabilities. This is intended primarily for testing, although
|
||||||
|
* these will possibly be available at runtime to the application
|
||||||
|
* running within the bootloader.
|
||||||
|
*/
|
||||||
|
uint32_t bootutil_get_caps(void);
|
||||||
|
|
||||||
|
#define BOOTUTIL_CAP_RSA2048 (1<<0)
|
||||||
|
/* reserved (1<<1) */
|
||||||
|
#define BOOTUTIL_CAP_ECDSA_P256 (1<<2)
|
||||||
|
#define BOOTUTIL_CAP_SWAP_USING_SCRATCH (1<<3)
|
||||||
|
#define BOOTUTIL_CAP_OVERWRITE_UPGRADE (1<<4)
|
||||||
|
#define BOOTUTIL_CAP_ENC_RSA (1<<5)
|
||||||
|
#define BOOTUTIL_CAP_ENC_KW (1<<6)
|
||||||
|
#define BOOTUTIL_CAP_VALIDATE_PRIMARY_SLOT (1<<7)
|
||||||
|
#define BOOTUTIL_CAP_RSA3072 (1<<8)
|
||||||
|
#define BOOTUTIL_CAP_ED25519 (1<<9)
|
||||||
|
#define BOOTUTIL_CAP_ENC_EC256 (1<<10)
|
||||||
|
#define BOOTUTIL_CAP_SWAP_USING_MOVE (1<<11)
|
||||||
|
#define BOOTUTIL_CAP_DOWNGRADE_PREVENTION (1<<12)
|
||||||
|
#define BOOTUTIL_CAP_ENC_X25519 (1<<13)
|
||||||
|
#define BOOTUTIL_CAP_BOOTSTRAP (1<<14)
|
||||||
|
#define BOOTUTIL_CAP_AES256 (1<<15)
|
||||||
|
#define BOOTUTIL_CAP_RAM_LOAD (1<<16)
|
||||||
|
#define BOOTUTIL_CAP_DIRECT_XIP (1<<17)
|
||||||
|
#define BOOTUTIL_CAP_HW_ROLLBACK_PROT (1<<18)
|
||||||
|
#define BOOTUTIL_CAP_ECDSA_P384 (1<<19)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query the number of images this bootloader is configured for. This
|
||||||
|
* is also primarily used for testing.
|
||||||
|
*/
|
||||||
|
uint32_t bootutil_get_num_images(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
|
||||||
|
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
|
||||||
|
* one of these defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_AES_CTR_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_AES_CTR_H_
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_USE_MBED_TLS) + \
|
||||||
|
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)
|
||||||
|
#include <mbedtls/aes.h>
|
||||||
|
#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 /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
#if defined(MCUBOOT_AES_256)
|
||||||
|
#error "Cannot use AES-256 for encryption with Tinycrypt library."
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
#include <tinycrypt/aes.h>
|
||||||
|
#include <tinycrypt/ctr_mode.h>
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE TC_AES_KEY_SIZE
|
||||||
|
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
#include <psa/crypto.h>
|
||||||
|
#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 <stdint.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
(void)mbedtls_aes_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_aes_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
|
||||||
|
{
|
||||||
|
return mbedtls_aes_setkey_enc(ctx, k, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline 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)
|
||||||
|
{
|
||||||
|
uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
|
||||||
|
return mbedtls_aes_crypt_ctr(ctx, mlen, &blk_off, counter, stream_block, m, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline 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)
|
||||||
|
{
|
||||||
|
uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
|
||||||
|
return mbedtls_aes_crypt_ctr(ctx, clen, &blk_off, counter, stream_block, c, m);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
typedef struct tc_aes_key_sched_struct bootutil_aes_ctr_context;
|
||||||
|
static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = tc_aes128_set_encrypt_key(ctx, k);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _bootutil_aes_ctr_crypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *in, uint32_t inlen, uint32_t blk_off, uint8_t *out)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = tc_ctr_mode(out, inlen, in, inlen, counter, &blk_off, ctx);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, uint32_t blk_off, uint8_t *c)
|
||||||
|
{
|
||||||
|
return _bootutil_aes_ctr_crypt(ctx, counter, m, mlen, blk_off, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, uint32_t blk_off, uint8_t *m)
|
||||||
|
{
|
||||||
|
return _bootutil_aes_ctr_crypt(ctx, counter, c, clen, blk_off, m);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_AES_CTR_H_ */
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
|
||||||
|
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
|
||||||
|
* one of these defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_AES_KW_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_AES_KW_H_
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#include <mbedtls/aes.h>
|
||||||
|
#include <mbedtls/nist_kw.h>
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
#if defined(MCUBOOT_AES_256)
|
||||||
|
#error "Cannot use AES-256 for encryption with Tinycrypt library."
|
||||||
|
#endif
|
||||||
|
#include <tinycrypt/aes.h>
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
typedef mbedtls_nist_kw_context bootutil_aes_kw_context;
|
||||||
|
static inline void bootutil_aes_kw_init(bootutil_aes_kw_context *ctx)
|
||||||
|
{
|
||||||
|
(void)mbedtls_nist_kw_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_aes_kw_drop(bootutil_aes_kw_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_nist_kw_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_kw_set_unwrap_key(bootutil_aes_kw_context *ctx, const uint8_t *k, uint32_t klen)
|
||||||
|
{
|
||||||
|
return mbedtls_nist_kw_setkey(ctx, MBEDTLS_CIPHER_ID_AES, k, klen * 8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_kw_unwrap(bootutil_aes_kw_context *ctx, const uint8_t *wrapped_key, uint32_t wrapped_key_len, uint8_t *key, uint32_t key_len)
|
||||||
|
{
|
||||||
|
size_t olen;
|
||||||
|
return mbedtls_nist_kw_unwrap(ctx, MBEDTLS_KW_MODE_KW, wrapped_key, wrapped_key_len, key, &olen, key_len);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
typedef struct tc_aes_key_sched_struct bootutil_aes_kw_context;
|
||||||
|
static inline void bootutil_aes_kw_init(bootutil_aes_kw_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_aes_kw_drop(bootutil_aes_kw_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_aes_kw_set_unwrap_key(bootutil_aes_kw_context *ctx, const uint8_t *k, uint32_t klen)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (klen != 16) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = tc_aes128_set_decrypt_key(ctx, k);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implements AES key unwrapping following RFC-3394 section 2.2.2, using
|
||||||
|
* tinycrypt for AES-128 decryption.
|
||||||
|
*/
|
||||||
|
static int bootutil_aes_kw_unwrap(bootutil_aes_kw_context *ctx, const uint8_t *wrapped_key, uint32_t wrapped_key_len, uint8_t *key, uint32_t key_len)
|
||||||
|
{
|
||||||
|
uint8_t A[8];
|
||||||
|
uint8_t B[16];
|
||||||
|
int8_t i, j, k;
|
||||||
|
|
||||||
|
if (wrapped_key_len != 24 || key_len != 16) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
A[k] = wrapped_key[k];
|
||||||
|
key[k] = wrapped_key[8 + k];
|
||||||
|
key[8 + k] = wrapped_key[16 + k];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 5; j >= 0; j--) {
|
||||||
|
for (i = 2; i > 0; i--) {
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
B[k] = A[k];
|
||||||
|
B[8 + k] = key[((i-1) * 8) + k];
|
||||||
|
}
|
||||||
|
B[7] ^= 2 * j + i;
|
||||||
|
if (tc_aes_decrypt((uint8_t *)&B, (uint8_t *)&B, ctx) != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
A[k] = B[k];
|
||||||
|
key[((i-1) * 8) + k] = B[8 + k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, k = 0; i < 8; i++) {
|
||||||
|
k |= A[i] ^ 0xa6;
|
||||||
|
}
|
||||||
|
if (k) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_AES_KW_H_ */
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_COMMON_H__
|
||||||
|
#define __BOOTUTIL_CRYPTO_COMMON_H__
|
||||||
|
|
||||||
|
/* The check below can be performed even for those cases
|
||||||
|
* where MCUBOOT_USE_MBED_TLS has not been defined
|
||||||
|
*/
|
||||||
|
#include "mbedtls/version.h"
|
||||||
|
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||||
|
#define MBEDTLS_CONTEXT_MEMBER(X) MBEDTLS_PRIVATE(X)
|
||||||
|
#else
|
||||||
|
#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__ */
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
|
||||||
|
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
|
||||||
|
* one of these defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_ECDH_P256_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_ECDH_P256_H_
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#include <mbedtls/ecp.h>
|
||||||
|
#include <mbedtls/ecdh.h>
|
||||||
|
#define EC256_PUBK_LEN (65)
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
#include <tinycrypt/ecc_dh.h>
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#define BOOTUTIL_CRYPTO_ECDH_P256_HASH_SIZE (4 * 8)
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
typedef uintptr_t bootutil_ecdh_p256_context;
|
||||||
|
static inline void bootutil_ecdh_p256_init(bootutil_ecdh_p256_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdh_p256_drop(bootutil_ecdh_p256_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdh_p256_shared_secret(bootutil_ecdh_p256_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
if (pk[0] != 0x04) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = uECC_valid_public_key(&pk[1], uECC_secp256r1());
|
||||||
|
if (rc != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = uECC_shared_secret(&pk[1], sk, z, uECC_secp256r1());
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#define NUM_ECC_BYTES 32
|
||||||
|
|
||||||
|
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||||
|
static int fake_rng(void *p_rng, unsigned char *output, size_t len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct bootutil_ecdh_p256_context {
|
||||||
|
mbedtls_ecp_group grp;
|
||||||
|
mbedtls_ecp_point P;
|
||||||
|
mbedtls_mpi z;
|
||||||
|
mbedtls_mpi d;
|
||||||
|
} bootutil_ecdh_p256_context;
|
||||||
|
|
||||||
|
static inline void bootutil_ecdh_p256_init(bootutil_ecdh_p256_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_mpi_init(&ctx->z);
|
||||||
|
mbedtls_mpi_init(&ctx->d);
|
||||||
|
|
||||||
|
mbedtls_ecp_group_init(&ctx->grp);
|
||||||
|
mbedtls_ecp_point_init(&ctx->P);
|
||||||
|
|
||||||
|
if (mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
|
||||||
|
mbedtls_ecp_group_free(&ctx->grp);
|
||||||
|
mbedtls_ecp_point_free(&ctx->P);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdh_p256_drop(bootutil_ecdh_p256_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_mpi_free(&ctx->d);
|
||||||
|
mbedtls_mpi_free(&ctx->z);
|
||||||
|
mbedtls_ecp_group_free(&ctx->grp);
|
||||||
|
mbedtls_ecp_point_free(&ctx->P);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdh_p256_shared_secret(bootutil_ecdh_p256_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = mbedtls_ecp_point_read_binary(&ctx->grp,
|
||||||
|
&ctx->P,
|
||||||
|
pk,
|
||||||
|
EC256_PUBK_LEN);
|
||||||
|
if (rc != 0) {
|
||||||
|
mbedtls_ecp_group_free(&ctx->grp);
|
||||||
|
mbedtls_ecp_point_free(&ctx->P);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->P);
|
||||||
|
if (rc != 0) {
|
||||||
|
mbedtls_ecp_group_free(&ctx->grp);
|
||||||
|
mbedtls_ecp_point_free(&ctx->P);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_mpi_read_binary(&ctx->d, sk, NUM_ECC_BYTES);
|
||||||
|
|
||||||
|
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||||
|
rc = mbedtls_ecdh_compute_shared(&ctx->grp,
|
||||||
|
&ctx->z,
|
||||||
|
&ctx->P,
|
||||||
|
&ctx->d,
|
||||||
|
fake_rng,
|
||||||
|
NULL);
|
||||||
|
#else
|
||||||
|
rc = mbedtls_ecdh_compute_shared(&ctx->grp,
|
||||||
|
&ctx->z,
|
||||||
|
&ctx->P,
|
||||||
|
&ctx->d,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
|
mbedtls_mpi_write_binary(&ctx->z, z, NUM_ECC_BYTES);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_ECDH_P256_H_ */
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
|
||||||
|
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
|
||||||
|
* one of these defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_ECDH_X25519_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_ECDH_X25519_H_
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
extern int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
|
||||||
|
const uint8_t peer_public_value[32]);
|
||||||
|
|
||||||
|
typedef uintptr_t bootutil_ecdh_x25519_context;
|
||||||
|
static inline void bootutil_ecdh_x25519_init(bootutil_ecdh_x25519_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdh_x25519_drop(bootutil_ecdh_x25519_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdh_x25519_shared_secret(bootutil_ecdh_x25519_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
rc = X25519(z, sk, pk);
|
||||||
|
if (rc != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_ECDH_X25519_H_ */
|
||||||
672
bootloader/mcuboot/boot/bootutil/include/bootutil/crypto/ecdsa.h
Normal file
672
bootloader/mcuboot/boot/bootutil/include/bootutil/crypto/ecdsa.h
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023-2024 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, the choices are: MCUBOOT_USE_TINYCRYPT, MCUBOOT_USE_CC310,
|
||||||
|
* MCUBOOT_USE_MBED_TLS, MCUBOOT_USE_PSA_CRYPTO. Note that support for
|
||||||
|
* MCUBOOT_USE_PSA_CRYPTO is still experimental and it might not support all
|
||||||
|
* the crypto abstractions that MCUBOOT_USE_MBED_TLS supports. For this
|
||||||
|
* reason, it's allowed to have both of them defined, and for crypto modules
|
||||||
|
* that support both abstractions, the MCUBOOT_USE_PSA_CRYPTO will take
|
||||||
|
* precedence.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_ECDSA_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_ECDSA_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#define MCUBOOT_USE_PSA_OR_MBED_TLS
|
||||||
|
#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_EC384) && \
|
||||||
|
!defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
#error "P384 requires PSA_CRYPTO to be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_USE_TINYCRYPT) + \
|
||||||
|
defined(MCUBOOT_USE_CC310) + \
|
||||||
|
defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \
|
||||||
|
defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1
|
||||||
|
#error "One crypto backend must be defined: either CC310/TINYCRYPT/MBED_TLS/PSA_CRYPTO"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
#include <tinycrypt/ecc_dsa.h>
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_CC310)
|
||||||
|
#include <cc310_glue.h>
|
||||||
|
#endif /* MCUBOOT_USE_CC310 */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
#include <psa/crypto.h>
|
||||||
|
#include <string.h>
|
||||||
|
#elif defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#include <mbedtls/ecdsa.h>
|
||||||
|
/* Indicate to the caller that the verify function needs the raw ASN.1
|
||||||
|
* signature, not a decoded one. */
|
||||||
|
#define MCUBOOT_ECDSA_NEED_ASN1_SIG
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
/*TODO: remove this after cypress port mbedtls to abstract crypto api */
|
||||||
|
#if defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#define NUM_ECC_BYTES (256 / 8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Universal defines */
|
||||||
|
#define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (32)
|
||||||
|
|
||||||
|
#include "mbedtls/oid.h"
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
#include "bootutil/sign_key.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)
|
||||||
|
#include <bl_crypto.h>
|
||||||
|
#define NUM_ECC_BYTES (256 / 8)
|
||||||
|
#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \
|
||||||
|
defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \
|
||||||
|
&& !defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
/*
|
||||||
|
* Declaring these like this adds NULL termination.
|
||||||
|
*/
|
||||||
|
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
|
||||||
|
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a public key. Helper function.
|
||||||
|
*/
|
||||||
|
static int bootutil_import_key(uint8_t **cp, uint8_t *end)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
mbedtls_asn1_buf alg;
|
||||||
|
mbedtls_asn1_buf param;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_tag(cp, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
end = *cp + len;
|
||||||
|
|
||||||
|
/* ECParameters (RFC5480) */
|
||||||
|
if (mbedtls_asn1_get_alg(cp, end, &alg, ¶m)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
/* id-ecPublicKey (RFC5480) */
|
||||||
|
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.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) */
|
||||||
|
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
if (*cp + len != end) {
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != 2 * NUM_ECC_BYTES + 1) {
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cp points to ASN1 string containing an integer.
|
||||||
|
* Verify the tag, and that the length is 32 bytes. Helper function.
|
||||||
|
*/
|
||||||
|
static int bootutil_read_bigint(uint8_t i[NUM_ECC_BYTES], uint8_t **cp, uint8_t *end)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_tag(cp, end, &len, MBEDTLS_ASN1_INTEGER)) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= NUM_ECC_BYTES) {
|
||||||
|
memcpy(i, *cp + len - NUM_ECC_BYTES, NUM_ECC_BYTES);
|
||||||
|
} else {
|
||||||
|
memset(i, 0, NUM_ECC_BYTES - len);
|
||||||
|
memcpy(i + NUM_ECC_BYTES - len, *cp, len);
|
||||||
|
}
|
||||||
|
*cp += len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read in signature. Signature has r and s encoded as integers. Helper function.
|
||||||
|
*/
|
||||||
|
static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp, uint8_t *end)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
rc = mbedtls_asn1_get_tag(&cp, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (cp + len > end) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_read_bigint(signature, &cp, end);
|
||||||
|
if (rc) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
rc = bootutil_read_bigint(signature + NUM_ECC_BYTES, &cp, end);
|
||||||
|
if (rc) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
typedef uintptr_t bootutil_ecdsa_context;
|
||||||
|
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t *pk, size_t pk_len,
|
||||||
|
uint8_t *hash, size_t hash_len,
|
||||||
|
uint8_t *sig, size_t sig_len)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
(void)ctx;
|
||||||
|
(void)pk_len;
|
||||||
|
(void)sig_len;
|
||||||
|
(void)hash_len;
|
||||||
|
|
||||||
|
uint8_t signature[2 * NUM_ECC_BYTES];
|
||||||
|
rc = bootutil_decode_sig(signature, sig, sig + sig_len);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only support uncompressed keys. */
|
||||||
|
if (pk[0] != 0x04) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pk++;
|
||||||
|
|
||||||
|
rc = uECC_verify(pk, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, signature, uECC_secp256r1());
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t **cp,uint8_t *end)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
return bootutil_import_key(cp, end);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_CC310)
|
||||||
|
typedef uintptr_t bootutil_ecdsa_context;
|
||||||
|
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t *pk, size_t pk_len,
|
||||||
|
uint8_t *hash, size_t hash_len,
|
||||||
|
uint8_t *sig, size_t sig_len)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)pk_len;
|
||||||
|
(void)hash_len;
|
||||||
|
uint8_t dsig[2 * NUM_ECC_BYTES];
|
||||||
|
|
||||||
|
if (bootutil_decode_sig(dsig, sig, sig + sig_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only support uncompressed keys. */
|
||||||
|
if (pk[0] != 0x04) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pk++;
|
||||||
|
|
||||||
|
return cc310_ecdsa_verify_secp256r1(hash, pk, dsig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t **cp,uint8_t *end)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
return bootutil_import_key(cp, end);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_CC310 */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
typedef struct {
|
||||||
|
psa_key_id_t key_id;
|
||||||
|
size_t curve_byte_count;
|
||||||
|
psa_algorithm_t required_algorithm;
|
||||||
|
} bootutil_ecdsa_context;
|
||||||
|
|
||||||
|
/* ECDSA public key with format specified in RFC5280 et al. in ASN.1 syntax
|
||||||
|
*
|
||||||
|
* SEQUENCE {
|
||||||
|
* SEQUENCE {
|
||||||
|
* OBJECT idEcPublicKey
|
||||||
|
* OBJECT namedCurve
|
||||||
|
* }
|
||||||
|
* BIT STRING publicKey
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ECDSA signature format specified in RFC3279 et al. in ASN.1 syntax
|
||||||
|
*
|
||||||
|
* SEQUENCE {
|
||||||
|
* INTEGER r
|
||||||
|
* INTEGER s
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Offset in bytes from the start of the encoding to the length field
|
||||||
|
* of the innermost SEQUENCE in the ECDSA public key
|
||||||
|
*/
|
||||||
|
#define PUB_KEY_LEN_OFF (3)
|
||||||
|
|
||||||
|
/* Offset in bytes from the start of the publicKey encoding of the BIT STRING */
|
||||||
|
#define PUB_KEY_VAL_OFF (3)
|
||||||
|
|
||||||
|
/* Computes the pointer to the idEcPublicKey OID from the base of the encoding */
|
||||||
|
#define PUB_KEY_OID_OFFSET(p) (*p + PUB_KEY_LEN_OFF+1)
|
||||||
|
|
||||||
|
/* Computes the pointer to the namedCurve OID from the base of the encoding */
|
||||||
|
#define CURVE_TYPE_OID_OFFSET(p) PUB_KEY_OID_OFFSET(p) + sizeof(IdEcPublicKey)
|
||||||
|
|
||||||
|
/* This helper function gets a pointer to the bitstring associated to the publicKey
|
||||||
|
* as encoded per RFC 5280. This function assumes that the public key encoding is not
|
||||||
|
* bigger than 127 bytes (i.e. usually up until 384 bit curves)
|
||||||
|
*
|
||||||
|
* \param[in,out] p Double pointer to a buffer containing the RFC 5280 of the ECDSA public key.
|
||||||
|
* On output, the pointer is updated to point to the start of the public key
|
||||||
|
* in BIT STRING form.
|
||||||
|
* \param[out] size Pointer to a buffer containing the size of the public key extracted
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline void get_public_key_from_rfc5280_encoding(uint8_t **p, size_t *size)
|
||||||
|
{
|
||||||
|
uint8_t *key_start = (*p) + (PUB_KEY_LEN_OFF + 1 + (*p)[PUB_KEY_LEN_OFF] + PUB_KEY_VAL_OFF);
|
||||||
|
*p = key_start;
|
||||||
|
*size = key_start[-2]-1; /* -2 from PUB_KEY_VAL_OFF to get the length, -1 to remove the ASN.1 padding byte count */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This helper function parses a signature as specified in RFC3279 into a pair
|
||||||
|
* (r,s) of contiguous bytes
|
||||||
|
*
|
||||||
|
* \param[in] sig Pointer to a buffer containing the encoded signature
|
||||||
|
* \param[in] num_of_curve_bytes The required number of bytes for r and s
|
||||||
|
* \param[out] r_s_pair Buffer containing the (r,s) pair extracted. It's caller
|
||||||
|
* responsibility to ensure the buffer is big enough to
|
||||||
|
* hold the parsed (r,s) pair.
|
||||||
|
*/
|
||||||
|
static void parse_signature_from_rfc5480_encoding(const uint8_t *sig,
|
||||||
|
size_t num_of_curve_bytes,
|
||||||
|
uint8_t *r_s_pair)
|
||||||
|
{
|
||||||
|
const uint8_t *sig_ptr = NULL;
|
||||||
|
|
||||||
|
/* r or s can be greater than the expected size by one, due to the way
|
||||||
|
* ASN.1 encodes signed integers. If either r or s starts with a bit 1,
|
||||||
|
* a zero byte will be added in front of the encoding
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* sig[0] == 0x30, sig[1] == <length>, sig[2] == 0x02 */
|
||||||
|
|
||||||
|
/* Move r in place */
|
||||||
|
size_t r_len = sig[3];
|
||||||
|
sig_ptr = &sig[4];
|
||||||
|
if (r_len >= num_of_curve_bytes) {
|
||||||
|
sig_ptr = sig_ptr + r_len - num_of_curve_bytes;
|
||||||
|
memcpy(&r_s_pair[0], sig_ptr, num_of_curve_bytes);
|
||||||
|
if(r_len % 2) {
|
||||||
|
r_len--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* For encodings that reduce the size of r or s in case of zeros */
|
||||||
|
memcpy(&r_s_pair[num_of_curve_bytes - r_len], sig_ptr, r_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move s in place */
|
||||||
|
size_t s_len = sig_ptr[r_len+1]; /* + 1 to skip SEQUENCE */
|
||||||
|
sig_ptr = &sig_ptr[r_len+2];
|
||||||
|
if (s_len >= num_of_curve_bytes) {
|
||||||
|
sig_ptr = sig_ptr + s_len - num_of_curve_bytes;
|
||||||
|
memcpy(&r_s_pair[num_of_curve_bytes], sig_ptr, num_of_curve_bytes);
|
||||||
|
} else {
|
||||||
|
/* For encodings that reduce the size of r or s in case of zeros */
|
||||||
|
memcpy(&r_s_pair[2*num_of_curve_bytes - s_len], sig_ptr, s_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OID id-ecPublicKey 1.2.840.10045.2.1.
|
||||||
|
static const uint8_t IdEcPublicKey[] = {0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01};
|
||||||
|
#if defined(MCUBOOT_SIGN_EC256)
|
||||||
|
// OID secp256r1 1.2.840.10045.3.1.7.
|
||||||
|
static const uint8_t Secp256r1[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
|
||||||
|
#endif /* MCUBOOT_SIGN_EC256 */
|
||||||
|
#if defined(MCUBOOT_SIGN_EC384)
|
||||||
|
// OID secp384r1 1.3.132.0.34
|
||||||
|
static const uint8_t Secp384r1[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22};
|
||||||
|
#endif /* MCUBOOT_SIGN_EC384 */
|
||||||
|
|
||||||
|
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
#if !defined(MCUBOOT_BUILTIN_KEY)
|
||||||
|
ctx->key_id = PSA_KEY_ID_NULL;
|
||||||
|
ctx->curve_byte_count = 0;
|
||||||
|
ctx->required_algorithm = 0;
|
||||||
|
|
||||||
|
#else /* !MCUBOOT_BUILTIN_KEY */
|
||||||
|
/* The incoming key ID is equal to the image index. The key ID value must be
|
||||||
|
* shifted (by one in this case) because zero is reserved (PSA_KEY_ID_NULL)
|
||||||
|
* and considered invalid.
|
||||||
|
*/
|
||||||
|
ctx->key_id++; /* Make sure it is not equal to 0. */
|
||||||
|
#if defined(MCUBOOT_SIGN_EC256)
|
||||||
|
ctx->curve_byte_count = 32;
|
||||||
|
ctx->required_algorithm = PSA_ALG_SHA_256;
|
||||||
|
#endif /* MCUBOOT_SIGN_EC256 */
|
||||||
|
#if defined(MCUBOOT_SIGN_EC384)
|
||||||
|
ctx->curve_byte_count = 48;
|
||||||
|
ctx->required_algorithm = PSA_ALG_SHA_384;
|
||||||
|
#endif /* MCUBOOT_SIGN_EC384 */
|
||||||
|
#endif /* !MCUBOOT_BUILTIN_KEY */
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->key_id != PSA_KEY_ID_NULL) {
|
||||||
|
(void)psa_destroy_key(ctx->key_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_BUILTIN_KEY)
|
||||||
|
/*
|
||||||
|
* Parse a ECDSA public key with format specified in RFC5280 et al.
|
||||||
|
*
|
||||||
|
* OID for icEcPublicKey is 1.2.840.10045.2.1
|
||||||
|
* OIDs for supported curves are as follows:
|
||||||
|
* secp256r1 (prime256v1): 1.2.840.10045.3.1.7
|
||||||
|
* secp384r1: 1.3.132.0.34
|
||||||
|
*/
|
||||||
|
static int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t **cp, uint8_t *end)
|
||||||
|
{
|
||||||
|
psa_key_attributes_t key_attributes = psa_key_attributes_init();
|
||||||
|
size_t key_size;
|
||||||
|
(void)end;
|
||||||
|
|
||||||
|
/* public key oid is valid */
|
||||||
|
if (memcmp(PUB_KEY_OID_OFFSET(cp), IdEcPublicKey, sizeof(IdEcPublicKey))) {
|
||||||
|
return (int)PSA_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_EC256)
|
||||||
|
if (!memcmp(CURVE_TYPE_OID_OFFSET(cp), Secp256r1, sizeof(Secp256r1))) {
|
||||||
|
ctx->curve_byte_count = 32;
|
||||||
|
ctx->required_algorithm = PSA_ALG_SHA_256;
|
||||||
|
} else
|
||||||
|
#endif /* MCUBOOT_SIGN_EC256 */
|
||||||
|
#if defined(MCUBOOT_SIGN_EC384)
|
||||||
|
if (!memcmp(CURVE_TYPE_OID_OFFSET(cp), Secp384r1, sizeof(Secp384r1))) {
|
||||||
|
ctx->curve_byte_count = 48;
|
||||||
|
ctx->required_algorithm = PSA_ALG_SHA_384;
|
||||||
|
} else
|
||||||
|
#endif /* MCUBOOT_SIGN_EC384 */
|
||||||
|
{
|
||||||
|
return (int)PSA_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_public_key_from_rfc5280_encoding(cp, &key_size);
|
||||||
|
/* Set attributes and import key */
|
||||||
|
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
|
||||||
|
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(ctx->required_algorithm));
|
||||||
|
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
|
||||||
|
|
||||||
|
return (int)psa_import_key(&key_attributes, *cp, key_size, &ctx->key_id);
|
||||||
|
}
|
||||||
|
#endif /* !MCUBOOT_BUILTIN_KEY */
|
||||||
|
|
||||||
|
/* Verify the signature against the provided hash. The signature gets parsed from
|
||||||
|
* the encoding first, then PSA Crypto has a dedicated API for ECDSA verification
|
||||||
|
*/
|
||||||
|
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t *pk, size_t pk_len,
|
||||||
|
uint8_t *hash, size_t hlen,
|
||||||
|
uint8_t *sig, size_t slen)
|
||||||
|
{
|
||||||
|
(void)pk;
|
||||||
|
(void)pk_len;
|
||||||
|
(void)slen;
|
||||||
|
|
||||||
|
uint8_t reformatted_signature[96] = {0}; /* Enough for P-384 signature sizes */
|
||||||
|
parse_signature_from_rfc5480_encoding(sig, ctx->curve_byte_count,reformatted_signature);
|
||||||
|
|
||||||
|
return (int) psa_verify_hash(ctx->key_id, PSA_ALG_ECDSA(ctx->required_algorithm),
|
||||||
|
hash, hlen, reformatted_signature, 2*ctx->curve_byte_count);
|
||||||
|
}
|
||||||
|
#elif defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
|
||||||
|
typedef mbedtls_ecdsa_context bootutil_ecdsa_context;
|
||||||
|
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_ecdsa_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_ecdsa_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CY_MBEDTLS_HW_ACCELERATION
|
||||||
|
/*
|
||||||
|
* Parse the public key used for signing.
|
||||||
|
*/
|
||||||
|
static int bootutil_parse_eckey(bootutil_ecdsa_context *ctx, uint8_t **p, uint8_t *end)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
mbedtls_asn1_buf alg;
|
||||||
|
mbedtls_asn1_buf param;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_tag(p, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
end = *p + len;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_alg(p, end, &alg, ¶m)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1)) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_bitstring_null(p, end, &len)) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
if (*p + len != end) {
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, *p, end - *p)) {
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->Q)) {
|
||||||
|
return -9;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t *pk, size_t pk_len,
|
||||||
|
uint8_t *hash, size_t hash_len,
|
||||||
|
uint8_t *sig, size_t sig_len)
|
||||||
|
{
|
||||||
|
(void)pk;
|
||||||
|
(void)pk_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is simplified, as the hash length is also 32 bytes.
|
||||||
|
*/
|
||||||
|
while (sig[sig_len - 1] == '\0') {
|
||||||
|
sig_len--;
|
||||||
|
}
|
||||||
|
return mbedtls_ecdsa_read_signature(&ctx, hash, hash_len, sig, sig_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* CY_MBEDTLS_HW_ACCELERATION */
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t *pk, size_t pk_len,
|
||||||
|
uint8_t *hash, size_t hash_len,
|
||||||
|
uint8_t *sig, size_t sig_len)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
(void)sig;
|
||||||
|
(void)hash;
|
||||||
|
(void)hash_len;
|
||||||
|
|
||||||
|
rc = mbedtls_ecp_group_load(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), MBEDTLS_ECP_DP_SECP256R1);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mbedtls_ecp_point_read_binary(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), &ctx->MBEDTLS_CONTEXT_MEMBER(Q), pk, pk_len);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mbedtls_ecp_check_pubkey(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), &ctx->MBEDTLS_CONTEXT_MEMBER(Q));
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mbedtls_ecdsa_read_signature(ctx, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE,
|
||||||
|
sig, sig_len);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CY_MBEDTLS_HW_ACCELERATION */
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t **cp,uint8_t *end)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
#ifdef CY_MBEDTLS_HW_ACCELERATION
|
||||||
|
rc = bootutil_parse_eckey(&ctx, cp, end);
|
||||||
|
#else
|
||||||
|
(void)ctx;
|
||||||
|
rc = bootutil_import_key(cp, end);
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)
|
||||||
|
typedef uintptr_t bootutil_ecdsa_context;
|
||||||
|
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t *pk, size_t pk_len,
|
||||||
|
uint8_t *hash, size_t hash_len,
|
||||||
|
uint8_t *sig, size_t sig_len)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)pk_len;
|
||||||
|
(void)hash_len;
|
||||||
|
uint8_t dsig[2 * NUM_ECC_BYTES];
|
||||||
|
|
||||||
|
if (bootutil_decode_sig(dsig, sig, sig + sig_len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only support uncompressed keys. */
|
||||||
|
if (pk[0] != 0x04) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pk++;
|
||||||
|
|
||||||
|
return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, pk, dsig);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
|
||||||
|
uint8_t **cp,uint8_t *end)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
return bootutil_import_key(cp, end);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_ECDSA_H_ */
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
|
||||||
|
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
|
||||||
|
* one of these defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_HMAC_SHA256_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_HMAC_SHA256_H_
|
||||||
|
|
||||||
|
#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"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <mbedtls/cmac.h>
|
||||||
|
#include <mbedtls/md.h>
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
#include <tinycrypt/sha256.h>
|
||||||
|
#include <tinycrypt/utils.h>
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#include <tinycrypt/hmac.h>
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
typedef struct tc_hmac_state_struct bootutil_hmac_sha256_context;
|
||||||
|
static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = tc_hmac_set_key(ctx, key, key_size);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rc = tc_hmac_init(ctx);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = tc_hmac_update(ctx, data, data_length);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = tc_hmac_final(tag, taglen, ctx);
|
||||||
|
if (rc != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
/**
|
||||||
|
* The generic message-digest context.
|
||||||
|
*/
|
||||||
|
typedef mbedtls_md_context_t bootutil_hmac_sha256_context;
|
||||||
|
|
||||||
|
static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_md_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_md_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = mbedtls_md_setup(ctx, mbedtls_md_info_from_string("SHA256"), 1);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc = mbedtls_md_hmac_starts(ctx, key, key_size);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length)
|
||||||
|
{
|
||||||
|
return mbedtls_md_hmac_update(ctx, data, data_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen)
|
||||||
|
{
|
||||||
|
(void)taglen;
|
||||||
|
/*
|
||||||
|
* HMAC the key and check that our received MAC matches the generated tag
|
||||||
|
*/
|
||||||
|
return mbedtls_md_hmac_finish(ctx, tag);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_HMAC_SHA256_H_ */
|
||||||
356
bootloader/mcuboot/boot/bootutil/include/bootutil/crypto/rsa.h
Normal file
356
bootloader/mcuboot/boot/bootutil/include/bootutil/crypto/rsa.h
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, the choices are: MCUBOOT_USE_MBED_TLS and
|
||||||
|
* MCUBOOT_USE_PSA_CRYPTO. Note that support for MCUBOOT_USE_PSA_CRYPTO is
|
||||||
|
* still experimental and it might not support all the crypto abstractions
|
||||||
|
* that MCUBOOT_USE_MBED_TLS supports. For this reason, it's allowed to have
|
||||||
|
* both of them defined, and for crypto modules that support both abstractions,
|
||||||
|
* the MCUBOOT_USE_PSA_CRYPTO will take precedence.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: The source file that includes this header should either define one of the
|
||||||
|
* two options BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED or BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
|
||||||
|
* This will make the signature functions or encryption functions visible without
|
||||||
|
* generating a "defined but not used" compiler warning
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_RSA_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_RSA_H_
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#define MCUBOOT_USE_PSA_OR_MBED_TLS
|
||||||
|
#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1
|
||||||
|
#error "One crypto backend must be defined: either MBED_TLS/PSA_CRYPTO"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
|
||||||
|
#include <psa/crypto.h>
|
||||||
|
#include "bootutil/enc_key_public.h"
|
||||||
|
|
||||||
|
#elif defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
|
||||||
|
#include "mbedtls/rsa.h"
|
||||||
|
#include "mbedtls/version.h"
|
||||||
|
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
|
||||||
|
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||||
|
#include "rsa_alt_helpers.h"
|
||||||
|
#else
|
||||||
|
#include "mbedtls/rsa_internal.h"
|
||||||
|
#endif
|
||||||
|
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
#include "bootutil/crypto/common.h"
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
psa_key_id_t key_id;
|
||||||
|
} bootutil_rsa_context;
|
||||||
|
|
||||||
|
static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
|
||||||
|
{
|
||||||
|
ctx->key_id = PSA_KEY_ID_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->key_id != PSA_KEY_ID_NULL) {
|
||||||
|
(void)psa_destroy_key(ctx->key_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
|
||||||
|
static int bootutil_rsa_oaep_decrypt(
|
||||||
|
bootutil_rsa_context *ctx,
|
||||||
|
size_t *olen,
|
||||||
|
const uint8_t *input,
|
||||||
|
uint8_t *output,
|
||||||
|
size_t output_max_len)
|
||||||
|
{
|
||||||
|
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
/* Perform an additional defensive check to compare the modulus of the RSA
|
||||||
|
* key to the expected input of the decryption function, i.e. TLV_ENC_RSA_SZ
|
||||||
|
*/
|
||||||
|
psa_key_attributes_t key_attr = psa_key_attributes_init();
|
||||||
|
status = psa_get_key_attributes(ctx->key_id, &key_attr);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t input_size = PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attr));
|
||||||
|
if (input_size != TLV_ENC_RSA_SZ) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = psa_asymmetric_decrypt(ctx->key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
|
||||||
|
input, TLV_ENC_RSA_SZ, NULL, 0,
|
||||||
|
output, output_max_len, olen);
|
||||||
|
return (int)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a RSA private key with format specified in RFC3447 A.1.2
|
||||||
|
*
|
||||||
|
* The key is meant to be used for OAEP decrypt hence algorithm and usage are hardcoded
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
|
||||||
|
{
|
||||||
|
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
|
||||||
|
psa_key_attributes_t key_attributes = psa_key_attributes_init();
|
||||||
|
|
||||||
|
/* Set attributes and import key */
|
||||||
|
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DECRYPT);
|
||||||
|
psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
|
||||||
|
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
|
||||||
|
|
||||||
|
status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
|
||||||
|
return (int)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
|
||||||
|
|
||||||
|
#if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
|
||||||
|
/*
|
||||||
|
* Parse a RSA public key with format specified in RFC3447 A.1.1
|
||||||
|
*
|
||||||
|
* The key is meant to be used for PSS signature verification hence algorithm and usage are hardcoded
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bootutil_rsa_parse_public_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
|
||||||
|
{
|
||||||
|
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
|
||||||
|
psa_key_attributes_t key_attributes = psa_key_attributes_init();
|
||||||
|
|
||||||
|
/* Set attributes and import key */
|
||||||
|
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
|
||||||
|
psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256));
|
||||||
|
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
|
||||||
|
|
||||||
|
status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
|
||||||
|
return (int)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the modulus (N) length in bytes */
|
||||||
|
static size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
|
||||||
|
{
|
||||||
|
psa_key_attributes_t key_attributes = psa_key_attributes_init();
|
||||||
|
psa_status_t status = psa_get_key_attributes(ctx->key_id, &key_attributes);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attributes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PSA Crypto has a dedicated API for RSASSA-PSS verification */
|
||||||
|
static inline int bootutil_rsassa_pss_verify(const bootutil_rsa_context *ctx,
|
||||||
|
uint8_t *hash, size_t hlen, uint8_t *sig, size_t slen)
|
||||||
|
{
|
||||||
|
return (int) psa_verify_hash(ctx->key_id, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256),
|
||||||
|
hash, hlen, sig, slen);
|
||||||
|
}
|
||||||
|
#endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
|
||||||
|
|
||||||
|
#elif defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
|
||||||
|
typedef mbedtls_rsa_context bootutil_rsa_context;
|
||||||
|
|
||||||
|
static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
|
||||||
|
{
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_rsa_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED) && (MBEDTLS_VERSION_NUMBER >= 0x03000000)
|
||||||
|
static int fake_rng(void *p_rng, unsigned char *output, size_t len);
|
||||||
|
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED && MBEDTLS_VERSION_NUMBER >= 3.0 */
|
||||||
|
|
||||||
|
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
|
||||||
|
static inline int bootutil_rsa_oaep_decrypt(
|
||||||
|
bootutil_rsa_context *ctx,
|
||||||
|
size_t *olen,
|
||||||
|
const uint8_t *input,
|
||||||
|
uint8_t *output,
|
||||||
|
size_t output_max_len)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||||
|
rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, fake_rng, NULL,
|
||||||
|
NULL, 0, olen, input, output, output_max_len);
|
||||||
|
#else
|
||||||
|
rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, NULL, NULL, MBEDTLS_RSA_PRIVATE,
|
||||||
|
NULL, 0, olen, input, output, output_max_len);
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a RSA private key with format specified in RFC3447 A.1.2
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_tag(p, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p + len != end) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-optional fields. */
|
||||||
|
if ( /* version */
|
||||||
|
mbedtls_asn1_get_int(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(ver)) != 0 ||
|
||||||
|
/* public modulus */
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0 ||
|
||||||
|
/* public exponent */
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0 ||
|
||||||
|
/* private exponent */
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(D)) != 0 ||
|
||||||
|
/* primes */
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(P)) != 0 ||
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(Q)) != 0) {
|
||||||
|
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_RSA_NO_CRT)
|
||||||
|
/*
|
||||||
|
* DP/DQ/QP are only used inside mbedTLS if it was built with the
|
||||||
|
* Chinese Remainder Theorem enabled (default). In case it is disabled
|
||||||
|
* we parse, or if not available, we calculate those values.
|
||||||
|
*/
|
||||||
|
if (*p < end) {
|
||||||
|
if ( /* d mod (p-1) and d mod (q-1) */
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DP)) != 0 ||
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DQ)) != 0 ||
|
||||||
|
/* q ^ (-1) mod p */
|
||||||
|
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
|
||||||
|
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mbedtls_rsa_deduce_crt(&ctx->MBEDTLS_CONTEXT_MEMBER(P),
|
||||||
|
&ctx->MBEDTLS_CONTEXT_MEMBER(Q),
|
||||||
|
&ctx->MBEDTLS_CONTEXT_MEMBER(D),
|
||||||
|
&ctx->MBEDTLS_CONTEXT_MEMBER(DP),
|
||||||
|
&ctx->MBEDTLS_CONTEXT_MEMBER(DQ),
|
||||||
|
&ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !MBEDTLS_RSA_NO_CRT */
|
||||||
|
|
||||||
|
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
|
||||||
|
|
||||||
|
if (mbedtls_rsa_check_privkey(ctx) != 0) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
|
||||||
|
|
||||||
|
#if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
|
||||||
|
/*
|
||||||
|
* Parse a RSA public key with format specified in RFC3447 A.1.1
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bootutil_rsa_parse_public_key(bootutil_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_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N))) != 0 ||
|
||||||
|
(rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E))) != 0) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
|
||||||
|
|
||||||
|
if (*p != end) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The Mbed TLS version is more than 2.6.1 */
|
||||||
|
#if MBEDTLS_VERSION_NUMBER > 0x02060100
|
||||||
|
rc = mbedtls_rsa_import(ctx, &ctx->MBEDTLS_CONTEXT_MEMBER(N), NULL,
|
||||||
|
NULL, NULL, &ctx->MBEDTLS_CONTEXT_MEMBER(E));
|
||||||
|
if (rc != 0) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = mbedtls_rsa_check_pubkey(ctx);
|
||||||
|
if (rc != 0) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the modulus (N) length in bytes */
|
||||||
|
static inline size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
|
||||||
|
{
|
||||||
|
return mbedtls_rsa_get_len(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Performs modular exponentiation using the public key output = input^E mod N */
|
||||||
|
static inline int bootutil_rsa_public(bootutil_rsa_context *ctx, const uint8_t *input, uint8_t *output)
|
||||||
|
{
|
||||||
|
return mbedtls_rsa_public(ctx, input, output);
|
||||||
|
}
|
||||||
|
#endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_RSA_H_ */
|
||||||
250
bootloader/mcuboot/boot/bootutil/include/bootutil/crypto/sha.h
Normal file
250
bootloader/mcuboot/boot/bootutil/include/bootutil/crypto/sha.h
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2017-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2021-2023 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module provides a thin abstraction over some of the crypto
|
||||||
|
* primitives to make it easier to swap out the used crypto library.
|
||||||
|
*
|
||||||
|
* At this point, the choices are: MCUBOOT_USE_MBED_TLS, MCUBOOT_USE_TINYCRYPT,
|
||||||
|
* MCUBOOT_USE_PSA_CRYPTO, MCUBOOT_USE_CC310. Note that support for MCUBOOT_USE_PSA_CRYPTO
|
||||||
|
* is still experimental and it might not support all the crypto abstractions
|
||||||
|
* that MCUBOOT_USE_MBED_TLS supports. For this reason, it's allowed to have
|
||||||
|
* both of them defined, and for crypto modules that support both abstractions,
|
||||||
|
* the MCUBOOT_USE_PSA_CRYPTO will take precedence.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_CRYPTO_SHA_H_
|
||||||
|
#define __BOOTUTIL_CRYPTO_SHA_H_
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
#include "mcuboot_config/mcuboot_logging.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
#define MCUBOOT_USE_PSA_OR_MBED_TLS
|
||||||
|
#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS) + \
|
||||||
|
defined(MCUBOOT_USE_TINYCRYPT) + \
|
||||||
|
defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \
|
||||||
|
defined(MCUBOOT_USE_CC310)) != 1
|
||||||
|
#error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SHA512)
|
||||||
|
#define IMAGE_HASH_SIZE (64)
|
||||||
|
#define EXPECTED_HASH_TLV IMAGE_TLV_SHA512
|
||||||
|
#elif defined(MCUBOOT_SIGN_EC384)
|
||||||
|
#define IMAGE_HASH_SIZE (48)
|
||||||
|
#define EXPECTED_HASH_TLV IMAGE_TLV_SHA384
|
||||||
|
#else
|
||||||
|
#define IMAGE_HASH_SIZE (32)
|
||||||
|
#define EXPECTED_HASH_TLV IMAGE_TLV_SHA256
|
||||||
|
#endif /* MCUBOOT_SIGN */
|
||||||
|
|
||||||
|
/* Universal defines for SHA-256 */
|
||||||
|
#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64)
|
||||||
|
#define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE (32)
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
|
||||||
|
#include <psa/crypto.h>
|
||||||
|
|
||||||
|
#elif defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
|
||||||
|
#include <mbedtls/sha256.h>
|
||||||
|
#include <mbedtls/version.h>
|
||||||
|
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||||
|
#include <mbedtls/compat-2.x.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
#include <tinycrypt/sha256.h>
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_CC310)
|
||||||
|
#include <cc310_glue.h>
|
||||||
|
#endif /* MCUBOOT_USE_CC310 */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
|
||||||
|
typedef psa_hash_operation_t bootutil_sha_context;
|
||||||
|
|
||||||
|
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
*ctx = psa_hash_operation_init();
|
||||||
|
#if defined(MCUBOOT_SHA512)
|
||||||
|
psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_512);
|
||||||
|
#elif defined(MCUBOOT_SIGN_EC384)
|
||||||
|
psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_384);
|
||||||
|
#else
|
||||||
|
psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_256);
|
||||||
|
#endif
|
||||||
|
return (int)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
return (int)psa_hash_abort(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
|
||||||
|
const void *data,
|
||||||
|
uint32_t data_len)
|
||||||
|
{
|
||||||
|
return (int)psa_hash_update(ctx, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
|
||||||
|
uint8_t *output)
|
||||||
|
{
|
||||||
|
size_t hash_length = 0;
|
||||||
|
/* Assumes the output buffer is at least the expected size of the hash */
|
||||||
|
#if defined(MCUBOOT_SHA512)
|
||||||
|
return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_512), &hash_length);
|
||||||
|
#elif defined(MCUBOOT_SIGN_EC384)
|
||||||
|
return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_384), &hash_length);
|
||||||
|
#else
|
||||||
|
return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(MCUBOOT_USE_MBED_TLS)
|
||||||
|
|
||||||
|
typedef mbedtls_sha256_context bootutil_sha_context;
|
||||||
|
|
||||||
|
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_sha256_init(ctx);
|
||||||
|
return mbedtls_sha256_starts_ret(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
mbedtls_sha256_free(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
|
||||||
|
const void *data,
|
||||||
|
uint32_t data_len)
|
||||||
|
{
|
||||||
|
return mbedtls_sha256_update_ret(ctx, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
|
||||||
|
uint8_t *output)
|
||||||
|
{
|
||||||
|
return mbedtls_sha256_finish_ret(ctx, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_USE_MBED_TLS */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_TINYCRYPT)
|
||||||
|
typedef struct tc_sha256_state_struct bootutil_sha_context;
|
||||||
|
|
||||||
|
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
tc_sha256_init(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
|
||||||
|
const void *data,
|
||||||
|
uint32_t data_len)
|
||||||
|
{
|
||||||
|
return tc_sha256_update(ctx, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
|
||||||
|
uint8_t *output)
|
||||||
|
{
|
||||||
|
return tc_sha256_final(output, ctx);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_TINYCRYPT */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_CC310)
|
||||||
|
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
cc310_sha256_init(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
nrf_cc310_disable();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
|
||||||
|
const void *data,
|
||||||
|
uint32_t data_len)
|
||||||
|
{
|
||||||
|
cc310_sha256_update(ctx, data, data_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
|
||||||
|
uint8_t *output)
|
||||||
|
{
|
||||||
|
cc310_sha256_finalize(ctx, output);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_CC310 */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)
|
||||||
|
|
||||||
|
#include <bl_crypto.h>
|
||||||
|
|
||||||
|
typedef bl_sha256_ctx_t bootutil_sha_context;
|
||||||
|
|
||||||
|
static inline void bootutil_sha_init(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
bl_sha256_init(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bootutil_sha_drop(bootutil_sha_context *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
|
||||||
|
const void *data,
|
||||||
|
uint32_t data_len)
|
||||||
|
{
|
||||||
|
return bl_sha256_update(ctx, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
|
||||||
|
uint8_t *output)
|
||||||
|
{
|
||||||
|
bl_sha256_finalize(ctx, output);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_CRYPTO_SHA_H_ */
|
||||||
83
bootloader/mcuboot/boot/bootutil/include/bootutil/enc_key.h
Normal file
83
bootloader/mcuboot/boot/bootutil/include/bootutil/enc_key.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOTUTIL_ENC_KEY_H
|
||||||
|
#define BOOTUTIL_ENC_KEY_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <flash_map_backend/flash_map_backend.h>
|
||||||
|
#include "bootutil/crypto/aes_ctr.h"
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/sign_key.h"
|
||||||
|
#include "bootutil/enc_key_public.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOT_ENC_TLV_ALIGN_SIZE ALIGN_UP(BOOT_ENC_TLV_SIZE, BOOT_MAX_ALIGN)
|
||||||
|
|
||||||
|
struct enc_key_data {
|
||||||
|
uint8_t valid;
|
||||||
|
bootutil_aes_ctr_context aes_ctr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the private key for image encryption.
|
||||||
|
*
|
||||||
|
* @param[out] private_key structure to store the private key and
|
||||||
|
* its length.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int boot_enc_retrieve_private_key(struct bootutil_key **private_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 slot,
|
||||||
|
const struct image_header *hdr, const struct flash_area *fap,
|
||||||
|
struct boot_status *bs);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BOOTUTIL_ENC_KEY_H */
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2021 Arm Limited
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOTUTIL_ENC_KEY_PUBLIC_H
|
||||||
|
#define BOOTUTIL_ENC_KEY_PUBLIC_H
|
||||||
|
#include <mcuboot_config/mcuboot_config.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ALIGN_UP
|
||||||
|
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_AES_256
|
||||||
|
#define BOOT_ENC_KEY_SIZE 32
|
||||||
|
#else
|
||||||
|
#define BOOT_ENC_KEY_SIZE 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOT_ENC_KEY_ALIGN_SIZE ALIGN_UP(BOOT_ENC_KEY_SIZE, BOOT_MAX_ALIGN)
|
||||||
|
|
||||||
|
#define TLV_ENC_RSA_SZ 256
|
||||||
|
#define TLV_ENC_KW_SZ (BOOT_ENC_KEY_SIZE + 8)
|
||||||
|
#define TLV_ENC_EC256_SZ (65 + 32 + BOOT_ENC_KEY_SIZE)
|
||||||
|
#define TLV_ENC_X25519_SZ (32 + 32 + BOOT_ENC_KEY_SIZE)
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_RSA)
|
||||||
|
#define BOOT_ENC_TLV_SIZE TLV_ENC_RSA_SZ
|
||||||
|
#elif defined(MCUBOOT_ENCRYPT_EC256)
|
||||||
|
#define BOOT_ENC_TLV_SIZE TLV_ENC_EC256_SZ
|
||||||
|
#elif defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
#define BOOT_ENC_TLV_SIZE TLV_ENC_X25519_SZ
|
||||||
|
#else
|
||||||
|
#define BOOT_ENC_TLV_SIZE TLV_ENC_KW_SZ
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BOOTUTIL_ENC_KEY_PUBLIC_H */
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FAULT_INJECTION_HARDENING_H__
|
||||||
|
#define __FAULT_INJECTION_HARDENING_H__
|
||||||
|
|
||||||
|
/* Fault injection mitigation library.
|
||||||
|
*
|
||||||
|
* Has support for different measures, which can either be enabled/disabled
|
||||||
|
* separately or by defining one of the MCUBOOT_FIH_PROFILEs.
|
||||||
|
*
|
||||||
|
* NOTE: These constructs against fault injection attacks are not guaranteed to
|
||||||
|
* be secure for all compilers, but execution is going to be correct and
|
||||||
|
* including them will certainly help to harden the code.
|
||||||
|
*
|
||||||
|
* FIH_ENABLE_DOUBLE_VARS makes critical variables into a tuple (x, x ^ msk).
|
||||||
|
* Then the correctness of x can be checked by XORing the two tuple values
|
||||||
|
* together. This also means that comparisons between fih_ints can be verified
|
||||||
|
* by doing x == y && x_msk == y_msk.
|
||||||
|
*
|
||||||
|
* FIH_ENABLE_GLOBAL_FAIL makes all while(1) failure loops redirect to a global
|
||||||
|
* failure loop. This loop has mitigations against loop escapes / unlooping.
|
||||||
|
* This also means that any unlooping won't immediately continue executing the
|
||||||
|
* function that was executing before the failure.
|
||||||
|
*
|
||||||
|
* FIH_ENABLE_CFI (Control Flow Integrity) creates a global counter that is
|
||||||
|
* incremented before every FIH_CALL of vulnerable functions. On the function
|
||||||
|
* return the counter is decremented, and after the return it is verified that
|
||||||
|
* the counter has the same value as before this process. This can be used to
|
||||||
|
* verify that the function has actually been called. This protection is
|
||||||
|
* intended to discover that important functions are called in an expected
|
||||||
|
* sequence and neither of them is missed due to an instruction skip which could
|
||||||
|
* be a result of glitching attack. It does not provide protection against ROP
|
||||||
|
* or JOP attacks.
|
||||||
|
*
|
||||||
|
* FIH_ENABLE_DELAY causes random delays. This makes it hard to cause faults
|
||||||
|
* precisely. It requires an RNG. An mbedtls integration is provided in
|
||||||
|
* fault_injection_hardening_delay_mbedtls.h, but any RNG that has an entropy
|
||||||
|
* source can be used by implementing the fih_delay_random_uchar function.
|
||||||
|
*
|
||||||
|
* The basic call pattern is:
|
||||||
|
*
|
||||||
|
* FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
* FIH_CALL(vulnerable_function, fih_rc, arg1, arg2);
|
||||||
|
* if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
* FIH_PANIC;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Note that any function called by FIH_CALL must only return using FIH_RETURN,
|
||||||
|
* as otherwise the CFI counter will not be decremented and the CFI check will
|
||||||
|
* fail causing a panic.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_FIH_PROFILE_HIGH)
|
||||||
|
|
||||||
|
#define FIH_ENABLE_DELAY /* Requires an entropy source */
|
||||||
|
#define FIH_ENABLE_DOUBLE_VARS
|
||||||
|
#define FIH_ENABLE_GLOBAL_FAIL
|
||||||
|
#define FIH_ENABLE_CFI
|
||||||
|
|
||||||
|
#elif defined(MCUBOOT_FIH_PROFILE_MEDIUM)
|
||||||
|
|
||||||
|
#define FIH_ENABLE_DOUBLE_VARS
|
||||||
|
#define FIH_ENABLE_GLOBAL_FAIL
|
||||||
|
#define FIH_ENABLE_CFI
|
||||||
|
|
||||||
|
#elif defined(MCUBOOT_FIH_PROFILE_LOW)
|
||||||
|
|
||||||
|
#define FIH_ENABLE_GLOBAL_FAIL
|
||||||
|
#define FIH_ENABLE_CFI
|
||||||
|
|
||||||
|
#elif !defined(MCUBOOT_FIH_PROFILE_OFF)
|
||||||
|
#define MCUBOOT_FIH_PROFILE_OFF
|
||||||
|
#endif /* MCUBOOT_FIH_PROFILE */
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_DELAY
|
||||||
|
#include "fault_injection_hardening_delay_rng.h"
|
||||||
|
#endif /* FIH_ENABLE_DELAY */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/* Non-zero success value to defend against register resets. Zero is the most
|
||||||
|
* common value for a corrupted register so complex bit-patterns are used
|
||||||
|
*/
|
||||||
|
#ifndef MCUBOOT_FIH_PROFILE_OFF
|
||||||
|
#define FIH_POSITIVE_VALUE 0x1AAAAAAA
|
||||||
|
#define FIH_NEGATIVE_VALUE 0x15555555
|
||||||
|
#define FIH_CONST1 0x1FCDEA88
|
||||||
|
#define FIH_CONST2 0x19C1F6E1
|
||||||
|
#else
|
||||||
|
#define FIH_POSITIVE_VALUE 0
|
||||||
|
#define FIH_NEGATIVE_VALUE -1
|
||||||
|
#define FIH_CONST1 1
|
||||||
|
#define FIH_CONST2 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A volatile mask is used to prevent compiler optimization - the mask is xored
|
||||||
|
* with the variable to create the backup and the integrity can be checked with
|
||||||
|
* another xor. The mask value doesn't _really_ matter that much, as long as
|
||||||
|
* it has reasonably high hamming weight.
|
||||||
|
*/
|
||||||
|
#define _FIH_MASK_VALUE 0xBEEF
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_DOUBLE_VARS
|
||||||
|
|
||||||
|
/* All ints are replaced with two int - the normal one and a backup which is
|
||||||
|
* XORed with the mask.
|
||||||
|
*/
|
||||||
|
extern volatile int _fih_mask;
|
||||||
|
typedef volatile struct {
|
||||||
|
volatile int val;
|
||||||
|
volatile int msk;
|
||||||
|
} fih_int;
|
||||||
|
typedef volatile int fih_ret;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef int fih_int;
|
||||||
|
typedef int fih_ret;
|
||||||
|
|
||||||
|
#endif /* FIH_ENABLE_DOUBLE_VARS */
|
||||||
|
|
||||||
|
extern fih_ret FIH_SUCCESS;
|
||||||
|
extern fih_ret FIH_FAILURE;
|
||||||
|
extern fih_ret FIH_NO_BOOTABLE_IMAGE;
|
||||||
|
extern fih_ret FIH_BOOT_HOOK_REGULAR;
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_GLOBAL_FAIL
|
||||||
|
/* Global failure handler - more resistant to unlooping. noinline and used are
|
||||||
|
* used to prevent optimization
|
||||||
|
*/
|
||||||
|
__attribute__((noinline)) __attribute__((used))
|
||||||
|
void fih_panic_loop(void);
|
||||||
|
#define FIH_PANIC fih_panic_loop()
|
||||||
|
#else
|
||||||
|
#define FIH_PANIC while (1) {}
|
||||||
|
#endif /* FIH_ENABLE_GLOBAL_FAIL */
|
||||||
|
|
||||||
|
/* NOTE: For functions to be inlined outside their compilation unit they have to
|
||||||
|
* have the body in the header file. This is required as function calls are easy
|
||||||
|
* to skip.
|
||||||
|
*/
|
||||||
|
#ifdef FIH_ENABLE_DELAY
|
||||||
|
|
||||||
|
/* Delaying logic, with randomness from a CSPRNG */
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
int fih_delay(void)
|
||||||
|
{
|
||||||
|
unsigned char delay;
|
||||||
|
int foo = 0;
|
||||||
|
volatile int rc;
|
||||||
|
|
||||||
|
delay = fih_delay_random_uchar();
|
||||||
|
|
||||||
|
for (volatile int i = 0; i < delay; i++) {
|
||||||
|
foo++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = 1;
|
||||||
|
|
||||||
|
/* rc is volatile so if it is the return value then the function cannot be
|
||||||
|
* optimized
|
||||||
|
*/
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
int fih_delay_init(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
int fih_delay(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* FIH_ENABLE_DELAY */
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_DOUBLE_VARS
|
||||||
|
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
void fih_int_validate(fih_int x)
|
||||||
|
{
|
||||||
|
if (x.val != (x.msk ^ _fih_mask)) {
|
||||||
|
FIH_PANIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a fih_int to an int. Validate for tampering. */
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
int fih_int_decode(fih_int x)
|
||||||
|
{
|
||||||
|
fih_int_validate(x);
|
||||||
|
return x.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert an int to a fih_int, can be used to encode specific error codes. */
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
fih_int fih_int_encode(int x)
|
||||||
|
{
|
||||||
|
fih_int ret = {x, x ^ _fih_mask};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard equality. If A == B then 1, else 0 */
|
||||||
|
#define FIH_EQ(x, y) ((x == y) && fih_delay() && !(y != x))
|
||||||
|
#define FIH_NOT_EQ(x, y) ((x != y) || !fih_delay() || !(y == x))
|
||||||
|
#define FIH_SET(x, y) x = y; if(fih_delay() && (x != y)) FIH_PANIC
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* NOOP */
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
void fih_int_validate(fih_int x)
|
||||||
|
{
|
||||||
|
(void) x;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOOP */
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
int fih_int_decode(fih_int x)
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOOP */
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
fih_int fih_int_encode(int x)
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FIH_EQ(x, y) (x == y)
|
||||||
|
#define FIH_NOT_EQ(x, y) (x != y)
|
||||||
|
#define FIH_SET(x, y) x = y
|
||||||
|
|
||||||
|
#endif /* FIH_ENABLE_DOUBLE_VARS */
|
||||||
|
|
||||||
|
#define FIH_DECLARE(var, val) \
|
||||||
|
fih_ret FIH_SET(var, val)
|
||||||
|
|
||||||
|
/* C has a common return pattern where 0 is a correct value and all others are
|
||||||
|
* errors. This function converts 0 to FIH_SUCCESS and any other number to a
|
||||||
|
* value that is not FIH_SUCCESS
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) inline
|
||||||
|
fih_ret fih_ret_encode_zero_equality(int x)
|
||||||
|
{
|
||||||
|
if (x) {
|
||||||
|
return FIH_FAILURE;
|
||||||
|
} else {
|
||||||
|
return FIH_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_CFI
|
||||||
|
extern fih_int _fih_cfi_ctr;
|
||||||
|
#endif /* FIH_ENABLE_CFI */
|
||||||
|
|
||||||
|
fih_int fih_cfi_get_and_increment(void);
|
||||||
|
void fih_cfi_validate(fih_int saved);
|
||||||
|
void fih_cfi_decrement(void);
|
||||||
|
|
||||||
|
/* Label for interacting with FIH testing tool. Can be parsed from the elf file
|
||||||
|
* after compilation. Does not require debug symbols.
|
||||||
|
*/
|
||||||
|
#if defined(__ICCARM__)
|
||||||
|
#define FIH_LABEL(str, lin, cnt) __asm volatile ("FIH_LABEL_" str "_" #lin "_" #cnt "::" ::);
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define FIH_LABEL(str) do {} while (0)
|
||||||
|
#else
|
||||||
|
#define FIH_LABEL(str) __asm volatile ("FIH_LABEL_" str "_%=:" ::);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Main FIH calling macro. return variable is second argument. Does some setup
|
||||||
|
* before and validation afterwards. Inserts labels for use with testing script.
|
||||||
|
*
|
||||||
|
* First perform the precall step - this gets the current value of the CFI
|
||||||
|
* counter and saves it to a local variable, and then increments the counter.
|
||||||
|
*
|
||||||
|
* Then set the return variable to FIH_FAILURE as a base case.
|
||||||
|
*
|
||||||
|
* Then perform the function call. As part of the funtion FIH_RET must be called
|
||||||
|
* which will decrement the counter.
|
||||||
|
*
|
||||||
|
* The postcall step gets the value of the counter and compares it to the
|
||||||
|
* previously saved value. If this is equal then the function call and all child
|
||||||
|
* function calls were performed.
|
||||||
|
*/
|
||||||
|
#if defined(__ICCARM__)
|
||||||
|
#define FIH_CALL(f, ret, ...) FIH_CALL2(f, ret, __LINE__, __COUNTER__, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define FIH_CALL2(f, ret, l, c, ...) \
|
||||||
|
do { \
|
||||||
|
FIH_LABEL("FIH_CALL_START", l, c); \
|
||||||
|
FIH_CFI_PRECALL_BLOCK; \
|
||||||
|
ret = FIH_FAILURE; \
|
||||||
|
if (fih_delay()) { \
|
||||||
|
ret = f(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
FIH_CFI_POSTCALL_BLOCK; \
|
||||||
|
FIH_LABEL("FIH_CALL_END", l, c); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define FIH_CALL(f, ret, ...) \
|
||||||
|
do { \
|
||||||
|
FIH_LABEL("FIH_CALL_START"); \
|
||||||
|
FIH_CFI_PRECALL_BLOCK; \
|
||||||
|
ret = FIH_FAILURE; \
|
||||||
|
if (fih_delay()) { \
|
||||||
|
ret = f(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
FIH_CFI_POSTCALL_BLOCK; \
|
||||||
|
FIH_LABEL("FIH_CALL_END"); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FIH return changes the state of the internal state machine. If you do a
|
||||||
|
* FIH_CALL then you need to do a FIH_RET else the state machine will detect
|
||||||
|
* tampering and panic.
|
||||||
|
*/
|
||||||
|
#define FIH_RET(ret) \
|
||||||
|
do { \
|
||||||
|
FIH_CFI_PRERET; \
|
||||||
|
return ret; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_CFI
|
||||||
|
/* Macro wrappers for functions - Even when the functions have zero body this
|
||||||
|
* saves a few bytes on noop functions as it doesn't generate the call/ret
|
||||||
|
*
|
||||||
|
* CFI precall function saves the CFI counter and then increments it - the
|
||||||
|
* postcall then checks if the counter is equal to the saved value. In order for
|
||||||
|
* this to be the case a FIH_RET must have been performed inside the called
|
||||||
|
* function in order to decrement the counter, so the function must have been
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
#define FIH_CFI_PRECALL_BLOCK \
|
||||||
|
fih_int _fih_cfi_saved_value = fih_cfi_get_and_increment()
|
||||||
|
|
||||||
|
#define FIH_CFI_POSTCALL_BLOCK \
|
||||||
|
fih_cfi_validate(_fih_cfi_saved_value)
|
||||||
|
|
||||||
|
#define FIH_CFI_PRERET \
|
||||||
|
fih_cfi_decrement()
|
||||||
|
#else
|
||||||
|
#define FIH_CFI_PRECALL_BLOCK
|
||||||
|
#define FIH_CFI_POSTCALL_BLOCK
|
||||||
|
#define FIH_CFI_PRERET
|
||||||
|
#endif /* FIH_ENABLE_CFI */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* __FAULT_INJECTION_HARDENING_H__ */
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FAULT_INJECTION_HARDENING_DELAY_RNG_H__
|
||||||
|
#define __FAULT_INJECTION_HARDENING_DELAY_RNG_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set up the RNG for use with random delays. Called once at startup.
|
||||||
|
*/
|
||||||
|
int fih_delay_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get a random unsigned char from an RNG seeded with an entropy source.
|
||||||
|
*
|
||||||
|
* \return A random value that fits inside an unsigned char.
|
||||||
|
*/
|
||||||
|
unsigned char fih_delay_random_uchar(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* __FAULT_INJECTION_HARDENING_DELAY_RNG_H__ */
|
||||||
70
bootloader/mcuboot/boot/bootutil/include/bootutil/ignore.h
Normal file
70
bootloader/mcuboot/boot/bootutil/include/bootutil/ignore.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_IGNORE_
|
||||||
|
#define H_IGNORE_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These macros prevent the "set but not used" warnings for log writes below
|
||||||
|
* the log level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define IGN_1(X) ((void)(X))
|
||||||
|
#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__)
|
||||||
|
#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__)
|
||||||
|
#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__)
|
||||||
|
#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__)
|
||||||
|
#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__)
|
||||||
|
#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__)
|
||||||
|
#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__)
|
||||||
|
#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__)
|
||||||
|
#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__)
|
||||||
|
#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__)
|
||||||
|
#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__)
|
||||||
|
#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__)
|
||||||
|
#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__)
|
||||||
|
#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__)
|
||||||
|
#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__)
|
||||||
|
#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__)
|
||||||
|
#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__)
|
||||||
|
#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__)
|
||||||
|
#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
|
||||||
|
_13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME
|
||||||
|
#define IGNORE(...) \
|
||||||
|
GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \
|
||||||
|
IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \
|
||||||
|
IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
228
bootloader/mcuboot/boot/bootutil/include/bootutil/image.h
Normal file
228
bootloader/mcuboot/boot/bootutil/include/bootutil/image.h
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2023 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_IMAGE_
|
||||||
|
#define H_IMAGE_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __packed
|
||||||
|
#define __packed __attribute__((__packed__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct flash_area;
|
||||||
|
|
||||||
|
#define IMAGE_MAGIC 0x96f3b83d
|
||||||
|
#define IMAGE_MAGIC_V1 0x96f3b83c
|
||||||
|
#define IMAGE_MAGIC_NONE 0xffffffff
|
||||||
|
#define IMAGE_TLV_INFO_MAGIC 0x6907
|
||||||
|
#define IMAGE_TLV_PROT_INFO_MAGIC 0x6908
|
||||||
|
|
||||||
|
#define IMAGE_HEADER_SIZE 32
|
||||||
|
#define IMAGE_HASH_LEN 32 /* Size of SHA256 TLV hash */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Image header flags.
|
||||||
|
*/
|
||||||
|
#define IMAGE_F_PIC 0x00000001 /* Not supported. */
|
||||||
|
#define IMAGE_F_ENCRYPTED_AES128 0x00000004 /* Encrypted using AES128. */
|
||||||
|
#define IMAGE_F_ENCRYPTED_AES256 0x00000008 /* Encrypted using AES256. */
|
||||||
|
#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */
|
||||||
|
/*
|
||||||
|
* Indicates that this image should be loaded into RAM instead of run
|
||||||
|
* directly from flash. The address to load should be in the
|
||||||
|
* ih_load_addr field of the header.
|
||||||
|
*/
|
||||||
|
#define IMAGE_F_RAM_LOAD 0x00000020
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicates that ih_load_addr stores information on flash/ROM address the
|
||||||
|
* image has been built for.
|
||||||
|
*/
|
||||||
|
#define IMAGE_F_ROM_FIXED 0x00000100
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags that indicate if the image data is compressed
|
||||||
|
*/
|
||||||
|
#define IMAGE_F_COMPRESSED_LZMA1 0x00000200
|
||||||
|
#define IMAGE_F_COMPRESSED_LZMA2 0x00000400
|
||||||
|
#define IMAGE_F_COMPRESSED_ARM_THUMB_FLT 0x00000800
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ECSDA224 is with NIST P-224
|
||||||
|
* ECSDA256 is with NIST P-256
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Image trailer TLV types.
|
||||||
|
*
|
||||||
|
* Signature is generated by computing signature over the image hash.
|
||||||
|
*
|
||||||
|
* Signature comes in the form of 2 TLVs.
|
||||||
|
* 1st on identifies the public key which should be used to verify it.
|
||||||
|
* 2nd one is the actual signature.
|
||||||
|
*/
|
||||||
|
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
|
||||||
|
#define IMAGE_TLV_PUBKEY 0x02 /* public key */
|
||||||
|
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
|
||||||
|
#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */
|
||||||
|
#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */
|
||||||
|
#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */
|
||||||
|
#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */
|
||||||
|
#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */
|
||||||
|
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
|
||||||
|
#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */
|
||||||
|
#define IMAGE_TLV_SIG_PURE 0x25 /* Indicator that attached signature has been prepared
|
||||||
|
* over image rather than its digest.
|
||||||
|
*/
|
||||||
|
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
|
||||||
|
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/
|
||||||
|
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */
|
||||||
|
#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
|
||||||
|
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
|
||||||
|
#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */
|
||||||
|
#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */
|
||||||
|
/* The following flags relate to compressed images and are for the decompressed image data */
|
||||||
|
#define IMAGE_TLV_DECOMP_SIZE 0x70 /* Decompressed image size excluding header/TLVs */
|
||||||
|
#define IMAGE_TLV_DECOMP_SHA 0x71 /*
|
||||||
|
* Decompressed image shaX hash, this field must match
|
||||||
|
* the format and size of the raw slot (compressed)
|
||||||
|
* shaX hash
|
||||||
|
*/
|
||||||
|
#define IMAGE_TLV_DECOMP_SIGNATURE 0x72 /*
|
||||||
|
* Decompressed image signature, this field must match
|
||||||
|
* the format and size of the raw slot (compressed)
|
||||||
|
* signature
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* vendor reserved TLVs at xxA0-xxFF,
|
||||||
|
* where xx denotes the upper byte
|
||||||
|
* range. Examples:
|
||||||
|
* 0x00a0 - 0x00ff
|
||||||
|
* 0x01a0 - 0x01ff
|
||||||
|
* 0x02a0 - 0x02ff
|
||||||
|
* ...
|
||||||
|
* 0xffa0 - 0xfffe
|
||||||
|
*/
|
||||||
|
#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */
|
||||||
|
|
||||||
|
struct image_version {
|
||||||
|
uint8_t iv_major;
|
||||||
|
uint8_t iv_minor;
|
||||||
|
uint16_t iv_revision;
|
||||||
|
uint32_t iv_build_num;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct image_dependency {
|
||||||
|
uint8_t image_id; /* Image index (from 0) */
|
||||||
|
uint8_t _pad1;
|
||||||
|
uint16_t _pad2;
|
||||||
|
struct image_version image_min_version; /* Indicates at minimum which
|
||||||
|
* version of firmware must be
|
||||||
|
* available to satisfy compliance
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Image header. All fields are in little endian byte order. */
|
||||||
|
struct image_header {
|
||||||
|
uint32_t ih_magic;
|
||||||
|
uint32_t ih_load_addr;
|
||||||
|
uint16_t ih_hdr_size; /* Size of image header (bytes). */
|
||||||
|
uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
|
||||||
|
uint32_t ih_img_size; /* Does not include header. */
|
||||||
|
uint32_t ih_flags; /* IMAGE_F_[...]. */
|
||||||
|
struct image_version ih_ver;
|
||||||
|
uint32_t _pad1;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/** Image TLV header. All fields in little endian. */
|
||||||
|
struct image_tlv_info {
|
||||||
|
uint16_t it_magic;
|
||||||
|
uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/** Image trailer TLV format. All fields in little endian. */
|
||||||
|
struct image_tlv {
|
||||||
|
uint16_t it_type; /* IMAGE_TLV_[...]. */
|
||||||
|
uint16_t it_len; /* Data length (not including TLV header). */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define ENCRYPTIONFLAGS (IMAGE_F_ENCRYPTED_AES128 | IMAGE_F_ENCRYPTED_AES256)
|
||||||
|
#define IS_ENCRYPTED(hdr) (((hdr)->ih_flags & IMAGE_F_ENCRYPTED_AES128) \
|
||||||
|
|| ((hdr)->ih_flags & IMAGE_F_ENCRYPTED_AES256))
|
||||||
|
#define MUST_DECRYPT(fap, idx, hdr) \
|
||||||
|
(flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_ENCRYPTED(hdr))
|
||||||
|
|
||||||
|
#define COMPRESSIONFLAGS (IMAGE_F_COMPRESSED_LZMA1 | IMAGE_F_COMPRESSED_LZMA2 \
|
||||||
|
| IMAGE_F_COMPRESSED_ARM_THUMB_FLT)
|
||||||
|
#define IS_COMPRESSED(hdr) ((hdr)->ih_flags & COMPRESSIONFLAGS)
|
||||||
|
#define MUST_DECOMPRESS(fap, idx, hdr) \
|
||||||
|
(flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_COMPRESSED(hdr))
|
||||||
|
|
||||||
|
_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE,
|
||||||
|
"struct image_header not required size");
|
||||||
|
|
||||||
|
struct enc_key_data;
|
||||||
|
fih_ret bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
|
||||||
|
struct image_header *hdr,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
uint8_t *tmp_buf, uint32_t tmp_buf_sz,
|
||||||
|
uint8_t *seed, int seed_len, uint8_t *out_hash);
|
||||||
|
|
||||||
|
struct image_tlv_iter {
|
||||||
|
const struct image_header *hdr;
|
||||||
|
const struct flash_area *fap;
|
||||||
|
uint16_t type;
|
||||||
|
bool prot;
|
||||||
|
uint32_t prot_end;
|
||||||
|
uint32_t tlv_off;
|
||||||
|
uint32_t tlv_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
int bootutil_tlv_iter_begin(struct image_tlv_iter *it,
|
||||||
|
const struct image_header *hdr,
|
||||||
|
const struct flash_area *fap, uint16_t type,
|
||||||
|
bool prot);
|
||||||
|
int bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off,
|
||||||
|
uint16_t *len, uint16_t *type);
|
||||||
|
int bootutil_tlv_iter_is_prot(struct image_tlv_iter *it, uint32_t off);
|
||||||
|
|
||||||
|
int32_t bootutil_get_img_security_cnt(struct image_header *hdr,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
uint32_t *security_cnt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Laird Connectivity
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_MCUBOOT_STATUS_
|
||||||
|
#define H_MCUBOOT_STATUS_
|
||||||
|
|
||||||
|
/* Enumeration representing the states that MCUboot can be in */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MCUBOOT_STATUS_STARTUP = 0,
|
||||||
|
MCUBOOT_STATUS_UPGRADING,
|
||||||
|
MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND,
|
||||||
|
MCUBOOT_STATUS_NO_BOOTABLE_IMAGE_FOUND,
|
||||||
|
MCUBOOT_STATUS_BOOT_FAILED,
|
||||||
|
MCUBOOT_STATUS_USB_DFU_WAITING,
|
||||||
|
MCUBOOT_STATUS_USB_DFU_ENTERED,
|
||||||
|
MCUBOOT_STATUS_USB_DFU_TIMED_OUT,
|
||||||
|
MCUBOOT_STATUS_SERIAL_DFU_ENTERED,
|
||||||
|
} mcuboot_status_type_t;
|
||||||
|
|
||||||
|
#if defined(CONFIG_MCUBOOT_ACTION_HOOKS)
|
||||||
|
extern void mcuboot_status_change(mcuboot_status_type_t status);
|
||||||
|
#else
|
||||||
|
#define mcuboot_status_change(_status) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* H_MCUBOOT_STATUS_ */
|
||||||
35
bootloader/mcuboot/boot/bootutil/include/bootutil/ramload.h
Normal file
35
bootloader/mcuboot/boot/bootutil/include/bootutil/ramload.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RAMLOAD_H__
|
||||||
|
#define __RAMLOAD_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
|
||||||
|
/**
|
||||||
|
* Provides information about the Executable RAM for a given image ID.
|
||||||
|
*
|
||||||
|
* @param image_id Index of the image (from 0).
|
||||||
|
* @param exec_ram_start Pointer to store the start address of the exec RAM
|
||||||
|
* @param exec_ram_size Pointer to store the size of the exec RAM
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_get_image_exec_ram_info(uint32_t image_id,
|
||||||
|
uint32_t *exec_ram_start,
|
||||||
|
uint32_t *exec_ram_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __RAMLOAD_H__ */
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020, Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SECURITY_CNT_H__
|
||||||
|
#define __SECURITY_CNT_H__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file security_cnt.h
|
||||||
|
*
|
||||||
|
* @note The interface must be implemented in a fail-safe way that is
|
||||||
|
* resistant to asynchronous power failures or it can use hardware
|
||||||
|
* counters that have this capability, if supported by the platform.
|
||||||
|
* When a counter incrementation was interrupted it must be able to
|
||||||
|
* continue the incrementation process or recover the previous consistent
|
||||||
|
* status of the counters. If the counters have reached a stable status
|
||||||
|
* (every counter incrementation operation has finished), from that point
|
||||||
|
* their value cannot decrease due to any kind of power failure.
|
||||||
|
*
|
||||||
|
* @note A security counter might be implemented using non-volatile OTP memory
|
||||||
|
* (i.e. fuses) in which case it is the responsibility of the platform
|
||||||
|
* code to map each possible security counter values onto the fuse bits
|
||||||
|
* as the direct usage of counter values can be costly / impractical.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the security counters.
|
||||||
|
*
|
||||||
|
* @return FIH_SUCCESS on success
|
||||||
|
*/
|
||||||
|
fih_ret boot_nv_security_counter_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the stored value of a given image's security counter.
|
||||||
|
*
|
||||||
|
* @param image_id Index of the image (from 0).
|
||||||
|
* @param security_cnt Pointer to store the security counter value.
|
||||||
|
*
|
||||||
|
* @return FIH_SUCCESS on success
|
||||||
|
*/
|
||||||
|
fih_ret boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the stored value of a given image's security counter with a new
|
||||||
|
* security counter value if the new one is greater.
|
||||||
|
*
|
||||||
|
* @param image_id Index of the image (from 0).
|
||||||
|
* @param img_security_cnt New security counter value. The new value must be
|
||||||
|
* between 0 and UINT32_MAX and it must be greater than
|
||||||
|
* or equal to the current security counter value.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int32_t boot_nv_security_counter_update(uint32_t image_id,
|
||||||
|
uint32_t img_security_cnt);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SECURITY_CNT_H__ */
|
||||||
71
bootloader/mcuboot/boot/bootutil/include/bootutil/sign_key.h
Normal file
71
bootloader/mcuboot/boot/bootutil/include/bootutil/sign_key.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOTUTIL_SIGN_KEY_H_
|
||||||
|
#define __BOOTUTIL_SIGN_KEY_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* mcuboot_config.h is needed for MCUBOOT_HW_KEY to work */
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_HW_KEY
|
||||||
|
struct bootutil_key {
|
||||||
|
const uint8_t *key;
|
||||||
|
const unsigned int *len;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct bootutil_key bootutil_keys[];
|
||||||
|
#else
|
||||||
|
struct bootutil_key {
|
||||||
|
uint8_t *key;
|
||||||
|
unsigned int *len;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct bootutil_key bootutil_keys[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the hash of the corresponding public key for image authentication.
|
||||||
|
*
|
||||||
|
* @param[in] image_index Index of the image to be authenticated.
|
||||||
|
* @param[out] public_key_hash Buffer to store the key-hash in.
|
||||||
|
* @param[in,out] key_hash_size As input the size of the buffer. As output
|
||||||
|
* the actual key-hash length.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int boot_retrieve_public_key_hash(uint8_t image_index,
|
||||||
|
uint8_t *public_key_hash,
|
||||||
|
size_t *key_hash_size);
|
||||||
|
#endif /* !MCUBOOT_HW_KEY */
|
||||||
|
|
||||||
|
extern const int bootutil_key_cnt;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BOOTUTIL_SIGN_KEY_H_ */
|
||||||
65
bootloader/mcuboot/boot/bootutil/pkg.yml
Normal file
65
bootloader/mcuboot/boot/bootutil/pkg.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
pkg.name: boot/bootutil
|
||||||
|
pkg.description: The bootutil library performs most of the functions of a boot loader.
|
||||||
|
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||||
|
pkg.homepage: "http://mynewt.apache.org/"
|
||||||
|
pkg.keywords:
|
||||||
|
- boot
|
||||||
|
- bootloader
|
||||||
|
|
||||||
|
pkg.apis:
|
||||||
|
- bootloader
|
||||||
|
|
||||||
|
pkg.cflags:
|
||||||
|
- "-DMCUBOOT_MYNEWT=1"
|
||||||
|
|
||||||
|
pkg.cflags.BOOTUTIL_USE_MBED_TLS:
|
||||||
|
- '-DMBEDTLS_USER_CONFIG_FILE="mbedtls/config_mynewt.h"'
|
||||||
|
|
||||||
|
pkg.deps:
|
||||||
|
- "@mcuboot/boot/mynewt/mcuboot_config"
|
||||||
|
- "@apache-mynewt-core/hw/hal"
|
||||||
|
- "@apache-mynewt-core/kernel/os"
|
||||||
|
- "@apache-mynewt-core/sys/defs"
|
||||||
|
- "@mcuboot/boot/mynewt/flash_map_backend"
|
||||||
|
|
||||||
|
pkg.ign_files.BOOTUTIL_SINGLE_APPLICATION_SLOT:
|
||||||
|
- "loader.c"
|
||||||
|
- "swap_scratch.c"
|
||||||
|
|
||||||
|
pkg.deps.BOOTUTIL_USE_MBED_TLS:
|
||||||
|
- "@apache-mynewt-core/crypto/mbedtls"
|
||||||
|
|
||||||
|
pkg.deps.BOOTUTIL_USE_TINYCRYPT:
|
||||||
|
- "@mcuboot/ext/tinycrypt/lib"
|
||||||
|
- "@mcuboot/ext/mbedtls-asn1"
|
||||||
|
|
||||||
|
pkg.deps.BOOTUTIL_SIGN_ED25519:
|
||||||
|
- "@mcuboot/ext/tinycrypt/lib"
|
||||||
|
- "@mcuboot/ext/tinycrypt-sha512/lib"
|
||||||
|
- "@mcuboot/ext/mbedtls-asn1"
|
||||||
|
- "@mcuboot/ext/fiat"
|
||||||
|
|
||||||
|
pkg.deps.BOOTUTIL_ENCRYPT_X25519:
|
||||||
|
- "@mcuboot/ext/tinycrypt/lib"
|
||||||
|
- "@mcuboot/ext/tinycrypt-sha512/lib"
|
||||||
|
- "@mcuboot/ext/mbedtls-asn1"
|
||||||
|
- "@mcuboot/ext/fiat"
|
||||||
343
bootloader/mcuboot/boot/bootutil/src/boot_record.c
Normal file
343
bootloader/mcuboot/boot/bootutil/src/boot_record.c
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2023 Arm Limited
|
||||||
|
* Copyright (c) 2020 Linaro Limited
|
||||||
|
* Copyright (c) 2023, Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
#include "bootutil/crypto/sha.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
|
||||||
|
#include "bootutil/boot_record.h"
|
||||||
|
#include "bootutil/boot_status.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "flash_map_backend/flash_map_backend.h"
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION)
|
||||||
|
/**
|
||||||
|
* @var shared_memory_init_done
|
||||||
|
*
|
||||||
|
* @brief Indicates whether shared memory area was already initialized.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static bool shared_memory_init_done;
|
||||||
|
|
||||||
|
/* See in boot_record.h */
|
||||||
|
int
|
||||||
|
boot_add_data_to_shared_area(uint8_t major_type,
|
||||||
|
uint16_t minor_type,
|
||||||
|
size_t size,
|
||||||
|
const uint8_t *data)
|
||||||
|
{
|
||||||
|
struct shared_data_tlv_entry tlv_entry = {0};
|
||||||
|
struct shared_boot_data *boot_data;
|
||||||
|
uint16_t boot_data_size;
|
||||||
|
uintptr_t tlv_end, offset;
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
return SHARED_MEMORY_GEN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_data = (struct shared_boot_data *)MCUBOOT_SHARED_DATA_BASE;
|
||||||
|
|
||||||
|
/* Check whether first time to call this function. If does then initialise
|
||||||
|
* shared data area.
|
||||||
|
*/
|
||||||
|
if (!shared_memory_init_done) {
|
||||||
|
memset((void *)MCUBOOT_SHARED_DATA_BASE, 0, MCUBOOT_SHARED_DATA_SIZE);
|
||||||
|
boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
|
||||||
|
boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
|
||||||
|
shared_memory_init_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether TLV entry is already added.
|
||||||
|
* Get the boundaries of TLV section
|
||||||
|
*/
|
||||||
|
tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
|
||||||
|
offset = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
|
||||||
|
|
||||||
|
/* Iterates over the TLV section looks for the same entry if found then
|
||||||
|
* returns with error: SHARED_MEMORY_OVERWRITE
|
||||||
|
*/
|
||||||
|
while (offset < tlv_end) {
|
||||||
|
/* Create local copy to avoid unaligned access */
|
||||||
|
memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
|
||||||
|
if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
|
||||||
|
GET_MINOR(tlv_entry.tlv_type) == minor_type) {
|
||||||
|
return SHARED_MEMORY_OVERWRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add TLV entry */
|
||||||
|
tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
|
||||||
|
tlv_entry.tlv_len = size;
|
||||||
|
|
||||||
|
if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
|
||||||
|
SHARED_DATA_ENTRY_SIZE(size))) {
|
||||||
|
return SHARED_MEMORY_GEN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify overflow of shared area */
|
||||||
|
if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
|
||||||
|
return SHARED_MEMORY_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = tlv_end;
|
||||||
|
memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
|
||||||
|
|
||||||
|
offset += SHARED_DATA_ENTRY_HEADER_SIZE;
|
||||||
|
memcpy((void *)offset, data, size);
|
||||||
|
|
||||||
|
boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
|
||||||
|
|
||||||
|
return SHARED_MEMORY_OK;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
|
||||||
|
#endif /* !MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION */
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_MEASURED_BOOT
|
||||||
|
/* See in boot_record.h */
|
||||||
|
int
|
||||||
|
boot_save_boot_status(uint8_t sw_module,
|
||||||
|
const struct image_header *hdr,
|
||||||
|
const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct image_tlv_iter it;
|
||||||
|
uint32_t offset;
|
||||||
|
uint16_t len;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t ias_minor;
|
||||||
|
size_t record_len = 0;
|
||||||
|
uint8_t image_hash[IMAGE_HASH_SIZE];
|
||||||
|
uint8_t buf[MAX_BOOT_RECORD_SZ];
|
||||||
|
bool boot_record_found = false;
|
||||||
|
bool hash_found = false;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Manifest data is concatenated to the end of the image.
|
||||||
|
* It is encoded in TLV format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse through the TLV area to find the boot record
|
||||||
|
* and image hash TLVs.
|
||||||
|
*/
|
||||||
|
while (true) {
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
|
||||||
|
if (rc < 0) {
|
||||||
|
return -1;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IMAGE_TLV_BOOT_RECORD) {
|
||||||
|
if (len > sizeof(buf)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rc = flash_area_read(fap, offset, buf, len);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
record_len = len;
|
||||||
|
boot_record_found = true;
|
||||||
|
|
||||||
|
} else if (type == EXPECTED_HASH_TLV) {
|
||||||
|
/* Get the image's hash value from the manifest section. */
|
||||||
|
if (len > sizeof(image_hash)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rc = flash_area_read(fap, offset, image_hash, len);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_found = true;
|
||||||
|
|
||||||
|
/* The boot record TLV is part of the protected TLV area which is
|
||||||
|
* located before the other parts of the TLV area (including the
|
||||||
|
* image hash) so at this point it is okay to break the loop
|
||||||
|
* as the boot record TLV should have already been found.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boot_record_found || !hash_found) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that we have enough in the record for the hash. This
|
||||||
|
* prevents an underflow in the calculation below.
|
||||||
|
*/
|
||||||
|
if (record_len < sizeof(image_hash)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the measurement value (hash of the image) data item in the
|
||||||
|
* boot record. It is always the last item in the structure to make
|
||||||
|
* it easy to calculate its position.
|
||||||
|
* The image hash is computed over the image header, the image itself and
|
||||||
|
* the protected TLV area (which should already include the image hash as
|
||||||
|
* part of the boot record TLV). For this reason this field has been
|
||||||
|
* filled with zeros during the image signing process.
|
||||||
|
*/
|
||||||
|
offset = record_len - sizeof(image_hash);
|
||||||
|
/* The size of 'buf' has already been checked when
|
||||||
|
* the BOOT_RECORD TLV was read, it won't overflow.
|
||||||
|
*/
|
||||||
|
memcpy(buf + offset, image_hash, sizeof(image_hash));
|
||||||
|
|
||||||
|
/* Add the CBOR encoded boot record to the shared data area. */
|
||||||
|
ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
|
||||||
|
ias_minor,
|
||||||
|
record_len,
|
||||||
|
buf);
|
||||||
|
if (rc != SHARED_MEMORY_OK) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_MEASURED_BOOT */
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_DATA_SHARING_BOOTINFO
|
||||||
|
int boot_save_shared_data(const struct image_header *hdr, const struct flash_area *fap,
|
||||||
|
const uint8_t slot, const struct image_max_size *max_app_sizes)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint8_t image = 0;
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_SINGLE_SLOT;
|
||||||
|
#elif defined(MCUBOOT_SWAP_USING_SCRATCH)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_SWAP_USING_SCRATCH;
|
||||||
|
#elif defined(MCUBOOT_OVERWRITE_ONLY)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_UPGRADE_ONLY;
|
||||||
|
#elif defined(MCUBOOT_SWAP_USING_MOVE)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_SWAP_USING_MOVE;
|
||||||
|
#elif defined(MCUBOOT_DIRECT_XIP)
|
||||||
|
#if defined(MCUBOOT_DIRECT_XIP_REVERT)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT;
|
||||||
|
#else
|
||||||
|
uint8_t mode = MCUBOOT_MODE_DIRECT_XIP;
|
||||||
|
#endif
|
||||||
|
#elif defined(MCUBOOT_RAM_LOAD)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_RAM_LOAD;
|
||||||
|
#elif defined(MCUBOOT_FIRMWARE_LOADER)
|
||||||
|
uint8_t mode = MCUBOOT_MODE_FIRMWARE_LOADER;
|
||||||
|
#else
|
||||||
|
#error "Unknown mcuboot operating mode"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_RSA)
|
||||||
|
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_RSA;
|
||||||
|
#elif defined(MCUBOOT_SIGN_EC256)
|
||||||
|
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ECDSA_P256;
|
||||||
|
#elif defined(MCUBOOT_SIGN_ED25519)
|
||||||
|
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ED25519;
|
||||||
|
#else
|
||||||
|
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_NONE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SERIAL_RECOVERY)
|
||||||
|
uint8_t recovery = MCUBOOT_RECOVERY_MODE_SERIAL_RECOVERY;
|
||||||
|
#elif defined(MCUBOOT_USB_DFU)
|
||||||
|
uint8_t recovery = MCUBOOT_RECOVERY_MODE_DFU;
|
||||||
|
#else
|
||||||
|
uint8_t recovery = MCUBOOT_RECOVERY_MODE_NONE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_VERSION_AVAILABLE)
|
||||||
|
struct image_version mcuboot_version = {
|
||||||
|
.iv_major = MCUBOOT_VERSION_MAJOR,
|
||||||
|
.iv_minor = MCUBOOT_VERSION_MINOR,
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_VERSION_PATCHLEVEL)
|
||||||
|
.iv_revision = MCUBOOT_VERSION_PATCHLEVEL,
|
||||||
|
#else
|
||||||
|
.iv_revision = 0,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_VERSION_TWEAK)
|
||||||
|
.iv_build_num = MCUBOOT_VERSION_TWEAK,
|
||||||
|
#else
|
||||||
|
.iv_build_num = 0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write out all fields */
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO, BLINFO_MODE,
|
||||||
|
sizeof(mode), &mode);
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
|
||||||
|
BLINFO_SIGNATURE_TYPE,
|
||||||
|
sizeof(signature_type),
|
||||||
|
&signature_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
|
||||||
|
BLINFO_RECOVERY,
|
||||||
|
sizeof(recovery), &recovery);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
|
||||||
|
BLINFO_RUNNING_SLOT,
|
||||||
|
sizeof(slot), (void *)&slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_VERSION_AVAILABLE)
|
||||||
|
if (!rc) {
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
|
||||||
|
BLINFO_BOOTLOADER_VERSION,
|
||||||
|
sizeof(mcuboot_version),
|
||||||
|
(void *)&mcuboot_version);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (image < BOOT_IMAGE_NUMBER && !rc) {
|
||||||
|
if (max_app_sizes[image].calculated == true) {
|
||||||
|
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
|
||||||
|
(BLINFO_MAX_APPLICATION_SIZE + image),
|
||||||
|
sizeof(max_app_sizes[image].max_size),
|
||||||
|
(void *)&max_app_sizes[image].max_size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
++image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_DATA_SHARING_BOOTINFO */
|
||||||
357
bootloader/mcuboot/boot/bootutil/src/bootutil_misc.c
Normal file
357
bootloader/mcuboot/boot/bootutil/src/bootutil_misc.c
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2020 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "sysflash/sysflash.h"
|
||||||
|
#include "flash_map_backend/flash_map_backend.h"
|
||||||
|
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "bootutil_misc.h"
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
#include "bootutil/enc_key.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
|
||||||
|
/* Currently only used by imgmgr */
|
||||||
|
int boot_current_slot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determine if the data at two memory addresses is equal
|
||||||
|
*
|
||||||
|
* @param s1 The first memory region to compare.
|
||||||
|
* @param s2 The second memory region to compare.
|
||||||
|
* @param n The amount of bytes to compare.
|
||||||
|
*
|
||||||
|
* @note This function does not comply with the specification of memcmp,
|
||||||
|
* so should not be considered a drop-in replacement. It has no
|
||||||
|
* constant time execution. The point is to make sure that all the
|
||||||
|
* bytes are compared and detect if loop was abused and some cycles
|
||||||
|
* was skipped due to fault injection.
|
||||||
|
*
|
||||||
|
* @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
|
||||||
|
*/
|
||||||
|
#ifdef MCUBOOT_FIH_PROFILE_OFF
|
||||||
|
inline
|
||||||
|
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
return memcmp(s1, s2, n);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t *s1_p = (uint8_t*) s1;
|
||||||
|
uint8_t *s2_p = (uint8_t*) s2;
|
||||||
|
FIH_DECLARE(ret, FIH_FAILURE);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (s1_p[i] != s2_p[i]) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == n) {
|
||||||
|
ret = FIH_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
FIH_RET(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Amount of space used to save information required when doing a swap,
|
||||||
|
* or while a swap is under progress, but not the status of sector swap
|
||||||
|
* progress itself.
|
||||||
|
*/
|
||||||
|
static inline uint32_t
|
||||||
|
boot_trailer_info_sz(void)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
/* encryption keys */
|
||||||
|
# if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
BOOT_ENC_TLV_ALIGN_SIZE * 2 +
|
||||||
|
# else
|
||||||
|
BOOT_ENC_KEY_ALIGN_SIZE * 2 +
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
/* swap_type + copy_done + image_ok + swap_size */
|
||||||
|
BOOT_MAX_ALIGN * 4 +
|
||||||
|
BOOT_MAGIC_ALIGN_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Amount of space used to maintain progress information for a single swap
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
static inline uint32_t
|
||||||
|
boot_status_entry_sz(uint32_t min_write_sz)
|
||||||
|
{
|
||||||
|
return BOOT_STATUS_STATE_COUNT * min_write_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
boot_status_sz(uint32_t min_write_sz)
|
||||||
|
{
|
||||||
|
return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
boot_trailer_sz(uint32_t min_write_sz)
|
||||||
|
{
|
||||||
|
return boot_status_sz(min_write_sz) + boot_trailer_info_sz();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
/*
|
||||||
|
* Similar to `boot_trailer_sz` but this function returns the space used to
|
||||||
|
* store status in the scratch partition. The scratch partition only stores
|
||||||
|
* status during the swap of the last sector from primary/secondary (which
|
||||||
|
* is the first swap operation) and thus only requires space for one swap.
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
boot_scratch_trailer_sz(uint32_t min_write_sz)
|
||||||
|
{
|
||||||
|
return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_status_entries(int image_index, const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SCRATCH) {
|
||||||
|
return BOOT_STATUS_STATE_COUNT;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
|
||||||
|
flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
|
||||||
|
return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
boot_status_off(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
uint32_t off_from_end;
|
||||||
|
uint32_t elem_sz;
|
||||||
|
|
||||||
|
elem_sz = flash_area_align(fap);
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
|
||||||
|
off_from_end = boot_scratch_trailer_sz(elem_sz);
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
off_from_end = boot_trailer_sz(elem_sz);
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(off_from_end <= flash_area_get_size(fap));
|
||||||
|
return flash_area_get_size(fap) - off_from_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
static inline uint32_t
|
||||||
|
boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
|
||||||
|
{
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_ALIGN_SIZE);
|
||||||
|
#else
|
||||||
|
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_ALIGN_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions tries to locate the status area after an aborted swap,
|
||||||
|
* by looking for the magic in the possible locations.
|
||||||
|
*
|
||||||
|
* If the magic is successfully found, a flash_area * is returned and it
|
||||||
|
* is the responsibility of the called to close it.
|
||||||
|
*
|
||||||
|
* @returns 0 on success, -1 on errors
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_find_status(int image_index, const struct flash_area **fap)
|
||||||
|
{
|
||||||
|
uint8_t areas[] = {
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
FLASH_AREA_IMAGE_SCRATCH,
|
||||||
|
#endif
|
||||||
|
FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
};
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the middle a swap, tries to locate the area that is currently
|
||||||
|
* storing a valid magic, first on the primary slot, then on scratch.
|
||||||
|
* Both "slots" can end up being temporary storage for a swap and it
|
||||||
|
* is assumed that if magic is valid then other metadata is too,
|
||||||
|
* because magic is always written in the last step.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
|
||||||
|
uint8_t magic[BOOT_MAGIC_SZ];
|
||||||
|
|
||||||
|
if (flash_area_open(areas[i], fap)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flash_area_read(*fap, boot_magic_off(*fap), magic, BOOT_MAGIC_SZ)) {
|
||||||
|
flash_area_close(*fap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOOT_MAGIC_GOOD == boot_magic_decode(magic)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_area_close(*fap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we got here, no magic was found */
|
||||||
|
fap = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
off = boot_swap_size_off(fap);
|
||||||
|
rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
int
|
||||||
|
boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
uint32_t i;
|
||||||
|
#endif
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
off = boot_enc_key_off(fap, slot);
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
|
||||||
|
if (rc == 0) {
|
||||||
|
for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
|
||||||
|
if (bs->enctlv[slot][i] != 0xff) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Only try to decrypt non-erased TLV metadata */
|
||||||
|
if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
|
||||||
|
rc = boot_decrypt_key(bs->enctlv[slot], bs->enckey[slot]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
|
||||||
|
off = boot_swap_size_off(fap);
|
||||||
|
BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%lx (0x%lx)",
|
||||||
|
flash_area_get_id(fap), (unsigned long)off,
|
||||||
|
(unsigned long)flash_area_get_off(fap) + off);
|
||||||
|
return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
int
|
||||||
|
boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
|
||||||
|
const struct boot_status *bs)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
off = boot_enc_key_off(fap, slot);
|
||||||
|
BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
|
||||||
|
flash_area_get_id(fap), (unsigned long)off,
|
||||||
|
(unsigned long)flash_area_get_off(fap) + off);
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
|
||||||
|
#else
|
||||||
|
rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
|
||||||
|
#endif
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t bootutil_max_image_size(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \
|
||||||
|
defined(MCUBOOT_FIRMWARE_LOADER)
|
||||||
|
return boot_status_off(fap);
|
||||||
|
#elif defined(MCUBOOT_SWAP_USING_MOVE)
|
||||||
|
struct flash_sector sector;
|
||||||
|
/* get the last sector offset */
|
||||||
|
int rc = flash_area_get_sector(fap, boot_status_off(fap), §or);
|
||||||
|
if (rc) {
|
||||||
|
BOOT_LOG_ERR("Unable to determine flash sector of the image trailer");
|
||||||
|
return 0; /* Returning of zero here should cause any check which uses
|
||||||
|
* this value to fail.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return flash_sector_get_off(§or);
|
||||||
|
#elif defined(MCUBOOT_OVERWRITE_ONLY)
|
||||||
|
return boot_swap_info_off(fap);
|
||||||
|
#elif defined(MCUBOOT_DIRECT_XIP)
|
||||||
|
return boot_swap_info_off(fap);
|
||||||
|
#elif defined(MCUBOOT_RAM_LOAD)
|
||||||
|
return boot_swap_info_off(fap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
52
bootloader/mcuboot/boot/bootutil/src/bootutil_misc.h
Normal file
52
bootloader/mcuboot/boot/bootutil/src/bootutil_misc.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef H_BOOTUTIL_MISC_
|
||||||
|
#define H_BOOTUTIL_MISC_
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "bootutil/bootutil_public.h"
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
#include "bootutil/enc_key.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
boot_magic_decode(const uint8_t *magic)
|
||||||
|
{
|
||||||
|
if (memcmp(magic, BOOT_IMG_MAGIC, BOOT_MAGIC_SZ) == 0) {
|
||||||
|
return BOOT_MAGIC_GOOD;
|
||||||
|
}
|
||||||
|
return BOOT_MAGIC_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
boot_magic_off(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
boot_image_ok_off(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
boot_copy_done_off(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
boot_swap_size_off(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* H_BOOTUTIL_MISC_ */
|
||||||
486
bootloader/mcuboot/boot/bootutil/src/bootutil_priv.h
Normal file
486
bootloader/mcuboot/boot/bootutil/src/bootutil_priv.h
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2020 Linaro LTD
|
||||||
|
* Copyright (c) 2017-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2021 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_BOOTUTIL_PRIV_
|
||||||
|
#define H_BOOTUTIL_PRIV_
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sysflash/sysflash.h"
|
||||||
|
|
||||||
|
#include <flash_map_backend/flash_map_backend.h>
|
||||||
|
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
#include "bootutil/enc_key.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct flash_area;
|
||||||
|
|
||||||
|
#define BOOT_TMPBUF_SZ 256
|
||||||
|
|
||||||
|
/** Number of image slots in flash; currently limited to two. */
|
||||||
|
#define BOOT_NUM_SLOTS 2
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_OVERWRITE_ONLY) + \
|
||||||
|
defined(MCUBOOT_SWAP_USING_MOVE) + \
|
||||||
|
defined(MCUBOOT_DIRECT_XIP) + \
|
||||||
|
defined(MCUBOOT_RAM_LOAD) + \
|
||||||
|
defined(MCUBOOT_FIRMWARE_LOADER) + \
|
||||||
|
defined(MCUBOOT_SWAP_USING_SCRATCH)) > 1
|
||||||
|
#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP, MCUBOOT_RAM_LOAD or MCUBOOT_FIRMWARE_LOADER"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_DIRECT_XIP) && \
|
||||||
|
defined(MCUBOOT_DIRECT_XIP_REVERT)
|
||||||
|
#error "MCUBOOT_DIRECT_XIP_REVERT cannot be enabled unless MCUBOOT_DIRECT_XIP is used"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_OVERWRITE_ONLY) && \
|
||||||
|
!defined(MCUBOOT_SWAP_USING_MOVE) && \
|
||||||
|
!defined(MCUBOOT_DIRECT_XIP) && \
|
||||||
|
!defined(MCUBOOT_RAM_LOAD) && \
|
||||||
|
!defined(MCUBOOT_SINGLE_APPLICATION_SLOT) && \
|
||||||
|
!defined(MCUBOOT_FIRMWARE_LOADER)
|
||||||
|
#define MCUBOOT_SWAP_USING_SCRATCH 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOT_STATUS_OP_MOVE 1
|
||||||
|
#define BOOT_STATUS_OP_SWAP 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maintain state of copy progress.
|
||||||
|
*/
|
||||||
|
struct boot_status {
|
||||||
|
uint32_t idx; /* Which area we're operating on */
|
||||||
|
uint8_t state; /* Which part of the swapping process are we at */
|
||||||
|
uint8_t op; /* What operation are we performing? */
|
||||||
|
uint8_t use_scratch; /* Are status bytes ever written to scratch? */
|
||||||
|
uint8_t swap_type; /* The type of swap in effect */
|
||||||
|
uint32_t swap_size; /* Total size of swapped image */
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
uint8_t enckey[BOOT_NUM_SLOTS][BOOT_ENC_KEY_ALIGN_SIZE];
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
uint8_t enctlv[BOOT_NUM_SLOTS][BOOT_ENC_TLV_ALIGN_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
int source; /* Which slot contains swap status metadata */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BOOT_STATUS_IDX_0 1
|
||||||
|
|
||||||
|
#define BOOT_STATUS_STATE_0 1
|
||||||
|
#define BOOT_STATUS_STATE_1 2
|
||||||
|
#define BOOT_STATUS_STATE_2 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End-of-image slot structure.
|
||||||
|
*
|
||||||
|
* 0 1 2 3
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* ~ ~
|
||||||
|
* ~ Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) ~
|
||||||
|
* ~ ~
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Encryption key 0 (16 octets) [*] |
|
||||||
|
* | |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | 0xff padding as needed |
|
||||||
|
* | (BOOT_MAX_ALIGN minus 16 octets from Encryption key 0) [*] |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Encryption key 1 (16 octets) [*] |
|
||||||
|
* | |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | 0xff padding as needed |
|
||||||
|
* | (BOOT_MAX_ALIGN minus 16 octets from Encryption key 1) [*] |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Swap size (4 octets) |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | 0xff padding as needed |
|
||||||
|
* | (BOOT_MAX_ALIGN minus 4 octets from Swap size) |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Swap info | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Copy done | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | Image OK | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | 0xff padding as needed |
|
||||||
|
* | (BOOT_MAX_ALIGN minus 16 octets from MAGIC) |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | MAGIC (16 octets) |
|
||||||
|
* | |
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*
|
||||||
|
* [*]: Only present if the encryption option is enabled
|
||||||
|
* (`MCUBOOT_ENC_IMAGES`).
|
||||||
|
*/
|
||||||
|
|
||||||
|
union boot_img_magic_t
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
uint16_t align;
|
||||||
|
uint8_t magic[14];
|
||||||
|
};
|
||||||
|
uint8_t val[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const union boot_img_magic_t boot_img_magic;
|
||||||
|
|
||||||
|
#define BOOT_IMG_MAGIC (boot_img_magic.val)
|
||||||
|
|
||||||
|
#if BOOT_MAX_ALIGN == 8
|
||||||
|
#define BOOT_IMG_ALIGN (BOOT_MAX_ALIGN)
|
||||||
|
#else
|
||||||
|
#define BOOT_IMG_ALIGN (boot_img_magic.align)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_Static_assert(sizeof(boot_img_magic) == BOOT_MAGIC_SZ, "Invalid size for image magic");
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
|
||||||
|
#define ARE_SLOTS_EQUIVALENT() 0
|
||||||
|
#else
|
||||||
|
#define ARE_SLOTS_EQUIVALENT() 1
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_ENC_IMAGES)
|
||||||
|
#error "Image encryption (MCUBOOT_ENC_IMAGES) is not supported when MCUBOOT_DIRECT_XIP is selected."
|
||||||
|
#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_ENC_IMAGES */
|
||||||
|
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
|
||||||
|
|
||||||
|
#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS
|
||||||
|
|
||||||
|
#define BOOT_LOG_IMAGE_INFO(slot, hdr) \
|
||||||
|
BOOT_LOG_INF("%-9s slot: version=%u.%u.%u+%u", \
|
||||||
|
((slot) == BOOT_PRIMARY_SLOT) ? "Primary" : "Secondary", \
|
||||||
|
(hdr)->ih_ver.iv_major, \
|
||||||
|
(hdr)->ih_ver.iv_minor, \
|
||||||
|
(hdr)->ih_ver.iv_revision, \
|
||||||
|
(hdr)->ih_ver.iv_build_num)
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_MOVE
|
||||||
|
#define BOOT_STATUS_MOVE_STATE_COUNT 1
|
||||||
|
#define BOOT_STATUS_SWAP_STATE_COUNT 2
|
||||||
|
#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT)
|
||||||
|
#else
|
||||||
|
#define BOOT_STATUS_STATE_COUNT 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Maximum number of image sectors supported by the bootloader. */
|
||||||
|
#define BOOT_STATUS_MAX_ENTRIES BOOT_MAX_IMG_SECTORS
|
||||||
|
|
||||||
|
#define BOOT_PRIMARY_SLOT 0
|
||||||
|
#define BOOT_SECONDARY_SLOT 1
|
||||||
|
|
||||||
|
#define BOOT_STATUS_SOURCE_NONE 0
|
||||||
|
#define BOOT_STATUS_SOURCE_SCRATCH 1
|
||||||
|
#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compatibility shim for flash sector type.
|
||||||
|
*
|
||||||
|
* This can be deleted when flash_area_to_sectors() is removed.
|
||||||
|
*/
|
||||||
|
#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
|
||||||
|
typedef struct flash_sector boot_sector_t;
|
||||||
|
#else
|
||||||
|
typedef struct flash_area boot_sector_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Private state maintained during boot. */
|
||||||
|
struct boot_loader_state {
|
||||||
|
struct {
|
||||||
|
struct image_header hdr;
|
||||||
|
const struct flash_area *area;
|
||||||
|
boot_sector_t *sectors;
|
||||||
|
uint32_t num_sectors;
|
||||||
|
} imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
struct {
|
||||||
|
const struct flash_area *area;
|
||||||
|
boot_sector_t *sectors;
|
||||||
|
uint32_t num_sectors;
|
||||||
|
} scratch;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t swap_type[BOOT_IMAGE_NUMBER];
|
||||||
|
uint32_t write_sz;
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENC_IMAGES)
|
||||||
|
struct enc_key_data enc[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER > 1)
|
||||||
|
uint8_t curr_img_idx;
|
||||||
|
bool img_mask[BOOT_IMAGE_NUMBER];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
|
||||||
|
struct slot_usage_t {
|
||||||
|
/* Index of the slot chosen to be loaded */
|
||||||
|
uint32_t active_slot;
|
||||||
|
bool slot_available[BOOT_NUM_SLOTS];
|
||||||
|
#if defined(MCUBOOT_RAM_LOAD)
|
||||||
|
/* Image destination and size for the active slot */
|
||||||
|
uint32_t img_dst;
|
||||||
|
uint32_t img_sz;
|
||||||
|
#elif defined(MCUBOOT_DIRECT_XIP_REVERT)
|
||||||
|
/* Swap status for the active slot */
|
||||||
|
struct boot_swap_state swap_state;
|
||||||
|
#endif
|
||||||
|
} slot_usage[BOOT_IMAGE_NUMBER];
|
||||||
|
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
|
||||||
|
};
|
||||||
|
|
||||||
|
fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
|
||||||
|
size_t slen, uint8_t key_id);
|
||||||
|
|
||||||
|
fih_ret bootutil_verify_img(const uint8_t *img, uint32_t size,
|
||||||
|
uint8_t *sig, size_t slen, uint8_t key_id);
|
||||||
|
|
||||||
|
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n);
|
||||||
|
|
||||||
|
int boot_find_status(int image_index, const struct flash_area **fap);
|
||||||
|
int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val);
|
||||||
|
uint32_t boot_status_sz(uint32_t min_write_sz);
|
||||||
|
uint32_t boot_trailer_sz(uint32_t min_write_sz);
|
||||||
|
int boot_status_entries(int image_index, const struct flash_area *fap);
|
||||||
|
uint32_t boot_status_off(const struct flash_area *fap);
|
||||||
|
int boot_read_swap_state(const struct flash_area *fap,
|
||||||
|
struct boot_swap_state *state);
|
||||||
|
int boot_read_swap_state_by_id(int flash_area_id,
|
||||||
|
struct boot_swap_state *state);
|
||||||
|
int boot_write_magic(const struct flash_area *fap);
|
||||||
|
int boot_write_status(const struct boot_loader_state *state, struct boot_status *bs);
|
||||||
|
int boot_write_copy_done(const struct flash_area *fap);
|
||||||
|
int boot_write_image_ok(const struct flash_area *fap);
|
||||||
|
int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
|
||||||
|
uint8_t image_num);
|
||||||
|
int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
|
||||||
|
int boot_write_trailer(const struct flash_area *fap, uint32_t off,
|
||||||
|
const uint8_t *inbuf, uint8_t inlen);
|
||||||
|
int boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
|
||||||
|
uint8_t flag_val);
|
||||||
|
int boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size);
|
||||||
|
int boot_slots_compatible(struct boot_loader_state *state);
|
||||||
|
uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz);
|
||||||
|
int boot_read_image_header(struct boot_loader_state *state, int slot,
|
||||||
|
struct image_header *out_hdr, struct boot_status *bs);
|
||||||
|
int boot_copy_region(struct boot_loader_state *state,
|
||||||
|
const struct flash_area *fap_src,
|
||||||
|
const struct flash_area *fap_dst,
|
||||||
|
uint32_t off_src, uint32_t off_dst, uint32_t sz);
|
||||||
|
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
|
||||||
|
bool boot_status_is_reset(const struct boot_status *bs);
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
int boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
|
||||||
|
const struct boot_status *bs);
|
||||||
|
int boot_read_enc_key(const struct flash_area *fap, uint8_t slot,
|
||||||
|
struct boot_status *bs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that a buffer is erased according to what the erase value for the
|
||||||
|
* flash device provided in `flash_area` is.
|
||||||
|
*
|
||||||
|
* @returns true if the buffer is erased; false if any of the bytes is not
|
||||||
|
* erased, or when buffer is NULL, or when len == 0.
|
||||||
|
*/
|
||||||
|
bool bootutil_buffer_is_erased(const struct flash_area *area,
|
||||||
|
const void *buffer, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safe (non-overflowing) uint32_t addition. Returns true, and stores
|
||||||
|
* the result in *dest if it can be done without overflow. Otherwise,
|
||||||
|
* returns false.
|
||||||
|
*/
|
||||||
|
static inline bool boot_u32_safe_add(uint32_t *dest, uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* "a + b <= UINT32_MAX", subtract 'b' from both sides to avoid
|
||||||
|
* the overflow.
|
||||||
|
*/
|
||||||
|
if (a > UINT32_MAX - b) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
*dest = a + b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safe (non-overflowing) uint16_t addition. Returns true, and stores
|
||||||
|
* the result in *dest if it can be done without overflow. Otherwise,
|
||||||
|
* returns false.
|
||||||
|
*/
|
||||||
|
static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b)
|
||||||
|
{
|
||||||
|
uint32_t tmp = a + b;
|
||||||
|
if (tmp > UINT16_MAX) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
*dest = tmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Accessors for the contents of struct boot_loader_state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* These are macros so they can be used as lvalues. */
|
||||||
|
#if (BOOT_IMAGE_NUMBER > 1)
|
||||||
|
#define BOOT_CURR_IMG(state) ((state)->curr_img_idx)
|
||||||
|
#else
|
||||||
|
#define BOOT_CURR_IMG(state) 0
|
||||||
|
#endif
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
#define BOOT_CURR_ENC(state) ((state)->enc[BOOT_CURR_IMG(state)])
|
||||||
|
#else
|
||||||
|
#define BOOT_CURR_ENC(state) NULL
|
||||||
|
#endif
|
||||||
|
#define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)])
|
||||||
|
#define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area)
|
||||||
|
#define BOOT_WRITE_SZ(state) ((state)->write_sz)
|
||||||
|
#define BOOT_SWAP_TYPE(state) ((state)->swap_type[BOOT_CURR_IMG(state)])
|
||||||
|
#define BOOT_TLV_OFF(hdr) ((hdr)->ih_hdr_size + (hdr)->ih_img_size)
|
||||||
|
|
||||||
|
#define BOOT_IS_UPGRADE(swap_type) \
|
||||||
|
(((swap_type) == BOOT_SWAP_TYPE_TEST) || \
|
||||||
|
((swap_type) == BOOT_SWAP_TYPE_REVERT) || \
|
||||||
|
((swap_type) == BOOT_SWAP_TYPE_PERM))
|
||||||
|
|
||||||
|
static inline struct image_header*
|
||||||
|
boot_img_hdr(struct boot_loader_state *state, size_t slot)
|
||||||
|
{
|
||||||
|
return &BOOT_IMG(state, slot).hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
boot_img_num_sectors(const struct boot_loader_state *state, size_t slot)
|
||||||
|
{
|
||||||
|
return BOOT_IMG(state, slot).num_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offset of the slot from the beginning of the flash device.
|
||||||
|
*/
|
||||||
|
static inline uint32_t
|
||||||
|
boot_img_slot_off(struct boot_loader_state *state, size_t slot)
|
||||||
|
{
|
||||||
|
return flash_area_get_off(BOOT_IMG(state, slot).area);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
boot_img_sector_size(const struct boot_loader_state *state,
|
||||||
|
size_t slot, size_t sector)
|
||||||
|
{
|
||||||
|
return flash_area_get_size(&BOOT_IMG(state, slot).sectors[sector]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offset of the sector from the beginning of the image, NOT the flash
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
static inline uint32_t
|
||||||
|
boot_img_sector_off(const struct boot_loader_state *state, size_t slot,
|
||||||
|
size_t sector)
|
||||||
|
{
|
||||||
|
return flash_area_get_off(&BOOT_IMG(state, slot).sectors[sector]) -
|
||||||
|
flash_area_get_off(&BOOT_IMG(state, slot).sectors[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
boot_img_sector_size(const struct boot_loader_state *state,
|
||||||
|
size_t slot, size_t sector)
|
||||||
|
{
|
||||||
|
return flash_sector_get_size(&BOOT_IMG(state, slot).sectors[sector]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
boot_img_sector_off(const struct boot_loader_state *state, size_t slot,
|
||||||
|
size_t sector)
|
||||||
|
{
|
||||||
|
return flash_sector_get_off(&BOOT_IMG(state, slot).sectors[sector]) -
|
||||||
|
flash_sector_get_off(&BOOT_IMG(state, slot).sectors[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_RAM_LOAD
|
||||||
|
# ifdef __BOOTSIM__
|
||||||
|
|
||||||
|
/* Query for the layout of a RAM buffer appropriate for holding the
|
||||||
|
* image. This will be per-test-thread, and therefore must be queried
|
||||||
|
* through this call. */
|
||||||
|
struct bootsim_ram_info {
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t size;
|
||||||
|
uintptr_t base;
|
||||||
|
};
|
||||||
|
struct bootsim_ram_info *bootsim_get_ram_info(void);
|
||||||
|
|
||||||
|
#define IMAGE_GET_FIELD(field) (bootsim_get_ram_info()->field)
|
||||||
|
#define IMAGE_RAM_BASE IMAGE_GET_FIELD(base)
|
||||||
|
#define IMAGE_EXECUTABLE_RAM_START IMAGE_GET_FIELD(start)
|
||||||
|
#define IMAGE_EXECUTABLE_RAM_SIZE IMAGE_GET_FIELD(size)
|
||||||
|
|
||||||
|
# else
|
||||||
|
# define IMAGE_RAM_BASE ((uintptr_t)0)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
|
||||||
|
(memcpy((output),(void*)(IMAGE_RAM_BASE + (hdr)->ih_load_addr + (start)), \
|
||||||
|
(size)), 0)
|
||||||
|
#else
|
||||||
|
#define IMAGE_RAM_BASE ((uintptr_t)0)
|
||||||
|
|
||||||
|
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
|
||||||
|
(flash_area_read((fap), (start), (output), (size)))
|
||||||
|
#endif /* MCUBOOT_RAM_LOAD */
|
||||||
|
|
||||||
|
uint32_t bootutil_max_image_size(const struct flash_area *fap);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
762
bootloader/mcuboot/boot/bootutil/src/bootutil_public.c
Normal file
762
bootloader/mcuboot/boot/bootutil/src/bootutil_public.c
Normal file
@@ -0,0 +1,762 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2023 Arm Limited
|
||||||
|
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Public MCUBoot interface API implementation
|
||||||
|
*
|
||||||
|
* This file contains API implementation which can be combined with
|
||||||
|
* the application in order to interact with the MCUBoot bootloader.
|
||||||
|
* This file contains shared code-base betwen MCUBoot and the application
|
||||||
|
* which controls DFU process.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "sysflash/sysflash.h"
|
||||||
|
#include "flash_map_backend/flash_map_backend.h"
|
||||||
|
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/bootutil_public.h"
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
#include "bootutil/boot_public_hooks.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "bootutil_misc.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_MCUBOOT
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
#else
|
||||||
|
BOOT_LOG_MODULE_REGISTER(mcuboot_util);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOOT_MAX_ALIGN == 8
|
||||||
|
const union boot_img_magic_t boot_img_magic = {
|
||||||
|
.val = {
|
||||||
|
0x77, 0xc2, 0x95, 0xf3,
|
||||||
|
0x60, 0xd2, 0xef, 0x7f,
|
||||||
|
0x35, 0x52, 0x50, 0x0f,
|
||||||
|
0x2c, 0xb6, 0x79, 0x80
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
const union boot_img_magic_t boot_img_magic = {
|
||||||
|
.align = BOOT_MAX_ALIGN,
|
||||||
|
.magic = {
|
||||||
|
0x2d, 0xe1,
|
||||||
|
0x5d, 0x29, 0x41, 0x0b,
|
||||||
|
0x8d, 0x77, 0x67, 0x9c,
|
||||||
|
0x11, 0x0f, 0x1f, 0x8a
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct boot_swap_table {
|
||||||
|
uint8_t magic_primary_slot;
|
||||||
|
uint8_t magic_secondary_slot;
|
||||||
|
uint8_t image_ok_primary_slot;
|
||||||
|
uint8_t image_ok_secondary_slot;
|
||||||
|
uint8_t copy_done_primary_slot;
|
||||||
|
|
||||||
|
uint8_t swap_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This set of tables maps image trailer contents to swap operation type.
|
||||||
|
* When searching for a match, these tables must be iterated sequentially.
|
||||||
|
*
|
||||||
|
* NOTE: the table order is very important. The settings in the secondary
|
||||||
|
* slot always are priority to the primary slot and should be located
|
||||||
|
* earlier in the table.
|
||||||
|
*
|
||||||
|
* The table lists only states where there is action needs to be taken by
|
||||||
|
* the bootloader, as in starting/finishing a swap operation.
|
||||||
|
*/
|
||||||
|
static const struct boot_swap_table boot_swap_tables[] = {
|
||||||
|
{
|
||||||
|
.magic_primary_slot = BOOT_MAGIC_ANY,
|
||||||
|
.magic_secondary_slot = BOOT_MAGIC_GOOD,
|
||||||
|
.image_ok_primary_slot = BOOT_FLAG_ANY,
|
||||||
|
.image_ok_secondary_slot = BOOT_FLAG_UNSET,
|
||||||
|
.copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||||
|
.swap_type = BOOT_SWAP_TYPE_TEST,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.magic_primary_slot = BOOT_MAGIC_ANY,
|
||||||
|
.magic_secondary_slot = BOOT_MAGIC_GOOD,
|
||||||
|
.image_ok_primary_slot = BOOT_FLAG_ANY,
|
||||||
|
.image_ok_secondary_slot = BOOT_FLAG_SET,
|
||||||
|
.copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||||
|
.swap_type = BOOT_SWAP_TYPE_PERM,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.magic_primary_slot = BOOT_MAGIC_GOOD,
|
||||||
|
.magic_secondary_slot = BOOT_MAGIC_UNSET,
|
||||||
|
.image_ok_primary_slot = BOOT_FLAG_UNSET,
|
||||||
|
.image_ok_secondary_slot = BOOT_FLAG_ANY,
|
||||||
|
.copy_done_primary_slot = BOOT_FLAG_SET,
|
||||||
|
.swap_type = BOOT_SWAP_TYPE_REVERT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BOOT_SWAP_TABLES_COUNT \
|
||||||
|
(sizeof boot_swap_tables / sizeof boot_swap_tables[0])
|
||||||
|
|
||||||
|
static int
|
||||||
|
boot_flag_decode(uint8_t flag)
|
||||||
|
{
|
||||||
|
if (flag != BOOT_FLAG_SET) {
|
||||||
|
return BOOT_FLAG_BAD;
|
||||||
|
}
|
||||||
|
return BOOT_FLAG_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
boot_swap_info_off(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a status source table is satisfied by the specified magic
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
* @param tbl_val A magic field from a status source table.
|
||||||
|
* @param val The magic value in a trailer, encoded as a
|
||||||
|
* BOOT_MAGIC_[...].
|
||||||
|
*
|
||||||
|
* @return 1 if the two values are compatible;
|
||||||
|
* 0 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
|
||||||
|
{
|
||||||
|
switch (tbl_val) {
|
||||||
|
case BOOT_MAGIC_ANY:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case BOOT_MAGIC_NOTGOOD:
|
||||||
|
return val != BOOT_MAGIC_GOOD;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return tbl_val == val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bootutil_buffer_is_erased(const struct flash_area *area,
|
||||||
|
const void *buffer, size_t len)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t *u8b;
|
||||||
|
uint8_t erased_val;
|
||||||
|
|
||||||
|
if (buffer == NULL || len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
erased_val = flash_area_erased_val(area);
|
||||||
|
for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) {
|
||||||
|
if (u8b[i] != erased_val) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_read(fap, off, flag, sizeof *flag);
|
||||||
|
if (rc < 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
if (bootutil_buffer_is_erased(fap, flag, sizeof *flag)) {
|
||||||
|
*flag = BOOT_FLAG_UNSET;
|
||||||
|
} else {
|
||||||
|
*flag = boot_flag_decode(*flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done)
|
||||||
|
{
|
||||||
|
return boot_read_flag(fap, copy_done, boot_copy_done_off(fap));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_read_swap_state(const struct flash_area *fap,
|
||||||
|
struct boot_swap_state *state)
|
||||||
|
{
|
||||||
|
uint8_t magic[BOOT_MAGIC_SZ];
|
||||||
|
uint32_t off;
|
||||||
|
uint8_t swap_info;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
off = boot_magic_off(fap);
|
||||||
|
rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
|
||||||
|
if (rc < 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) {
|
||||||
|
state->magic = BOOT_MAGIC_UNSET;
|
||||||
|
} else {
|
||||||
|
state->magic = boot_magic_decode(magic);
|
||||||
|
}
|
||||||
|
|
||||||
|
off = boot_swap_info_off(fap);
|
||||||
|
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
|
||||||
|
if (rc < 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the swap type and image number */
|
||||||
|
state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
|
||||||
|
state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
|
||||||
|
|
||||||
|
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) ||
|
||||||
|
state->swap_type > BOOT_SWAP_TYPE_REVERT) {
|
||||||
|
state->swap_type = BOOT_SWAP_TYPE_NONE;
|
||||||
|
state->image_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_copy_done(fap, &state->copy_done);
|
||||||
|
if (rc) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boot_read_image_ok(fap, &state->image_ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_open(flash_area_id, &fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(fap, state);
|
||||||
|
flash_area_close(fap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_write_magic(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
uint32_t pad_off;
|
||||||
|
int rc;
|
||||||
|
uint8_t magic[BOOT_MAGIC_ALIGN_SIZE];
|
||||||
|
uint8_t erased_val;
|
||||||
|
|
||||||
|
off = boot_magic_off(fap);
|
||||||
|
|
||||||
|
/* image_trailer structure was modified with additional padding such that
|
||||||
|
* the pad+magic ends up in a flash minimum write region. The address
|
||||||
|
* returned by boot_magic_off() is the start of magic which is not the
|
||||||
|
* start of the flash write boundary and thus writes to the magic will fail.
|
||||||
|
* To account for this change, write to magic is first padded with 0xFF
|
||||||
|
* before writing to the trailer.
|
||||||
|
*/
|
||||||
|
pad_off = ALIGN_DOWN(off, BOOT_MAX_ALIGN);
|
||||||
|
|
||||||
|
erased_val = flash_area_erased_val(fap);
|
||||||
|
|
||||||
|
memset(&magic[0], erased_val, sizeof(magic));
|
||||||
|
memcpy(&magic[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ], BOOT_IMG_MAGIC, BOOT_MAGIC_SZ);
|
||||||
|
|
||||||
|
BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)",
|
||||||
|
flash_area_get_id(fap), (unsigned long)off,
|
||||||
|
(unsigned long)(flash_area_get_off(fap) + off));
|
||||||
|
rc = flash_area_write(fap, pad_off, &magic[0], BOOT_MAGIC_ALIGN_SIZE);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write trailer data; status bytes, swap_size, etc
|
||||||
|
*
|
||||||
|
* @returns 0 on success, != 0 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_write_trailer(const struct flash_area *fap, uint32_t off,
|
||||||
|
const uint8_t *inbuf, uint8_t inlen)
|
||||||
|
{
|
||||||
|
uint8_t buf[BOOT_MAX_ALIGN];
|
||||||
|
uint8_t erased_val;
|
||||||
|
uint32_t align;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
align = flash_area_align(fap);
|
||||||
|
align = ALIGN_UP(inlen, align);
|
||||||
|
if (align > BOOT_MAX_ALIGN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
erased_val = flash_area_erased_val(fap);
|
||||||
|
|
||||||
|
memcpy(buf, inbuf, inlen);
|
||||||
|
memset(&buf[inlen], erased_val, align - inlen);
|
||||||
|
|
||||||
|
rc = flash_area_write(fap, off, buf, align);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
|
||||||
|
uint8_t flag_val)
|
||||||
|
{
|
||||||
|
const uint8_t buf[1] = { flag_val };
|
||||||
|
return boot_write_trailer(fap, off, buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_write_image_ok(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
|
||||||
|
off = boot_image_ok_off(fap);
|
||||||
|
BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)",
|
||||||
|
flash_area_get_id(fap), (unsigned long)off,
|
||||||
|
(unsigned long)(flash_area_get_off(fap) + off));
|
||||||
|
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok)
|
||||||
|
{
|
||||||
|
return boot_read_flag(fap, image_ok, boot_image_ok_off(fap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the specified value to the `swap-type` field of an image trailer.
|
||||||
|
* This value is persisted so that the boot loader knows what swap operation to
|
||||||
|
* resume in case of an unexpected reset.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
|
||||||
|
uint8_t image_num)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
uint8_t swap_info;
|
||||||
|
|
||||||
|
BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
|
||||||
|
off = boot_swap_info_off(fap);
|
||||||
|
BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x"
|
||||||
|
" image_num=0x%x",
|
||||||
|
flash_area_get_id(fap), (unsigned long)off,
|
||||||
|
(unsigned long)(flash_area_get_off(fap) + off),
|
||||||
|
swap_type, image_num);
|
||||||
|
return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_swap_type_multi(int image_index)
|
||||||
|
{
|
||||||
|
const struct boot_swap_table *table;
|
||||||
|
struct boot_swap_state primary_slot;
|
||||||
|
struct boot_swap_state secondary_slot;
|
||||||
|
int rc;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
rc = BOOT_HOOK_CALL(boot_read_swap_state_primary_slot_hook,
|
||||||
|
BOOT_HOOK_REGULAR, image_index, &primary_slot);
|
||||||
|
if (rc == BOOT_HOOK_REGULAR)
|
||||||
|
{
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
&primary_slot);
|
||||||
|
}
|
||||||
|
if (rc) {
|
||||||
|
return BOOT_SWAP_TYPE_PANIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
|
||||||
|
&secondary_slot);
|
||||||
|
if (rc == BOOT_EFLASH) {
|
||||||
|
BOOT_LOG_INF("Secondary image of image pair (%d.) "
|
||||||
|
"is unreachable. Treat it as empty", image_index);
|
||||||
|
secondary_slot.magic = BOOT_MAGIC_UNSET;
|
||||||
|
secondary_slot.swap_type = BOOT_SWAP_TYPE_NONE;
|
||||||
|
secondary_slot.copy_done = BOOT_FLAG_UNSET;
|
||||||
|
secondary_slot.image_ok = BOOT_FLAG_UNSET;
|
||||||
|
secondary_slot.image_num = 0;
|
||||||
|
} else if (rc) {
|
||||||
|
return BOOT_SWAP_TYPE_PANIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
|
||||||
|
table = boot_swap_tables + i;
|
||||||
|
|
||||||
|
if (boot_magic_compatible_check(table->magic_primary_slot,
|
||||||
|
primary_slot.magic) &&
|
||||||
|
boot_magic_compatible_check(table->magic_secondary_slot,
|
||||||
|
secondary_slot.magic) &&
|
||||||
|
(table->image_ok_primary_slot == BOOT_FLAG_ANY ||
|
||||||
|
table->image_ok_primary_slot == primary_slot.image_ok) &&
|
||||||
|
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
|
||||||
|
table->image_ok_secondary_slot == secondary_slot.image_ok) &&
|
||||||
|
(table->copy_done_primary_slot == BOOT_FLAG_ANY ||
|
||||||
|
table->copy_done_primary_slot == primary_slot.copy_done)) {
|
||||||
|
BOOT_LOG_INF("Image index: %d, Swap type: %s", image_index,
|
||||||
|
table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
|
||||||
|
table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
|
||||||
|
table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
|
||||||
|
"BUG; can't happen");
|
||||||
|
if (table->swap_type != BOOT_SWAP_TYPE_TEST &&
|
||||||
|
table->swap_type != BOOT_SWAP_TYPE_PERM &&
|
||||||
|
table->swap_type != BOOT_SWAP_TYPE_REVERT) {
|
||||||
|
return BOOT_SWAP_TYPE_PANIC;
|
||||||
|
}
|
||||||
|
return table->swap_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Image index: %d, Swap type: none", image_index);
|
||||||
|
return BOOT_SWAP_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_write_copy_done(const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
|
||||||
|
off = boot_copy_done_off(fap);
|
||||||
|
BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
|
||||||
|
flash_area_get_id(fap), (unsigned long)off,
|
||||||
|
(unsigned long)(flash_area_get_off(fap) + off));
|
||||||
|
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP
|
||||||
|
|
||||||
|
static int flash_area_to_image(const struct flash_area *fa)
|
||||||
|
{
|
||||||
|
#if BOOT_IMAGE_NUMBER > 1
|
||||||
|
uint8_t i = 0;
|
||||||
|
int id = flash_area_get_id(fa);
|
||||||
|
|
||||||
|
while (i < BOOT_IMAGE_NUMBER) {
|
||||||
|
if (FLASH_AREA_IMAGE_PRIMARY(i) == id || (FLASH_AREA_IMAGE_SECONDARY(i) == id)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)fa;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_set_next(const struct flash_area *fa, bool active, bool confirm)
|
||||||
|
{
|
||||||
|
struct boot_swap_state slot_state;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
confirm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(fa, &slot_state);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (slot_state.magic) {
|
||||||
|
case BOOT_MAGIC_GOOD:
|
||||||
|
/* If non-active then swap already scheduled, else confirm needed.*/
|
||||||
|
|
||||||
|
if (active && slot_state.image_ok == BOOT_FLAG_UNSET) {
|
||||||
|
/* Intentionally do not check copy_done flag to be able to
|
||||||
|
* confirm a padded image which has been programmed using
|
||||||
|
* a programming interface.
|
||||||
|
*/
|
||||||
|
rc = boot_write_image_ok(fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BOOT_MAGIC_UNSET:
|
||||||
|
if (!active) {
|
||||||
|
rc = boot_write_magic(fa);
|
||||||
|
|
||||||
|
if (rc == 0 && confirm) {
|
||||||
|
rc = boot_write_image_ok(fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
uint8_t swap_type;
|
||||||
|
|
||||||
|
if (confirm) {
|
||||||
|
swap_type = BOOT_SWAP_TYPE_PERM;
|
||||||
|
} else {
|
||||||
|
swap_type = BOOT_SWAP_TYPE_TEST;
|
||||||
|
}
|
||||||
|
rc = boot_write_swap_info(fa, swap_type, flash_area_to_image(fa));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BOOT_MAGIC_BAD:
|
||||||
|
if (active) {
|
||||||
|
rc = BOOT_EBADVECT;
|
||||||
|
} else {
|
||||||
|
/* The image slot is corrupt. There is no way to recover, so erase the
|
||||||
|
* slot to allow future upgrades.
|
||||||
|
*/
|
||||||
|
flash_area_erase(fa, 0, flash_area_get_size(fa));
|
||||||
|
rc = BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Something is not OK, this should never happen */
|
||||||
|
assert(0);
|
||||||
|
rc = BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int
|
||||||
|
boot_set_next(const struct flash_area *fa, bool active, bool confirm)
|
||||||
|
{
|
||||||
|
struct boot_swap_state slot_state;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* The only way to set active slot for next boot is to confirm it,
|
||||||
|
* as DirectXIP will conclude that, since slot has not been confirmed
|
||||||
|
* last boot, it is bad and will remove it.
|
||||||
|
*/
|
||||||
|
confirm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(fa, &slot_state);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (slot_state.magic) {
|
||||||
|
case BOOT_MAGIC_UNSET:
|
||||||
|
/* Magic is needed for MCUboot to even consider booting an image */
|
||||||
|
rc = boot_write_magic(fa);
|
||||||
|
if (rc != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Pass */
|
||||||
|
|
||||||
|
case BOOT_MAGIC_GOOD:
|
||||||
|
if (confirm) {
|
||||||
|
if (slot_state.copy_done == BOOT_FLAG_UNSET) {
|
||||||
|
/* Magic is needed for DirectXIP to even try to boot application.
|
||||||
|
* DirectXIP will set copy-done flag before attempting to boot
|
||||||
|
* application. Next boot, application that has copy-done flag
|
||||||
|
* is expected to already have ok flag, otherwise it will be removed.
|
||||||
|
*/
|
||||||
|
rc = boot_write_copy_done(fa);
|
||||||
|
if (rc != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot_state.image_ok == BOOT_FLAG_UNSET) {
|
||||||
|
rc = boot_write_image_ok(fa);
|
||||||
|
if (rc != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BOOT_MAGIC_BAD:
|
||||||
|
/* This image will not be boot next time anyway */
|
||||||
|
rc = BOOT_EBADIMAGE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Something is not OK, this should never happen */
|
||||||
|
assert(0);
|
||||||
|
rc = BOOT_EBADSTATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is not used by the bootloader itself, but its required API
|
||||||
|
* by external tooling like mcumgr.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_swap_type(void)
|
||||||
|
{
|
||||||
|
return boot_swap_type_multi(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with the given index in the secondary slot as pending. On the
|
||||||
|
* next reboot, the system will perform a one-time boot of the the secondary
|
||||||
|
* slot image.
|
||||||
|
*
|
||||||
|
* @param image_index Image pair index.
|
||||||
|
*
|
||||||
|
* @param permanent Whether the image should be used permanently or
|
||||||
|
* only tested once:
|
||||||
|
* 0=run image once, then confirm or revert.
|
||||||
|
* 1=run image forever.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_set_pending_multi(int image_index, int permanent)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_set_next(fap, false, !(permanent == 0));
|
||||||
|
|
||||||
|
flash_area_close(fap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with index 0 in the secondary slot as pending. On the next
|
||||||
|
* reboot, the system will perform a one-time boot of the the secondary slot
|
||||||
|
* image. Note that this API is kept for compatibility. The
|
||||||
|
* boot_set_pending_multi() API is recommended.
|
||||||
|
*
|
||||||
|
* @param permanent Whether the image should be used permanently or
|
||||||
|
* only tested once:
|
||||||
|
* 0=run image once, then confirm or revert.
|
||||||
|
* 1=run image forever.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_set_pending(int permanent)
|
||||||
|
{
|
||||||
|
return boot_set_pending_multi(0, permanent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with the given index in the primary slot as confirmed. The
|
||||||
|
* system will continue booting into the image in the primary slot until told to
|
||||||
|
* boot from a different slot.
|
||||||
|
*
|
||||||
|
* @param image_index Image pair index.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_set_confirmed_multi(int image_index)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap = NULL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_set_next(fap, true, true);
|
||||||
|
|
||||||
|
flash_area_close(fap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image with index 0 in the primary slot as confirmed. The system
|
||||||
|
* will continue booting into the image in the primary slot until told to boot
|
||||||
|
* from a different slot. Note that this API is kept for compatibility. The
|
||||||
|
* boot_set_confirmed_multi() API is recommended.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_set_confirmed(void)
|
||||||
|
{
|
||||||
|
return boot_set_confirmed_multi(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_image_load_header(const struct flash_area *fa_p,
|
||||||
|
struct image_header *hdr)
|
||||||
|
{
|
||||||
|
uint32_t size;
|
||||||
|
int rc = flash_area_read(fa_p, 0, hdr, sizeof *hdr);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
BOOT_LOG_ERR("Failed reading image header");
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->ih_magic != IMAGE_MAGIC) {
|
||||||
|
BOOT_LOG_ERR("Bad image magic 0x%lx", (unsigned long)hdr->ih_magic);
|
||||||
|
|
||||||
|
return BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
|
||||||
|
BOOT_LOG_ERR("Image not bootable");
|
||||||
|
|
||||||
|
return BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size) ||
|
||||||
|
size >= flash_area_get_size(fa_p)) {
|
||||||
|
return BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
95
bootloader/mcuboot/boot/bootutil/src/caps.c
Normal file
95
bootloader/mcuboot/boot/bootutil/src/caps.c
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Linaro Limited
|
||||||
|
* Copyright (c) 2021-2023 Arm Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <bootutil/caps.h>
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
uint32_t bootutil_get_caps(void)
|
||||||
|
{
|
||||||
|
uint32_t res = 0;
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_RSA)
|
||||||
|
#if MCUBOOT_SIGN_RSA_LEN == 2048
|
||||||
|
res |= BOOTUTIL_CAP_RSA2048;
|
||||||
|
#endif
|
||||||
|
#if MCUBOOT_SIGN_RSA_LEN == 3072
|
||||||
|
res |= BOOTUTIL_CAP_RSA3072;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_SIGN_EC256)
|
||||||
|
res |= BOOTUTIL_CAP_ECDSA_P256;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_SIGN_EC384)
|
||||||
|
res |= BOOTUTIL_CAP_ECDSA_P384;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_SIGN_ED25519)
|
||||||
|
res |= BOOTUTIL_CAP_ED25519;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_OVERWRITE_ONLY)
|
||||||
|
res |= BOOTUTIL_CAP_OVERWRITE_UPGRADE;
|
||||||
|
#elif defined(MCUBOOT_SWAP_USING_MOVE)
|
||||||
|
res |= BOOTUTIL_CAP_SWAP_USING_MOVE;
|
||||||
|
#else
|
||||||
|
res |= BOOTUTIL_CAP_SWAP_USING_SCRATCH;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_RSA)
|
||||||
|
res |= BOOTUTIL_CAP_ENC_RSA;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_KW)
|
||||||
|
res |= BOOTUTIL_CAP_ENC_KW;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256)
|
||||||
|
res |= BOOTUTIL_CAP_ENC_EC256;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
res |= BOOTUTIL_CAP_ENC_X25519;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
|
||||||
|
res |= BOOTUTIL_CAP_VALIDATE_PRIMARY_SLOT;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_DOWNGRADE_PREVENTION)
|
||||||
|
res |= BOOTUTIL_CAP_DOWNGRADE_PREVENTION;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_BOOTSTRAP)
|
||||||
|
res |= BOOTUTIL_CAP_BOOTSTRAP;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_AES_256)
|
||||||
|
res |= BOOTUTIL_CAP_AES256;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_RAM_LOAD)
|
||||||
|
res |= BOOTUTIL_CAP_RAM_LOAD;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_DIRECT_XIP)
|
||||||
|
res |= BOOTUTIL_CAP_DIRECT_XIP;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_HW_ROLLBACK_PROT)
|
||||||
|
res |= BOOTUTIL_CAP_HW_ROLLBACK_PROT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bootutil_get_num_images(void)
|
||||||
|
{
|
||||||
|
#if defined(MCUBOOT_IMAGE_NUMBER)
|
||||||
|
return MCUBOOT_IMAGE_NUMBER;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
122
bootloader/mcuboot/boot/bootutil/src/ed25519_psa.c
Normal file
122
bootloader/mcuboot/boot/bootutil/src/ed25519_psa.c
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||||
|
*/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mcuboot_config/mcuboot_config.h>
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
#include <psa/crypto.h>
|
||||||
|
#include <psa/crypto_types.h>
|
||||||
|
#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
#include <cracen_psa_kmu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(ed25519_psa);
|
||||||
|
|
||||||
|
#define SHA512_DIGEST_LENGTH 64
|
||||||
|
#define EDDSA_KEY_LENGTH 32
|
||||||
|
#define EDDSA_SIGNAGURE_LENGTH 64
|
||||||
|
|
||||||
|
#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
/* List of KMU stored key ids available for MCUboot */
|
||||||
|
#define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id)
|
||||||
|
static psa_key_id_t kmu_key_ids[3] = {
|
||||||
|
MAKE_PSA_KMU_KEY_ID(226),
|
||||||
|
MAKE_PSA_KMU_KEY_ID(228),
|
||||||
|
MAKE_PSA_KMU_KEY_ID(230)
|
||||||
|
};
|
||||||
|
#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
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])
|
||||||
|
{
|
||||||
|
ARG_UNUSED(public_key);
|
||||||
|
/* Set to any error */
|
||||||
|
psa_status_t status = PSA_ERROR_BAD_STATE;
|
||||||
|
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", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = PSA_ERROR_BAD_STATE;
|
||||||
|
|
||||||
|
for (int i = 0; i < KMU_KEY_COUNT; ++i) {
|
||||||
|
psa_key_id_t kid = kmu_key_ids[i];
|
||||||
|
|
||||||
|
status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message,
|
||||||
|
message_len, signature,
|
||||||
|
EDDSA_SIGNAGURE_LENGTH);
|
||||||
|
if (status == PSA_SUCCESS) {
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOT_LOG_ERR("ED25519 signature verification failed %d", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
755
bootloader/mcuboot/boot/bootutil/src/encrypted.c
Normal file
755
bootloader/mcuboot/boot/bootutil/src/encrypted.c
Normal file
@@ -0,0 +1,755 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2024 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENC_IMAGES)
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_RSA)
|
||||||
|
#define BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED
|
||||||
|
#include "bootutil/crypto/rsa.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_KW)
|
||||||
|
#include "bootutil/crypto/aes_kw.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256)
|
||||||
|
#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
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
#include "bootutil/crypto/sha.h"
|
||||||
|
#include "bootutil/crypto/hmac_sha256.h"
|
||||||
|
#include "mbedtls/oid.h"
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/enc_key.h"
|
||||||
|
#include "bootutil/sign_key.h"
|
||||||
|
#include "bootutil/crypto/common.h"
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
return _compare(a, b, size);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size)
|
||||||
|
{
|
||||||
|
const uint8_t *tempa = a;
|
||||||
|
const uint8_t *tempb = b;
|
||||||
|
uint8_t result = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
result |= tempa[i] ^ tempb[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_KW)
|
||||||
|
static int
|
||||||
|
key_unwrap(const uint8_t *wrapped, uint8_t *enckey, struct bootutil_key *bootutil_enc_key)
|
||||||
|
{
|
||||||
|
bootutil_aes_kw_context aes_kw;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
bootutil_aes_kw_init(&aes_kw);
|
||||||
|
rc = bootutil_aes_kw_set_unwrap_key(&aes_kw, bootutil_enc_key->key, *bootutil_enc_key->len);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
rc = bootutil_aes_kw_unwrap(&aes_kw, wrapped, TLV_ENC_KW_SZ, enckey, BOOT_ENC_KEY_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
bootutil_aes_kw_drop(&aes_kw);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_ENCRYPT_KW */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256)
|
||||||
|
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
|
||||||
|
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
|
||||||
|
|
||||||
|
#define SHARED_KEY_LEN NUM_ECC_BYTES
|
||||||
|
#define PRIV_KEY_LEN NUM_ECC_BYTES
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parses the output of `imgtool keygen`, which produces a PKCS#8 elliptic
|
||||||
|
* curve keypair. See RFC5208 and RFC5915.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_ec256_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
size_t len;
|
||||||
|
int version;
|
||||||
|
mbedtls_asn1_buf alg;
|
||||||
|
mbedtls_asn1_buf param;
|
||||||
|
|
||||||
|
if ((rc = 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 ((rc = mbedtls_asn1_get_alg(p, end, &alg, ¶m)) != 0) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RFC5915 - ECPrivateKey */
|
||||||
|
|
||||||
|
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
|
||||||
|
return -9;
|
||||||
|
}
|
||||||
|
|
||||||
|
version = 0;
|
||||||
|
if (mbedtls_asn1_get_int(p, end, &version) || version != 1) {
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* privateKey */
|
||||||
|
|
||||||
|
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
|
||||||
|
return -11;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != NUM_ECC_BYTES) {
|
||||||
|
return -12;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(private_key, *p, len);
|
||||||
|
|
||||||
|
/* publicKey usually follows but is not parsed here */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
#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
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
/*
|
||||||
|
* HKDF as described by RFC5869.
|
||||||
|
*
|
||||||
|
* @param ikm The input data to be derived.
|
||||||
|
* @param ikm_len Length of the input data.
|
||||||
|
* @param info An information tag.
|
||||||
|
* @param info_len Length of the information tag.
|
||||||
|
* @param okm Output of the KDF computation.
|
||||||
|
* @param okm_len On input the requested length; on output the generated length
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
hkdf(uint8_t *ikm, uint16_t ikm_len, uint8_t *info, uint16_t info_len,
|
||||||
|
uint8_t *okm, uint16_t *okm_len)
|
||||||
|
{
|
||||||
|
bootutil_hmac_sha256_context hmac;
|
||||||
|
uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
|
||||||
|
uint8_t prk[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
|
||||||
|
uint8_t T[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
|
||||||
|
uint16_t off;
|
||||||
|
uint16_t len;
|
||||||
|
uint8_t counter;
|
||||||
|
bool first;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ikm == NULL || okm == NULL || ikm_len == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_hmac_sha256_init(&hmac);
|
||||||
|
|
||||||
|
memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
rc = bootutil_hmac_sha256_set_key(&hmac, salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_update(&hmac, ikm, ikm_len);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_finish(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand
|
||||||
|
*/
|
||||||
|
|
||||||
|
len = *okm_len;
|
||||||
|
counter = 1;
|
||||||
|
first = true;
|
||||||
|
for (off = 0; len > 0; off += BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, ++counter) {
|
||||||
|
bootutil_hmac_sha256_init(&hmac);
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_set_key(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
rc = bootutil_hmac_sha256_update(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_update(&hmac, info, info_len);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_update(&hmac, &counter, 1);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_finish(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
|
||||||
|
if (len > BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE) {
|
||||||
|
memcpy(&okm[off], T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
len -= BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
|
||||||
|
} else {
|
||||||
|
memcpy(&okm[off], T, len);
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_ENCRYPT_EC256 || MCUBOOT_ENCRYPT_X25519 */
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_ENC_BUILTIN_KEY)
|
||||||
|
extern const struct bootutil_key bootutil_enc_key;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default implementation to retrieve the private encryption key which is
|
||||||
|
* embedded in the bootloader code (when MCUBOOT_ENC_BUILTIN_KEY is not defined).
|
||||||
|
*/
|
||||||
|
int boot_enc_retrieve_private_key(struct bootutil_key **private_key)
|
||||||
|
{
|
||||||
|
*private_key = (struct bootutil_key *)&bootutil_enc_key;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* !MCUBOOT_ENC_BUILTIN_KEY */
|
||||||
|
|
||||||
|
#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
|
||||||
|
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 /* MBEDTLS_VERSION_NUMBER */
|
||||||
|
#endif /* (MCUBOOT_ENCRYPT_RSA && MCUBOOT_USE_MBED_TLS && !MCUBOOT_USE_PSA_CRYPTO) ||
|
||||||
|
(MCUBOOT_ENCRYPT_EC256 && MCUBOOT_USE_MBED_TLS) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_RSA)
|
||||||
|
bootutil_rsa_context rsa;
|
||||||
|
uint8_t *cp;
|
||||||
|
uint8_t *cpend;
|
||||||
|
size_t olen;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256)
|
||||||
|
bootutil_ecdh_p256_context ecdh_p256;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
bootutil_ecdh_x25519_context ecdh_x25519;
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
bootutil_hmac_sha256_context hmac;
|
||||||
|
bootutil_aes_ctr_context aes_ctr;
|
||||||
|
uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
|
||||||
|
uint8_t shared[SHARED_KEY_LEN];
|
||||||
|
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];
|
||||||
|
uint8_t counter[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
|
||||||
|
uint16_t len;
|
||||||
|
#endif
|
||||||
|
struct bootutil_key *bootutil_enc_key = NULL;
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
rc = boot_enc_retrieve_private_key(&bootutil_enc_key);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootutil_enc_key == NULL) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_RSA)
|
||||||
|
|
||||||
|
bootutil_rsa_init(&rsa);
|
||||||
|
cp = (uint8_t *)bootutil_enc_key->key;
|
||||||
|
cpend = cp + *bootutil_enc_key->len;
|
||||||
|
|
||||||
|
/* The enckey is encrypted through RSA so for decryption we need the private key */
|
||||||
|
rc = bootutil_rsa_parse_private_key(&rsa, &cp, cpend);
|
||||||
|
if (rc) {
|
||||||
|
bootutil_rsa_drop(&rsa);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_rsa_oaep_decrypt(&rsa, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
|
||||||
|
bootutil_rsa_drop(&rsa);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_RSA) */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_KW)
|
||||||
|
|
||||||
|
assert(*bootutil_enc_key->len == BOOT_ENC_KEY_SIZE);
|
||||||
|
rc = key_unwrap(buf, enckey, bootutil_enc_key);
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_KW) */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256)
|
||||||
|
|
||||||
|
cp = (uint8_t *)bootutil_enc_key->key;
|
||||||
|
cpend = cp + *bootutil_enc_key->len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the stored EC256 decryption private key
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc = parse_ec256_enckey(&cp, cpend, private_key);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First "element" in the TLV is the curve point (public key)
|
||||||
|
*/
|
||||||
|
bootutil_ecdh_p256_init(&ecdh_p256);
|
||||||
|
|
||||||
|
rc = bootutil_ecdh_p256_shared_secret(&ecdh_p256, &buf[EC_PUBK_INDEX], private_key, shared);
|
||||||
|
bootutil_ecdh_p256_drop(&ecdh_p256);
|
||||||
|
if (rc != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
|
||||||
|
cp = (uint8_t *)bootutil_enc_key->key;
|
||||||
|
cpend = cp + *bootutil_enc_key->len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the stored X25519 decryption private key
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc = parse_x25519_enckey(&cp, cpend, private_key);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First "element" in the TLV is the curve point (public key)
|
||||||
|
*/
|
||||||
|
|
||||||
|
bootutil_ecdh_x25519_init(&ecdh_x25519);
|
||||||
|
|
||||||
|
rc = bootutil_ecdh_x25519_shared_secret(&ecdh_x25519, &buf[EC_PUBK_INDEX], private_key, shared);
|
||||||
|
bootutil_ecdh_x25519_drop(&ecdh_x25519);
|
||||||
|
if (!rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256
|
||||||
|
*/
|
||||||
|
|
||||||
|
len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
|
||||||
|
rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16,
|
||||||
|
derived_key, &len);
|
||||||
|
if (rc != 0 || len != (BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HMAC the key and check that our received MAC matches the generated tag
|
||||||
|
*/
|
||||||
|
|
||||||
|
bootutil_hmac_sha256_init(&hmac);
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOT_ENC_KEY_SIZE], 32);
|
||||||
|
if (rc != 0) {
|
||||||
|
(void)bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
(void)bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assumes the tag buffer is at least sizeof(hmac_tag_size(state)) bytes */
|
||||||
|
rc = bootutil_hmac_sha256_finish(&hmac, tag, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
|
||||||
|
if (rc != 0) {
|
||||||
|
(void)bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], 32) != 0) {
|
||||||
|
(void)bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_hmac_sha256_drop(&hmac);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally decrypt the received ciphered key
|
||||||
|
*/
|
||||||
|
|
||||||
|
bootutil_aes_ctr_init(&aes_ctr);
|
||||||
|
if (rc != 0) {
|
||||||
|
bootutil_aes_ctr_drop(&aes_ctr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_aes_ctr_set_key(&aes_ctr, derived_key);
|
||||||
|
if (rc != 0) {
|
||||||
|
bootutil_aes_ctr_drop(&aes_ctr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
|
||||||
|
rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
|
||||||
|
if (rc != 0) {
|
||||||
|
bootutil_aes_ctr_drop(&aes_ctr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_aes_ctr_drop(&aes_ctr);
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) */
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BOOT_ED25519_PSA */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load encryption key.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
uint16_t len;
|
||||||
|
struct image_tlv_iter it;
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
uint8_t *buf;
|
||||||
|
#else
|
||||||
|
uint8_t buf[EXPECTED_ENC_LEN];
|
||||||
|
#endif
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Already loaded... */
|
||||||
|
if (enc_state[slot].valid) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the AES context */
|
||||||
|
boot_enc_init(enc_state, slot);
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_ENC_TLV, false);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != EXPECTED_ENC_LEN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||||
|
buf = bs->enctlv[slot];
|
||||||
|
memset(buf, 0xff, BOOT_ENC_TLV_ALIGN_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = flash_area_read(fap, off, buf, EXPECTED_ENC_LEN);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boot_decrypt_key(buf, bs->enckey[slot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]);
|
||||||
|
if (rc != 0) {
|
||||||
|
boot_enc_drop(enc_state, slot);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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 = &enc_state[slot];
|
||||||
|
uint8_t nonce[16];
|
||||||
|
|
||||||
|
/* Nothing to do with size == 0 */
|
||||||
|
if (sz == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_decrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears encrypted state after use.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
boot_enc_zeroize(struct enc_key_data *enc_state)
|
||||||
|
{
|
||||||
|
uint8_t slot;
|
||||||
|
for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
|
||||||
|
(void)boot_enc_drop(enc_state, slot);
|
||||||
|
}
|
||||||
|
memset(enc_state, 0, sizeof(struct enc_key_data) * BOOT_NUM_SLOTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_ENC_IMAGES */
|
||||||
454
bootloader/mcuboot/boot/bootutil/src/encrypted_psa.c
Normal file
454
bootloader/mcuboot/boot/bootutil/src/encrypted_psa.c
Normal file
@@ -0,0 +1,454 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
extern const struct bootutil_key bootutil_enc_key;
|
||||||
|
/*
|
||||||
|
* 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) */
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_DOUBLE_VARS
|
||||||
|
/* Variable that could be (but isn't) changed at runtime to force the compiler
|
||||||
|
* not to optimize the double check. Value doesn't matter.
|
||||||
|
*/
|
||||||
|
volatile int _fih_mask = _FIH_MASK_VALUE;
|
||||||
|
#endif /* FIH_ENABLE_DOUBLE_VARS */
|
||||||
|
|
||||||
|
fih_ret FIH_SUCCESS = FIH_POSITIVE_VALUE;
|
||||||
|
fih_ret FIH_FAILURE = FIH_NEGATIVE_VALUE;
|
||||||
|
fih_ret FIH_NO_BOOTABLE_IMAGE = FIH_CONST1;
|
||||||
|
fih_ret FIH_BOOT_HOOK_REGULAR = FIH_CONST2;
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_CFI
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_DOUBLE_VARS
|
||||||
|
fih_int _fih_cfi_ctr = {0, 0 ^ _FIH_MASK_VALUE};
|
||||||
|
#else
|
||||||
|
fih_int _fih_cfi_ctr = {0};
|
||||||
|
#endif /* FIH_ENABLE_DOUBLE_VARS */
|
||||||
|
|
||||||
|
/* Increment the CFI counter by one, and return the value before the increment.
|
||||||
|
*/
|
||||||
|
fih_int fih_cfi_get_and_increment(void)
|
||||||
|
{
|
||||||
|
fih_int saved = _fih_cfi_ctr;
|
||||||
|
_fih_cfi_ctr = fih_int_encode(fih_int_decode(saved) + 1);
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate that the saved precall value is the same as the value of the global
|
||||||
|
* counter. For this to be the case, a fih_ret must have been called between
|
||||||
|
* these functions being executed. If the values aren't the same then panic.
|
||||||
|
*/
|
||||||
|
void fih_cfi_validate(fih_int saved)
|
||||||
|
{
|
||||||
|
if (fih_int_decode(saved) != fih_int_decode(_fih_cfi_ctr)) {
|
||||||
|
FIH_PANIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrement the global CFI counter by one, so that it has the same value as
|
||||||
|
* before the cfi_precall
|
||||||
|
*/
|
||||||
|
void fih_cfi_decrement(void)
|
||||||
|
{
|
||||||
|
_fih_cfi_ctr = fih_int_encode(fih_int_decode(_fih_cfi_ctr) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FIH_ENABLE_CFI */
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_GLOBAL_FAIL
|
||||||
|
/* Global failure loop for bootloader code. Uses attribute used to prevent
|
||||||
|
* compiler removing due to non-standard calling procedure. Multiple loop jumps
|
||||||
|
* used to make unlooping difficult.
|
||||||
|
*/
|
||||||
|
__attribute__((used))
|
||||||
|
__attribute__((noinline))
|
||||||
|
void fih_panic_loop(void)
|
||||||
|
{
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
__asm volatile ("b fih_panic_loop");
|
||||||
|
}
|
||||||
|
#endif /* FIH_ENABLE_GLOBAL_FAIL */
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
#ifdef FIH_ENABLE_DELAY
|
||||||
|
|
||||||
|
#include "mbedtls/ctr_drbg.h"
|
||||||
|
#include "mbedtls/entropy.h"
|
||||||
|
|
||||||
|
/* Mbedtls implementation of the delay RNG. Can be replaced by any other RNG
|
||||||
|
* implementation that is backed by an entropy source by altering these
|
||||||
|
* functions. This is not provided as a header API and a C file implementation
|
||||||
|
* due to issues with inlining.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
|
||||||
|
#error "FIH_ENABLE_DELAY requires an entropy source"
|
||||||
|
#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
|
||||||
|
|
||||||
|
mbedtls_entropy_context fih_entropy_ctx;
|
||||||
|
mbedtls_ctr_drbg_context fih_drbg_ctx;
|
||||||
|
|
||||||
|
int fih_delay_init(void)
|
||||||
|
{
|
||||||
|
mbedtls_entropy_init(&fih_entropy_ctx);
|
||||||
|
mbedtls_ctr_drbg_init(&fih_drbg_ctx);
|
||||||
|
mbedtls_ctr_drbg_seed(&fih_drbg_ctx , mbedtls_entropy_func,
|
||||||
|
&fih_entropy_ctx, NULL, 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char fih_delay_random_uchar(void)
|
||||||
|
{
|
||||||
|
unsigned char delay;
|
||||||
|
|
||||||
|
mbedtls_ctr_drbg_random(&fih_drbg_ctx,(unsigned char*) &delay,
|
||||||
|
sizeof(delay));
|
||||||
|
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FIH_ENABLE_DELAY */
|
||||||
95
bootloader/mcuboot/boot/bootutil/src/image_ecdsa.c
Normal file
95
bootloader/mcuboot/boot/bootutil/src/image_ecdsa.c
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2017 Linaro LTD
|
||||||
|
* Copyright (C) 2021-2024 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_EC256) || defined(MCUBOOT_SIGN_EC384)
|
||||||
|
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
#include "bootutil/crypto/ecdsa.h"
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_BUILTIN_KEY)
|
||||||
|
fih_ret
|
||||||
|
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
|
||||||
|
uint8_t key_id)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
bootutil_ecdsa_context ctx;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
uint8_t *pubkey;
|
||||||
|
uint8_t *end;
|
||||||
|
|
||||||
|
pubkey = (uint8_t *)bootutil_keys[key_id].key;
|
||||||
|
end = pubkey + *bootutil_keys[key_id].len;
|
||||||
|
bootutil_ecdsa_init(&ctx);
|
||||||
|
|
||||||
|
rc = bootutil_ecdsa_parse_public_key(&ctx, &pubkey, end);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_ecdsa_verify(&ctx, pubkey, end-pubkey, hash, hlen, sig, slen);
|
||||||
|
fih_rc = fih_ret_encode_zero_equality(rc);
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
bootutil_ecdsa_drop(&ctx);
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
#else /* !MCUBOOT_BUILTIN_KEY */
|
||||||
|
fih_ret
|
||||||
|
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
|
||||||
|
uint8_t key_id)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
bootutil_ecdsa_context ctx;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
|
||||||
|
/* Use builtin key for image verification, no key parsing is required. */
|
||||||
|
ctx.key_id = key_id;
|
||||||
|
bootutil_ecdsa_init(&ctx);
|
||||||
|
|
||||||
|
/* The public key pointer and key size can be omitted. */
|
||||||
|
rc = bootutil_ecdsa_verify(&ctx, NULL, 0, hash, hlen, sig, slen);
|
||||||
|
fih_rc = fih_ret_encode_zero_equality(rc);
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_ecdsa_drop(&ctx);
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_BUILTIN_KEY */
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_SIGN_EC256 || MCUBOOT_SIGN_EC384 */
|
||||||
160
bootloader/mcuboot/boot/bootutil/src/image_ed25519.c
Normal file
160
bootloader/mcuboot/boot/bootutil/src/image_ed25519.c
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 JUUL Labs
|
||||||
|
* Copyright (c) 2021-2023 Arm Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#include "mbedtls/oid.h"
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "bootutil/crypto/common.h"
|
||||||
|
#include "bootutil/crypto/sha.h"
|
||||||
|
|
||||||
|
#define EDDSA_SIGNATURE_LENGTH 64
|
||||||
|
#define NUM_ED25519_BYTES 32
|
||||||
|
|
||||||
|
extern int ED25519_verify(const uint8_t *message, size_t message_len,
|
||||||
|
const uint8_t signature[EDDSA_SIGNATURE_LENGTH],
|
||||||
|
const uint8_t public_key[NUM_ED25519_BYTES]);
|
||||||
|
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
|
||||||
|
static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the public key used for signing.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bootutil_import_key(uint8_t **cp, uint8_t *end)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
mbedtls_asn1_buf alg;
|
||||||
|
mbedtls_asn1_buf param;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_tag(cp, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
end = *cp + len;
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_alg(cp, end, &alg, ¶m)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (*cp + len != end) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != NUM_ED25519_BYTES) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fih_ret
|
||||||
|
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
|
||||||
|
uint8_t key_id)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
uint8_t *pubkey = NULL;
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
uint8_t *end;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (hlen != IMAGE_HASH_SIZE || slen != EDDSA_SIGNATURE_LENGTH) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
pubkey = (uint8_t *)bootutil_keys[key_id].key;
|
||||||
|
end = pubkey + *bootutil_keys[key_id].len;
|
||||||
|
|
||||||
|
rc = bootutil_import_key(&pubkey, end);
|
||||||
|
if (rc) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey);
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
/* if verify returns 0, there was an error. */
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_SET(fih_rc, FIH_SUCCESS);
|
||||||
|
out:
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
fih_ret
|
||||||
|
bootutil_verify_img(const uint8_t *img, uint32_t size,
|
||||||
|
uint8_t *sig, size_t slen, uint8_t key_id)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
uint8_t *pubkey = NULL;
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
uint8_t *end;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (slen != EDDSA_SIGNATURE_LENGTH) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
pubkey = (uint8_t *)bootutil_keys[key_id].key;
|
||||||
|
end = pubkey + *bootutil_keys[key_id].len;
|
||||||
|
|
||||||
|
rc = bootutil_import_key(&pubkey, end);
|
||||||
|
if (rc) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = ED25519_verify(img, size, sig, pubkey);
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
/* if verify returns 0, there was an error. */
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_SET(fih_rc, FIH_SUCCESS);
|
||||||
|
out:
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_SIGN_ED25519 */
|
||||||
288
bootloader/mcuboot/boot/bootutil/src/image_rsa.c
Normal file
288
bootloader/mcuboot/boot/bootutil/src/image_rsa.c
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2018 Linaro LTD
|
||||||
|
* Copyright (c) 2017-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2020-2023 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_SIGN_RSA
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "bootutil/sign_key.h"
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
#define BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
|
||||||
|
#include "bootutil/crypto/rsa.h"
|
||||||
|
|
||||||
|
/* PSA Crypto APIs provide an integrated API to perform the verification
|
||||||
|
* while for other crypto backends we need to implement each step at this
|
||||||
|
* abstraction level
|
||||||
|
*/
|
||||||
|
#if !defined(MCUBOOT_USE_PSA_CRYPTO)
|
||||||
|
|
||||||
|
#include "bootutil/crypto/sha.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants for this particular constrained implementation of
|
||||||
|
* RSA-PSS. In particular, we support RSA 2048, with a SHA256 hash,
|
||||||
|
* and a 32-byte salt. A signature with different parameters will be
|
||||||
|
* rejected as invalid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The size, in octets, of the message. */
|
||||||
|
#define PSS_EMLEN (MCUBOOT_SIGN_RSA_LEN / 8)
|
||||||
|
|
||||||
|
/* The size of the hash function. For SHA256, this is 32 bytes. */
|
||||||
|
#define PSS_HLEN 32
|
||||||
|
|
||||||
|
/* Size of the salt, should be fixed. */
|
||||||
|
#define PSS_SLEN 32
|
||||||
|
|
||||||
|
/* The length of the mask: emLen - hLen - 1. */
|
||||||
|
#define PSS_MASK_LEN (PSS_EMLEN - PSS_HLEN - 1)
|
||||||
|
|
||||||
|
#define PSS_HASH_OFFSET PSS_MASK_LEN
|
||||||
|
|
||||||
|
/* For the mask itself, how many bytes should be all zeros. */
|
||||||
|
#define PSS_MASK_ZERO_COUNT (PSS_MASK_LEN - PSS_SLEN - 1)
|
||||||
|
#define PSS_MASK_ONE_POS PSS_MASK_ZERO_COUNT
|
||||||
|
|
||||||
|
/* Where the salt starts. */
|
||||||
|
#define PSS_MASK_SALT_POS (PSS_MASK_ONE_POS + 1)
|
||||||
|
|
||||||
|
static const uint8_t pss_zeros[8] = {0};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the RSA-PSS mask-generation function, MGF1. Assumptions
|
||||||
|
* are that the mask length will be less than 256 * PSS_HLEN, and
|
||||||
|
* therefore we never need to increment anything other than the low
|
||||||
|
* byte of the counter.
|
||||||
|
*
|
||||||
|
* This is described in PKCS#1, B.2.1.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pss_mgf1(uint8_t *mask, const uint8_t *hash)
|
||||||
|
{
|
||||||
|
bootutil_sha_context ctx;
|
||||||
|
uint8_t counter[4] = { 0, 0, 0, 0 };
|
||||||
|
uint8_t htmp[PSS_HLEN];
|
||||||
|
int count = PSS_MASK_LEN;
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
bootutil_sha_init(&ctx);
|
||||||
|
bootutil_sha_update(&ctx, hash, PSS_HLEN);
|
||||||
|
bootutil_sha_update(&ctx, counter, 4);
|
||||||
|
bootutil_sha_finish(&ctx, htmp);
|
||||||
|
|
||||||
|
counter[3]++;
|
||||||
|
|
||||||
|
bytes = PSS_HLEN;
|
||||||
|
if (bytes > count)
|
||||||
|
bytes = count;
|
||||||
|
|
||||||
|
memcpy(mask, htmp, bytes);
|
||||||
|
mask += bytes;
|
||||||
|
count -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootutil_sha_drop(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate an RSA signature, using RSA-PSS, as described in PKCS #1
|
||||||
|
* v2.2, section 9.1.2, with many parameters required to have fixed
|
||||||
|
* values. RSASSA-PSS-VERIFY RFC8017 section 8.1.2
|
||||||
|
*/
|
||||||
|
static fih_ret
|
||||||
|
bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
|
||||||
|
uint8_t *sig, size_t slen)
|
||||||
|
{
|
||||||
|
bootutil_sha_context shactx;
|
||||||
|
uint8_t em[MBEDTLS_MPI_MAX_SIZE];
|
||||||
|
uint8_t db_mask[PSS_MASK_LEN];
|
||||||
|
uint8_t h2[PSS_HLEN];
|
||||||
|
int i;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
|
||||||
|
/* The caller has already verified that slen == bootutil_rsa_get_len(ctx) */
|
||||||
|
if (slen != PSS_EMLEN ||
|
||||||
|
PSS_EMLEN > MBEDTLS_MPI_MAX_SIZE) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hlen != PSS_HLEN) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply RSAVP1 to produce em = sig^E mod N using the public key */
|
||||||
|
if (bootutil_rsa_public(ctx, sig, em)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PKCS #1 v2.2, 9.1.2 EMSA-PSS-Verify
|
||||||
|
*
|
||||||
|
* emBits is 2048
|
||||||
|
* emLen = ceil(emBits/8) = 256
|
||||||
|
*
|
||||||
|
* The salt length is not known at the beginning.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 1. The message is constrained by the address space of a
|
||||||
|
* 32-bit processor, which is far less than the 2^61-1 limit of
|
||||||
|
* SHA-256.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 2. mHash is passed in as 'hash', with hLen the hlen
|
||||||
|
* argument. */
|
||||||
|
|
||||||
|
/* Step 3. if emLen < hLen + sLen + 2, inconsistent and stop.
|
||||||
|
* The salt length is not known at this point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 4. If the rightmost octet of EM does have the value
|
||||||
|
* 0xbc, output inconsistent and stop.
|
||||||
|
*/
|
||||||
|
if (em[PSS_EMLEN - 1] != 0xbc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 5. Let maskedDB be the leftmost emLen - hLen - 1 octets
|
||||||
|
* of EM, and H be the next hLen octets.
|
||||||
|
*
|
||||||
|
* maskedDB is then the first 256 - 32 - 1 = 0-222
|
||||||
|
* H is 32 bytes 223-254
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 6. If the leftmost 8emLen - emBits bits of the leftmost
|
||||||
|
* octet in maskedDB are not all equal to zero, output
|
||||||
|
* inconsistent and stop.
|
||||||
|
*
|
||||||
|
* 8emLen - emBits is zero, so there is nothing to test here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 7. let dbMask = MGF(H, emLen - hLen - 1). */
|
||||||
|
pss_mgf1(db_mask, &em[PSS_HASH_OFFSET]);
|
||||||
|
|
||||||
|
/* Step 8. let DB = maskedDB xor dbMask.
|
||||||
|
* To avoid needing an additional buffer, store the 'db' in the
|
||||||
|
* same buffer as db_mask. From now, to the end of this function,
|
||||||
|
* db_mask refers to the unmasked 'db'. */
|
||||||
|
for (i = 0; i < PSS_MASK_LEN; i++) {
|
||||||
|
db_mask[i] ^= em[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 9. Set the leftmost 8emLen - emBits bits of the leftmost
|
||||||
|
* octet in DB to zero.
|
||||||
|
* pycrypto seems to always make the emBits 2047, so we need to
|
||||||
|
* clear the top bit. */
|
||||||
|
db_mask[0] &= 0x7F;
|
||||||
|
|
||||||
|
/* Step 10. If the emLen - hLen - sLen - 2 leftmost octets of DB
|
||||||
|
* are not zero or if the octet at position emLen - hLen - sLen -
|
||||||
|
* 1 (the leftmost position is "position 1") does not have
|
||||||
|
* hexadecimal value 0x01, output "inconsistent" and stop. */
|
||||||
|
for (i = 0; i < PSS_MASK_ZERO_COUNT; i++) {
|
||||||
|
if (db_mask[i] != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (db_mask[PSS_MASK_ONE_POS] != 1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 11. Let salt be the last sLen octets of DB */
|
||||||
|
|
||||||
|
/* Step 12. Let M' = 0x00 00 00 00 00 00 00 00 || mHash || salt; */
|
||||||
|
|
||||||
|
/* Step 13. Let H' = Hash(M') */
|
||||||
|
bootutil_sha_init(&shactx);
|
||||||
|
bootutil_sha_update(&shactx, pss_zeros, 8);
|
||||||
|
bootutil_sha_update(&shactx, hash, PSS_HLEN);
|
||||||
|
bootutil_sha_update(&shactx, &db_mask[PSS_MASK_SALT_POS], PSS_SLEN);
|
||||||
|
bootutil_sha_finish(&shactx, h2);
|
||||||
|
bootutil_sha_drop(&shactx);
|
||||||
|
|
||||||
|
/* Step 14. If H = H', output "consistent". Otherwise, output
|
||||||
|
* "inconsistent". */
|
||||||
|
FIH_CALL(boot_fih_memequal, fih_rc, h2, &em[PSS_HASH_OFFSET], PSS_HLEN);
|
||||||
|
|
||||||
|
out:
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* MCUBOOT_USE_PSA_CRYPTO */
|
||||||
|
|
||||||
|
static fih_ret
|
||||||
|
bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
|
||||||
|
uint8_t *sig, size_t slen)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
|
||||||
|
/* PSA Crypto APIs allow the verification in a single call */
|
||||||
|
rc = bootutil_rsassa_pss_verify(ctx, hash, hlen, sig, slen);
|
||||||
|
|
||||||
|
fih_rc = fih_ret_encode_zero_equality(rc);
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MCUBOOT_USE_PSA_CRYPTO */
|
||||||
|
|
||||||
|
fih_ret
|
||||||
|
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
|
||||||
|
uint8_t key_id)
|
||||||
|
{
|
||||||
|
bootutil_rsa_context ctx;
|
||||||
|
int rc;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
uint8_t *cp;
|
||||||
|
uint8_t *end;
|
||||||
|
|
||||||
|
bootutil_rsa_init(&ctx);
|
||||||
|
|
||||||
|
cp = (uint8_t *)bootutil_keys[key_id].key;
|
||||||
|
end = cp + *bootutil_keys[key_id].len;
|
||||||
|
|
||||||
|
/* The key used for signature verification is a public RSA key */
|
||||||
|
rc = bootutil_rsa_parse_public_key(&ctx, &cp, end);
|
||||||
|
if (rc || slen != bootutil_rsa_get_len(&ctx)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
FIH_CALL(bootutil_cmp_rsasig, fih_rc, &ctx, hash, hlen, sig, slen);
|
||||||
|
|
||||||
|
out:
|
||||||
|
bootutil_rsa_drop(&ctx);
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_SIGN_RSA */
|
||||||
920
bootloader/mcuboot/boot/bootutil/src/image_validate.c
Normal file
920
bootloader/mcuboot/boot/bootutil/src/image_validate.c
Normal file
@@ -0,0 +1,920 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 Linaro LTD
|
||||||
|
* Copyright (c) 2016-2019 JUUL Labs
|
||||||
|
* Copyright (c) 2019-2024 Arm Limited
|
||||||
|
*
|
||||||
|
* Original license:
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <flash_map_backend/flash_map_backend.h>
|
||||||
|
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil/crypto/sha.h"
|
||||||
|
#include "bootutil/sign_key.h"
|
||||||
|
#include "bootutil/security_cnt.h"
|
||||||
|
#include "bootutil/fault_injection_hardening.h"
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_DECOMPRESS_IMAGES)
|
||||||
|
#include <nrf_compress/implementation.h>
|
||||||
|
#include <compression/decompression.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
#include "bootutil/enc_key.h"
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_SIGN_RSA)
|
||||||
|
#include "mbedtls/rsa.h"
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_SIGN_EC256)
|
||||||
|
#include "mbedtls/ecdsa.h"
|
||||||
|
#endif
|
||||||
|
#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SIGN_RSA) || \
|
||||||
|
defined(MCUBOOT_SIGN_EC256)
|
||||||
|
#include "mbedtls/asn1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_SIGN_PURE
|
||||||
|
/*
|
||||||
|
* Compute SHA hash over the image.
|
||||||
|
* (SHA384 if ECDSA-P384 is being used,
|
||||||
|
* SHA256 otherwise).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bootutil_img_hash(struct enc_key_data *enc_state, int image_index,
|
||||||
|
struct image_header *hdr, const struct flash_area *fap,
|
||||||
|
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result,
|
||||||
|
uint8_t *seed, int seed_len)
|
||||||
|
{
|
||||||
|
bootutil_sha_context sha_ctx;
|
||||||
|
uint32_t size;
|
||||||
|
uint16_t hdr_size;
|
||||||
|
uint32_t blk_off;
|
||||||
|
uint32_t tlv_off;
|
||||||
|
#if !defined(MCUBOOT_HASH_STORAGE_DIRECTLY)
|
||||||
|
int rc;
|
||||||
|
uint32_t off;
|
||||||
|
uint32_t blk_sz;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \
|
||||||
|
defined(MCUBOOT_RAM_LOAD)
|
||||||
|
(void)enc_state;
|
||||||
|
(void)image_index;
|
||||||
|
(void)hdr_size;
|
||||||
|
(void)blk_off;
|
||||||
|
(void)tlv_off;
|
||||||
|
#ifdef MCUBOOT_RAM_LOAD
|
||||||
|
(void)blk_sz;
|
||||||
|
(void)off;
|
||||||
|
(void)rc;
|
||||||
|
(void)fap;
|
||||||
|
(void)tmp_buf;
|
||||||
|
(void)tmp_buf_sz;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
/* Encrypted images only exist in the secondary slot */
|
||||||
|
if (MUST_DECRYPT(fap, image_index, hdr) &&
|
||||||
|
!boot_enc_valid(enc_state, 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bootutil_sha_init(&sha_ctx);
|
||||||
|
|
||||||
|
/* in some cases (split image) the hash is seeded with data from
|
||||||
|
* the loader image */
|
||||||
|
if (seed && (seed_len > 0)) {
|
||||||
|
bootutil_sha_update(&sha_ctx, seed, seed_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash is computed over image header and image itself. */
|
||||||
|
size = hdr_size = hdr->ih_hdr_size;
|
||||||
|
size += hdr->ih_img_size;
|
||||||
|
tlv_off = size;
|
||||||
|
|
||||||
|
/* If protected TLVs are present they are also hashed. */
|
||||||
|
size += hdr->ih_protect_tlv_size;
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY
|
||||||
|
/* No chunk loading, storage is mapped to address space and can
|
||||||
|
* be directly given to hashing function.
|
||||||
|
*/
|
||||||
|
bootutil_sha_update(&sha_ctx, (void *)flash_area_get_off(fap), size);
|
||||||
|
#else /* MCUBOOT_HASH_STORAGE_DIRECTLY */
|
||||||
|
#ifdef MCUBOOT_RAM_LOAD
|
||||||
|
bootutil_sha_update(&sha_ctx,
|
||||||
|
(void*)(IMAGE_RAM_BASE + hdr->ih_load_addr),
|
||||||
|
size);
|
||||||
|
#else
|
||||||
|
for (off = 0; off < size; off += blk_sz) {
|
||||||
|
blk_sz = size - off;
|
||||||
|
if (blk_sz > tmp_buf_sz) {
|
||||||
|
blk_sz = tmp_buf_sz;
|
||||||
|
}
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
/* The only data that is encrypted in an image is the payload;
|
||||||
|
* both header and TLVs (when protected) are not.
|
||||||
|
*/
|
||||||
|
if ((off < hdr_size) && ((off + blk_sz) > hdr_size)) {
|
||||||
|
/* read only the header */
|
||||||
|
blk_sz = hdr_size - off;
|
||||||
|
}
|
||||||
|
if ((off < tlv_off) && ((off + blk_sz) > tlv_off)) {
|
||||||
|
/* read only up to the end of the image payload */
|
||||||
|
blk_sz = tlv_off - off;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
rc = flash_area_read(fap, off, tmp_buf, blk_sz);
|
||||||
|
if (rc) {
|
||||||
|
bootutil_sha_drop(&sha_ctx);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#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_enc_decrypt(enc_state, slot, off - hdr_size,
|
||||||
|
blk_sz, blk_off, tmp_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bootutil_sha_update(&sha_ctx, tmp_buf, blk_sz);
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_RAM_LOAD */
|
||||||
|
#endif /* MCUBOOT_HASH_STORAGE_DIRECTLY */
|
||||||
|
bootutil_sha_finish(&sha_ctx, hash_result);
|
||||||
|
bootutil_sha_drop(&sha_ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently, we only support being able to verify one type of
|
||||||
|
* signature, because there is a single verification function that we
|
||||||
|
* call. List the type of TLV we are expecting. If we aren't
|
||||||
|
* configured for any signature, don't define this macro.
|
||||||
|
*/
|
||||||
|
#if (defined(MCUBOOT_SIGN_RSA) + \
|
||||||
|
defined(MCUBOOT_SIGN_EC256) + \
|
||||||
|
defined(MCUBOOT_SIGN_EC384) + \
|
||||||
|
defined(MCUBOOT_SIGN_ED25519)) > 1
|
||||||
|
#error "Only a single signature type is supported!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_RSA)
|
||||||
|
# if MCUBOOT_SIGN_RSA_LEN == 2048
|
||||||
|
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS
|
||||||
|
# elif MCUBOOT_SIGN_RSA_LEN == 3072
|
||||||
|
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS
|
||||||
|
# else
|
||||||
|
# error "Unsupported RSA signature length"
|
||||||
|
# endif
|
||||||
|
# define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8)
|
||||||
|
# define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE) /* 2048 bits */
|
||||||
|
#elif defined(MCUBOOT_SIGN_EC256) || \
|
||||||
|
defined(MCUBOOT_SIGN_EC384) || \
|
||||||
|
defined(MCUBOOT_SIGN_EC)
|
||||||
|
# define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG
|
||||||
|
# define SIG_BUF_SIZE 128
|
||||||
|
# define EXPECTED_SIG_LEN(x) (1) /* always true, ASN.1 will validate */
|
||||||
|
#elif defined(MCUBOOT_SIGN_ED25519)
|
||||||
|
# define EXPECTED_SIG_TLV IMAGE_TLV_ED25519
|
||||||
|
# define SIG_BUF_SIZE 64
|
||||||
|
# define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE)
|
||||||
|
#else
|
||||||
|
# define SIG_BUF_SIZE 32 /* no signing, sha256 digest only */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(MCUBOOT_HW_KEY) + \
|
||||||
|
defined(MCUBOOT_BUILTIN_KEY)) > 1
|
||||||
|
#error "Please use either MCUBOOT_HW_KEY or the MCUBOOT_BUILTIN_KEY feature."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EXPECTED_SIG_TLV
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_BUILTIN_KEY)
|
||||||
|
#if !defined(MCUBOOT_HW_KEY)
|
||||||
|
/* The key TLV contains the hash of the public key. */
|
||||||
|
# define EXPECTED_KEY_TLV IMAGE_TLV_KEYHASH
|
||||||
|
# define KEY_BUF_SIZE IMAGE_HASH_SIZE
|
||||||
|
#else
|
||||||
|
/* The key TLV contains the whole public key.
|
||||||
|
* Add a few extra bytes to the key buffer size for encoding and
|
||||||
|
* for public exponent.
|
||||||
|
*/
|
||||||
|
# define EXPECTED_KEY_TLV IMAGE_TLV_PUBKEY
|
||||||
|
# define KEY_BUF_SIZE (SIG_BUF_SIZE + 24)
|
||||||
|
#endif /* !MCUBOOT_HW_KEY */
|
||||||
|
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
#if !defined(MCUBOOT_HW_KEY)
|
||||||
|
static int
|
||||||
|
bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len)
|
||||||
|
{
|
||||||
|
bootutil_sha_context sha_ctx;
|
||||||
|
int i;
|
||||||
|
const struct bootutil_key *key;
|
||||||
|
uint8_t hash[IMAGE_HASH_SIZE];
|
||||||
|
|
||||||
|
if (keyhash_len > IMAGE_HASH_SIZE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bootutil_key_cnt; i++) {
|
||||||
|
key = &bootutil_keys[i];
|
||||||
|
bootutil_sha_init(&sha_ctx);
|
||||||
|
bootutil_sha_update(&sha_ctx, key->key, *key->len);
|
||||||
|
bootutil_sha_finish(&sha_ctx, hash);
|
||||||
|
if (!memcmp(hash, keyhash, keyhash_len)) {
|
||||||
|
bootutil_sha_drop(&sha_ctx);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bootutil_sha_drop(&sha_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else /* !MCUBOOT_HW_KEY */
|
||||||
|
extern unsigned int pub_key_len;
|
||||||
|
static int
|
||||||
|
bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
|
||||||
|
{
|
||||||
|
bootutil_sha_context sha_ctx;
|
||||||
|
uint8_t hash[IMAGE_HASH_SIZE];
|
||||||
|
uint8_t key_hash[IMAGE_HASH_SIZE];
|
||||||
|
size_t key_hash_size = sizeof(key_hash);
|
||||||
|
int rc;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
|
||||||
|
bootutil_sha_init(&sha_ctx);
|
||||||
|
bootutil_sha_update(&sha_ctx, key, key_len);
|
||||||
|
bootutil_sha_finish(&sha_ctx, hash);
|
||||||
|
bootutil_sha_drop(&sha_ctx);
|
||||||
|
|
||||||
|
rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adding hardening to avoid this potential attack:
|
||||||
|
* - Image is signed with an arbitrary key and the corresponding public
|
||||||
|
* key is added as a TLV field.
|
||||||
|
* - During public key validation (comparing against key-hash read from
|
||||||
|
* HW) a fault is injected to accept the public key as valid one.
|
||||||
|
*/
|
||||||
|
FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size);
|
||||||
|
if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
bootutil_keys[0].key = key;
|
||||||
|
pub_key_len = key_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* !MCUBOOT_HW_KEY */
|
||||||
|
#endif /* !MCUBOOT_BUILTIN_KEY */
|
||||||
|
#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */
|
||||||
|
#endif /* EXPECTED_SIG_TLV */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value of an image's security counter.
|
||||||
|
*
|
||||||
|
* @param hdr Pointer to the image header structure.
|
||||||
|
* @param fap Pointer to a description structure of the image's
|
||||||
|
* flash area.
|
||||||
|
* @param security_cnt Pointer to store the security counter value.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
int32_t
|
||||||
|
bootutil_get_img_security_cnt(struct image_header *hdr,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
uint32_t *img_security_cnt)
|
||||||
|
{
|
||||||
|
struct image_tlv_iter it;
|
||||||
|
uint32_t off;
|
||||||
|
uint16_t len;
|
||||||
|
int32_t rc;
|
||||||
|
|
||||||
|
if ((hdr == NULL) ||
|
||||||
|
(fap == NULL) ||
|
||||||
|
(img_security_cnt == NULL)) {
|
||||||
|
/* Invalid parameter. */
|
||||||
|
return BOOT_EBADARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The security counter TLV is in the protected part of the TLV area. */
|
||||||
|
if (hdr->ih_protect_tlv_size == 0) {
|
||||||
|
return BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SEC_CNT, true);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse through the protected TLV area to find
|
||||||
|
* the security counter TLV.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
|
||||||
|
if (rc != 0) {
|
||||||
|
/* Security counter TLV has not been found. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len != sizeof(*img_security_cnt)) {
|
||||||
|
/* Security counter is not valid. */
|
||||||
|
return BOOT_EBADIMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, img_security_cnt, len);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_PURE)
|
||||||
|
/* Returns:
|
||||||
|
* 0 -- found
|
||||||
|
* 1 -- not found or found but not true
|
||||||
|
* -1 -- failed for some reason
|
||||||
|
*
|
||||||
|
* Value of TLV does not matter, presence decides.
|
||||||
|
*/
|
||||||
|
static int bootutil_check_for_pure(const struct image_header *hdr,
|
||||||
|
const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
struct image_tlv_iter it;
|
||||||
|
uint32_t off;
|
||||||
|
uint16_t len;
|
||||||
|
int32_t rc;
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for the TLV */
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
|
||||||
|
if (rc == 0 && len == 1) {
|
||||||
|
bool val;
|
||||||
|
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, 1);
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = !val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ALLOW_ROGUE_TLVS
|
||||||
|
/*
|
||||||
|
* The following list of TLVs are the only entries allowed in the unprotected
|
||||||
|
* TLV section. All other TLV entries must be in the protected section.
|
||||||
|
*/
|
||||||
|
static const uint16_t allowed_unprot_tlvs[] = {
|
||||||
|
IMAGE_TLV_KEYHASH,
|
||||||
|
IMAGE_TLV_PUBKEY,
|
||||||
|
IMAGE_TLV_SHA256,
|
||||||
|
IMAGE_TLV_SHA384,
|
||||||
|
IMAGE_TLV_SHA512,
|
||||||
|
IMAGE_TLV_RSA2048_PSS,
|
||||||
|
IMAGE_TLV_ECDSA224,
|
||||||
|
IMAGE_TLV_ECDSA_SIG,
|
||||||
|
IMAGE_TLV_RSA3072_PSS,
|
||||||
|
IMAGE_TLV_ED25519,
|
||||||
|
#if defined(MCUBOOT_SIGN_PURE)
|
||||||
|
IMAGE_TLV_SIG_PURE,
|
||||||
|
#endif
|
||||||
|
IMAGE_TLV_ENC_RSA2048,
|
||||||
|
IMAGE_TLV_ENC_KW,
|
||||||
|
IMAGE_TLV_ENC_EC256,
|
||||||
|
IMAGE_TLV_ENC_X25519,
|
||||||
|
/* Mark end with ANY. */
|
||||||
|
IMAGE_TLV_ANY,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify the integrity of the image.
|
||||||
|
* Return non-zero if image could not be validated/does not validate.
|
||||||
|
*/
|
||||||
|
fih_ret
|
||||||
|
bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
|
||||||
|
struct image_header *hdr, const struct flash_area *fap,
|
||||||
|
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *seed,
|
||||||
|
int seed_len, uint8_t *out_hash)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
uint16_t len;
|
||||||
|
uint16_t type;
|
||||||
|
#ifdef EXPECTED_SIG_TLV
|
||||||
|
FIH_DECLARE(valid_signature, FIH_FAILURE);
|
||||||
|
#ifndef MCUBOOT_BUILTIN_KEY
|
||||||
|
int key_id = -1;
|
||||||
|
#else
|
||||||
|
/* Pass a key ID equal to the image index, the underlying crypto library
|
||||||
|
* is responsible for mapping the image index to a builtin key ID.
|
||||||
|
*/
|
||||||
|
int key_id = image_index;
|
||||||
|
#endif /* !MCUBOOT_BUILTIN_KEY */
|
||||||
|
#ifdef MCUBOOT_HW_KEY
|
||||||
|
uint8_t key_buf[KEY_BUF_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif /* EXPECTED_SIG_TLV */
|
||||||
|
struct image_tlv_iter it;
|
||||||
|
uint8_t buf[SIG_BUF_SIZE];
|
||||||
|
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
|
||||||
|
int image_hash_valid = 0;
|
||||||
|
uint8_t hash[IMAGE_HASH_SIZE];
|
||||||
|
#endif
|
||||||
|
int rc = 0;
|
||||||
|
FIH_DECLARE(fih_rc, FIH_FAILURE);
|
||||||
|
#ifdef MCUBOOT_HW_ROLLBACK_PROT
|
||||||
|
fih_int security_cnt = fih_int_encode(INT_MAX);
|
||||||
|
uint32_t img_security_cnt = 0;
|
||||||
|
FIH_DECLARE(security_counter_valid, FIH_FAILURE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_DECOMPRESS_IMAGES
|
||||||
|
/* If the image is compressed, the integrity of the image must also be validated */
|
||||||
|
if (MUST_DECOMPRESS(fap, image_index, hdr)) {
|
||||||
|
bool found_decompressed_size = false;
|
||||||
|
bool found_decompressed_sha = false;
|
||||||
|
bool found_decompressed_signature = false;
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.tlv_end > bootutil_max_image_size(fap)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint16_t expected_size = 0;
|
||||||
|
bool *found_flag = NULL;
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
|
||||||
|
if (rc < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case IMAGE_TLV_DECOMP_SIZE:
|
||||||
|
expected_size = sizeof(size_t);
|
||||||
|
found_flag = &found_decompressed_size;
|
||||||
|
break;
|
||||||
|
case IMAGE_TLV_DECOMP_SHA:
|
||||||
|
expected_size = IMAGE_HASH_SIZE;
|
||||||
|
found_flag = &found_decompressed_sha;
|
||||||
|
break;
|
||||||
|
case IMAGE_TLV_DECOMP_SIGNATURE:
|
||||||
|
found_flag = &found_decompressed_signature;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
} else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*found_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
|
||||||
|
rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
|
||||||
|
tmp_buf_sz, hash, seed, seed_len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_hash) {
|
||||||
|
memcpy(out_hash, hash, IMAGE_HASH_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SIGN_PURE)
|
||||||
|
/* If Pure type signature is expected then it has to be there */
|
||||||
|
rc = bootutil_check_for_pure(hdr, fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.tlv_end > bootutil_max_image_size(fap)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Traverse through all of the TLVs, performing any checks we know
|
||||||
|
* and are able to do.
|
||||||
|
*/
|
||||||
|
while (true) {
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
|
||||||
|
if (rc < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ALLOW_ROGUE_TLVS
|
||||||
|
/*
|
||||||
|
* Ensure that the non-protected TLV only has entries necessary to hold
|
||||||
|
* the signature. We also allow encryption related keys to be in the
|
||||||
|
* unprotected area.
|
||||||
|
*/
|
||||||
|
if (!bootutil_tlv_iter_is_prot(&it, off)) {
|
||||||
|
bool found = false;
|
||||||
|
for (const uint16_t *p = allowed_unprot_tlvs; *p != IMAGE_TLV_ANY; p++) {
|
||||||
|
if (type == *p) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
switch(type) {
|
||||||
|
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
|
||||||
|
case EXPECTED_HASH_TLV:
|
||||||
|
{
|
||||||
|
/* Verify the image hash. This must always be present. */
|
||||||
|
if (len != sizeof(hash)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash));
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_hash_valid = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
#ifdef EXPECTED_KEY_TLV
|
||||||
|
case EXPECTED_KEY_TLV:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Determine which key we should be checking.
|
||||||
|
*/
|
||||||
|
if (len > KEY_BUF_SIZE) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#ifndef MCUBOOT_HW_KEY
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
key_id = bootutil_find_key(buf, len);
|
||||||
|
#else
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
key_id = bootutil_find_key(image_index, key_buf, len);
|
||||||
|
#endif /* !MCUBOOT_HW_KEY */
|
||||||
|
/*
|
||||||
|
* The key may not be found, which is acceptable. There
|
||||||
|
* can be multiple signatures, each preceded by a key.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* EXPECTED_KEY_TLV */
|
||||||
|
#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */
|
||||||
|
#ifdef EXPECTED_SIG_TLV
|
||||||
|
case EXPECTED_SIG_TLV:
|
||||||
|
{
|
||||||
|
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
|
||||||
|
/* Ignore this signature if it is out of bounds. */
|
||||||
|
if (key_id < 0 || key_id >= bootutil_key_cnt) {
|
||||||
|
key_id = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */
|
||||||
|
if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#ifndef MCUBOOT_SIGN_PURE
|
||||||
|
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
|
||||||
|
buf, len, key_id);
|
||||||
|
#else
|
||||||
|
/* Directly check signature on the image, by using the mapping of
|
||||||
|
* a device to memory. The pointer is beginning of image in flash,
|
||||||
|
* so offset of area, the range is header + image + protected tlvs.
|
||||||
|
*/
|
||||||
|
FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap),
|
||||||
|
hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size,
|
||||||
|
buf, len, key_id);
|
||||||
|
#endif
|
||||||
|
key_id = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* EXPECTED_SIG_TLV */
|
||||||
|
#ifdef MCUBOOT_HW_ROLLBACK_PROT
|
||||||
|
case IMAGE_TLV_SEC_CNT:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Verify the image's security counter.
|
||||||
|
* This must always be present.
|
||||||
|
*/
|
||||||
|
if (len != sizeof(img_security_cnt)) {
|
||||||
|
/* Security counter is not valid. */
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, &img_security_cnt, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index,
|
||||||
|
&security_cnt);
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare the new image's security counter value against the
|
||||||
|
* stored security counter value.
|
||||||
|
*/
|
||||||
|
fih_rc = fih_ret_encode_zero_equality(img_security_cnt <
|
||||||
|
(uint32_t)fih_int_decode(security_cnt));
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The image's security counter has been successfully verified. */
|
||||||
|
security_counter_valid = fih_rc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
|
||||||
|
rc = !image_hash_valid;
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#elif defined(MCUBOOT_SIGN_PURE)
|
||||||
|
/* This returns true on EQ, rc is err on non-0 */
|
||||||
|
rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS);
|
||||||
|
#endif
|
||||||
|
#ifdef EXPECTED_SIG_TLV
|
||||||
|
FIH_SET(fih_rc, valid_signature);
|
||||||
|
#endif
|
||||||
|
#ifdef MCUBOOT_HW_ROLLBACK_PROT
|
||||||
|
if (FIH_NOT_EQ(security_counter_valid, FIH_SUCCESS)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_DECOMPRESS_IMAGES
|
||||||
|
/* Only after all previous verifications have passed, perform a dry-run of the decompression
|
||||||
|
* and ensure the image is valid
|
||||||
|
*/
|
||||||
|
if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) {
|
||||||
|
image_hash_valid = 0;
|
||||||
|
FIH_SET(valid_signature, FIH_FAILURE);
|
||||||
|
|
||||||
|
rc = bootutil_img_hash_decompress(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz,
|
||||||
|
hash, seed, seed_len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.tlv_end > bootutil_max_image_size(fap)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
|
||||||
|
if (rc < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IMAGE_TLV_DECOMP_SHA) {
|
||||||
|
/* Verify the image hash. This must always be present. */
|
||||||
|
if (len != sizeof(hash)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash));
|
||||||
|
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_hash_valid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = !image_hash_valid;
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef EXPECTED_SIG_TLV
|
||||||
|
#ifdef EXPECTED_KEY_TLV
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.tlv_end > bootutil_max_image_size(fap)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
|
||||||
|
if (rc < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == EXPECTED_KEY_TLV) {
|
||||||
|
/*
|
||||||
|
* Determine which key we should be checking.
|
||||||
|
*/
|
||||||
|
if (len > KEY_BUF_SIZE) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#ifndef MCUBOOT_HW_KEY
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
key_id = bootutil_find_key(buf, len);
|
||||||
|
#else
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
key_id = bootutil_find_key(image_index, key_buf, len);
|
||||||
|
#endif /* !MCUBOOT_HW_KEY */
|
||||||
|
/*
|
||||||
|
* The key may not be found, which is acceptable. There
|
||||||
|
* can be multiple signatures, each preceded by a key.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* EXPECTED_KEY_TLV */
|
||||||
|
|
||||||
|
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.tlv_end > bootutil_max_image_size(fap)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
|
||||||
|
if (rc < 0) {
|
||||||
|
goto out;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == IMAGE_TLV_DECOMP_SIGNATURE) {
|
||||||
|
/* Ignore this signature if it is out of bounds. */
|
||||||
|
if (key_id < 0 || key_id >= bootutil_key_cnt) {
|
||||||
|
key_id = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
|
||||||
|
if (rc) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
|
||||||
|
buf, len, key_id);
|
||||||
|
key_id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* EXPECTED_SIG_TLV */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EXPECTED_SIG_TLV
|
||||||
|
FIH_SET(fih_rc, valid_signature);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (rc) {
|
||||||
|
FIH_SET(fih_rc, FIH_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
FIH_RET(fih_rc);
|
||||||
|
}
|
||||||
3974
bootloader/mcuboot/boot/bootutil/src/loader.c
Normal file
3974
bootloader/mcuboot/boot/bootutil/src/loader.c
Normal file
File diff suppressed because it is too large
Load Diff
3896
bootloader/mcuboot/boot/bootutil/src/loader_legacy_child_parent.c
Normal file
3896
bootloader/mcuboot/boot/bootutil/src/loader_legacy_child_parent.c
Normal file
File diff suppressed because it is too large
Load Diff
234
bootloader/mcuboot/boot/bootutil/src/swap_misc.c
Normal file
234
bootloader/mcuboot/boot/bootutil/src/swap_misc.c
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 JUUL Labs
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "swap_priv.h"
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
|
||||||
|
int
|
||||||
|
swap_erase_trailer_sectors(const struct boot_loader_state *state,
|
||||||
|
const struct flash_area *fap)
|
||||||
|
{
|
||||||
|
uint8_t slot;
|
||||||
|
uint32_t sector;
|
||||||
|
uint32_t trailer_sz;
|
||||||
|
uint32_t total_sz;
|
||||||
|
uint32_t off;
|
||||||
|
uint32_t sz;
|
||||||
|
int fa_id_primary;
|
||||||
|
int fa_id_secondary;
|
||||||
|
uint8_t image_index;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
BOOT_LOG_DBG("erasing trailer; fa_id=%d", flash_area_get_id(fap));
|
||||||
|
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
|
||||||
|
BOOT_PRIMARY_SLOT);
|
||||||
|
fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
|
||||||
|
BOOT_SECONDARY_SLOT);
|
||||||
|
|
||||||
|
if (flash_area_get_id(fap) == fa_id_primary) {
|
||||||
|
slot = BOOT_PRIMARY_SLOT;
|
||||||
|
} else if (flash_area_get_id(fap) == fa_id_secondary) {
|
||||||
|
slot = BOOT_SECONDARY_SLOT;
|
||||||
|
} else {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete starting from last sector and moving to beginning */
|
||||||
|
sector = boot_img_num_sectors(state, slot) - 1;
|
||||||
|
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
|
||||||
|
total_sz = 0;
|
||||||
|
do {
|
||||||
|
sz = boot_img_sector_size(state, slot, sector);
|
||||||
|
off = boot_img_sector_off(state, slot, sector);
|
||||||
|
rc = boot_erase_region(fap, off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
sector--;
|
||||||
|
total_sz += sz;
|
||||||
|
} while (total_sz < trailer_sz);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swap_status_init(const struct boot_loader_state *state,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
const struct boot_status *bs)
|
||||||
|
{
|
||||||
|
struct boot_swap_state swap_state;
|
||||||
|
uint8_t image_index;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1)
|
||||||
|
(void)state;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
|
||||||
|
BOOT_LOG_DBG("initializing status; fa_id=%d", flash_area_get_id(fap));
|
||||||
|
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
|
||||||
|
&swap_state);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
|
||||||
|
rc = boot_write_swap_info(fap, bs->swap_type, image_index);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swap_state.image_ok == BOOT_FLAG_SET) {
|
||||||
|
rc = boot_write_image_ok(fap);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_write_swap_size(fap, bs->swap_size);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
rc = boot_write_enc_key(fap, 0, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_enc_key(fap, 1, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = boot_write_magic(fap);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
uint32_t off;
|
||||||
|
uint8_t swap_info;
|
||||||
|
int area_id;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
bs->source = swap_status_source(state);
|
||||||
|
switch (bs->source) {
|
||||||
|
case BOOT_STATUS_SOURCE_NONE:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
case BOOT_STATUS_SOURCE_SCRATCH:
|
||||||
|
area_id = FLASH_AREA_IMAGE_SCRATCH;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
|
||||||
|
area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return BOOT_EBADARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = flash_area_open(area_id, &fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = swap_read_status_bytes(fap, state, bs);
|
||||||
|
if (rc == 0) {
|
||||||
|
off = boot_swap_info_off(fap);
|
||||||
|
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info)) {
|
||||||
|
BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the swap type info */
|
||||||
|
bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
flash_area_close(fap);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swap_set_copy_done(uint8_t image_index)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
&fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_write_copy_done(fap);
|
||||||
|
flash_area_close(fap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swap_set_image_ok(uint8_t image_index)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
struct boot_swap_state state;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
&fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(fap, &state);
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.image_ok == BOOT_FLAG_UNSET) {
|
||||||
|
rc = boot_write_image_ok(fap);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
flash_area_close(fap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
|
||||||
608
bootloader/mcuboot/boot/bootutil/src/swap_move.c
Normal file
608
bootloader/mcuboot/boot/bootutil/src/swap_move.c
Normal file
@@ -0,0 +1,608 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 JUUL Labs
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "swap_priv.h"
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_SWAP_USING_MOVE
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
|
||||||
|
/*
|
||||||
|
* FIXME: this might have to be updated for threaded sim
|
||||||
|
*/
|
||||||
|
int boot_status_fails = 0;
|
||||||
|
#define BOOT_STATUS_ASSERT(x) \
|
||||||
|
do { \
|
||||||
|
if (!(x)) { \
|
||||||
|
boot_status_fails++; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define BOOT_STATUS_ASSERT(x) ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
find_last_idx(struct boot_loader_state *state, uint32_t swap_size)
|
||||||
|
{
|
||||||
|
uint32_t sector_sz;
|
||||||
|
uint32_t sz;
|
||||||
|
uint32_t last_idx;
|
||||||
|
|
||||||
|
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
|
||||||
|
sz = 0;
|
||||||
|
last_idx = 0;
|
||||||
|
while (1) {
|
||||||
|
sz += sector_sz;
|
||||||
|
last_idx++;
|
||||||
|
if (sz >= swap_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return last_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_read_image_header(struct boot_loader_state *state, int slot,
|
||||||
|
struct image_header *out_hdr, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
uint32_t off;
|
||||||
|
uint32_t sz;
|
||||||
|
uint32_t last_idx;
|
||||||
|
uint32_t swap_size;
|
||||||
|
int area_id;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1)
|
||||||
|
(void)state;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
if (bs && !boot_status_is_reset(bs)) {
|
||||||
|
boot_find_status(BOOT_CURR_IMG(state), &fap);
|
||||||
|
if (fap == NULL || boot_read_swap_size(fap, &swap_size)) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
flash_area_close(fap);
|
||||||
|
|
||||||
|
last_idx = find_last_idx(state, swap_size);
|
||||||
|
sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the correct offset or slot where the image header is expected to
|
||||||
|
* be found for the steps where it is moved or swapped.
|
||||||
|
*/
|
||||||
|
if (bs->op == BOOT_STATUS_OP_MOVE && slot == 0 && bs->idx > last_idx) {
|
||||||
|
off = sz;
|
||||||
|
} else if (bs->op == BOOT_STATUS_OP_SWAP) {
|
||||||
|
if (bs->idx > 1 && bs->idx <= last_idx) {
|
||||||
|
slot = (slot == 0) ? 1 : 0;
|
||||||
|
} else if (bs->idx == 1) {
|
||||||
|
if (slot == 0) {
|
||||||
|
off = sz;
|
||||||
|
} else if (slot == 1 && bs->state == 2) {
|
||||||
|
slot = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
|
||||||
|
rc = flash_area_open(area_id, &fap);
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = flash_area_read(fap, off, out_hdr, sizeof *out_hdr);
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only know where the headers are located when bs is valid */
|
||||||
|
if (bs != NULL && out_hdr->ih_magic != IMAGE_MAGIC) {
|
||||||
|
rc = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
flash_area_close(fap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swap_read_status_bytes(const struct flash_area *fap,
|
||||||
|
struct boot_loader_state *state, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
uint8_t status;
|
||||||
|
int max_entries;
|
||||||
|
int found_idx;
|
||||||
|
uint8_t write_sz;
|
||||||
|
int move_entries;
|
||||||
|
int rc;
|
||||||
|
int last_rc;
|
||||||
|
int erased_sections;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
|
||||||
|
if (max_entries < 0) {
|
||||||
|
return BOOT_EBADARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
erased_sections = 0;
|
||||||
|
found_idx = -1;
|
||||||
|
/* skip erased sectors at the end */
|
||||||
|
last_rc = 1;
|
||||||
|
write_sz = BOOT_WRITE_SZ(state);
|
||||||
|
off = boot_status_off(fap);
|
||||||
|
for (i = max_entries; i > 0; i--) {
|
||||||
|
rc = flash_area_read(fap, off + (i - 1) * write_sz, &status, 1);
|
||||||
|
if (rc < 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootutil_buffer_is_erased(fap, &status, 1)) {
|
||||||
|
if (rc != last_rc) {
|
||||||
|
erased_sections++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (found_idx == -1) {
|
||||||
|
found_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_rc = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (erased_sections > 1) {
|
||||||
|
/* This means there was an error writing status on the last
|
||||||
|
* swap. Tell user and move on to validation!
|
||||||
|
*/
|
||||||
|
#if !defined(__BOOTSIM__)
|
||||||
|
BOOT_LOG_ERR("Detected inconsistent status!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
|
||||||
|
/* With validation of the primary slot disabled, there is no way
|
||||||
|
* to be sure the swapped primary slot is OK, so abort!
|
||||||
|
*/
|
||||||
|
assert(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
move_entries = BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT;
|
||||||
|
if (found_idx == -1) {
|
||||||
|
/* no swap status found; nothing to do */
|
||||||
|
} else if (found_idx < move_entries) {
|
||||||
|
bs->op = BOOT_STATUS_OP_MOVE;
|
||||||
|
bs->idx = (found_idx / BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_IDX_0;
|
||||||
|
bs->state = (found_idx % BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_STATE_0;;
|
||||||
|
} else {
|
||||||
|
bs->op = BOOT_STATUS_OP_SWAP;
|
||||||
|
bs->idx = ((found_idx - move_entries) / BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_IDX_0;
|
||||||
|
bs->state = ((found_idx - move_entries) % BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_STATE_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
boot_status_internal_off(const struct boot_status *bs, int elem_sz)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
int idx_sz;
|
||||||
|
|
||||||
|
idx_sz = elem_sz * ((bs->op == BOOT_STATUS_OP_MOVE) ?
|
||||||
|
BOOT_STATUS_MOVE_STATE_COUNT : BOOT_STATUS_SWAP_STATE_COUNT);
|
||||||
|
|
||||||
|
off = ((bs->op == BOOT_STATUS_OP_MOVE) ?
|
||||||
|
0 : (BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT * elem_sz)) +
|
||||||
|
(bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
|
||||||
|
(bs->state - BOOT_STATUS_STATE_0) * elem_sz;
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int app_max_sectors(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
uint32_t sz = 0;
|
||||||
|
uint32_t sector_sz;
|
||||||
|
uint32_t trailer_sz;
|
||||||
|
uint32_t first_trailer_idx;
|
||||||
|
|
||||||
|
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
|
||||||
|
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
|
||||||
|
first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
sz += sector_sz;
|
||||||
|
if (sz >= trailer_sz) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first_trailer_idx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return first_trailer_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_slots_compatible(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
#ifdef PM_S1_ADDRESS
|
||||||
|
/* Patch needed for NCS. In this case, image 1 primary points to the other
|
||||||
|
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
|
||||||
|
* With this configuration, image 0 and image 1 share the secondary slot.
|
||||||
|
* Hence, the primary slot of image 1 will be *smaller* than image 1's
|
||||||
|
* secondary slot. This is not allowed in upstream mcuboot, so we need
|
||||||
|
* this patch to allow it. Also, all of these checks are redundant when
|
||||||
|
* partition manager is in use, and since we have the same sector size
|
||||||
|
* in all of our flash.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
size_t num_sectors_pri;
|
||||||
|
size_t num_sectors_sec;
|
||||||
|
size_t sector_sz_pri = 0;
|
||||||
|
size_t sector_sz_sec = 0;
|
||||||
|
size_t i;
|
||||||
|
size_t num_usable_sectors_pri;
|
||||||
|
|
||||||
|
num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
|
||||||
|
num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
|
||||||
|
num_usable_sectors_pri = app_max_sectors(state);
|
||||||
|
|
||||||
|
if ((num_sectors_pri != num_sectors_sec) &&
|
||||||
|
(num_sectors_pri != (num_sectors_sec + 1)) &&
|
||||||
|
(num_usable_sectors_pri != (num_sectors_sec + 1))) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors");
|
||||||
|
BOOT_LOG_DBG("slot0 sectors: %d, slot1 sectors: %d, usable slot0 sectors: %d",
|
||||||
|
(int)num_sectors_pri, (int)num_sectors_sec,
|
||||||
|
(int)(num_usable_sectors_pri - 1));
|
||||||
|
return 0;
|
||||||
|
} else if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_usable_sectors_pri != (num_sectors_sec + 1)) {
|
||||||
|
BOOT_LOG_DBG("Non-optimal sector distribution, slot0 has %d usable sectors (%d assigned) "
|
||||||
|
"but slot1 has %d assigned", (int)(num_usable_sectors_pri - 1),
|
||||||
|
(int)num_sectors_pri, (int)num_sectors_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_sectors_sec; i++) {
|
||||||
|
sector_sz_pri = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
|
||||||
|
sector_sz_sec = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i);
|
||||||
|
if (sector_sz_pri != sector_sz_sec) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_sectors_pri > num_sectors_sec) {
|
||||||
|
if (sector_sz_pri != boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i)) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
#endif /* PM_S1_ADDRESS */
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOOT_LOG_SWAP_STATE(area, state) \
|
||||||
|
BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
|
||||||
|
"image_ok=0x%x", \
|
||||||
|
(area), \
|
||||||
|
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
|
||||||
|
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
|
||||||
|
"bad"), \
|
||||||
|
(state)->swap_type, \
|
||||||
|
(state)->copy_done, \
|
||||||
|
(state)->image_ok)
|
||||||
|
|
||||||
|
int
|
||||||
|
swap_status_source(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
struct boot_swap_state state_primary_slot;
|
||||||
|
struct boot_swap_state state_secondary_slot;
|
||||||
|
int rc;
|
||||||
|
uint8_t source;
|
||||||
|
uint8_t image_index;
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1)
|
||||||
|
(void)state;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
&state_primary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
|
||||||
|
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
|
||||||
|
&state_secondary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
BOOT_LOG_SWAP_STATE("Secondary image", &state_secondary_slot);
|
||||||
|
|
||||||
|
if (state_primary_slot.magic == BOOT_MAGIC_GOOD &&
|
||||||
|
state_primary_slot.copy_done == BOOT_FLAG_UNSET &&
|
||||||
|
state_secondary_slot.magic != BOOT_MAGIC_GOOD) {
|
||||||
|
|
||||||
|
source = BOOT_STATUS_SOURCE_PRIMARY_SLOT;
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Boot source: primary slot");
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Boot source: none");
|
||||||
|
return BOOT_STATUS_SOURCE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Moves" the sector located at idx - 1 to idx.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
|
||||||
|
struct boot_status *bs, const struct flash_area *fap_pri,
|
||||||
|
const struct flash_area *fap_sec)
|
||||||
|
{
|
||||||
|
uint32_t new_off;
|
||||||
|
uint32_t old_off;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: assuming sectors of size == sz, a single off variable
|
||||||
|
* would be enough
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Calculate offset from start of image area. */
|
||||||
|
new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
|
||||||
|
old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
|
||||||
|
|
||||||
|
if (bs->idx == BOOT_STATUS_IDX_0) {
|
||||||
|
if (bs->source != BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
|
||||||
|
rc = swap_erase_trailer_sectors(state, fap_pri);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = swap_status_init(state, fap_pri, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = swap_erase_trailer_sectors(state, fap_sec);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_erase_region(fap_pri, new_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_status(state, bs);
|
||||||
|
|
||||||
|
bs->idx++;
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
|
||||||
|
struct boot_status *bs, const struct flash_area *fap_pri,
|
||||||
|
const struct flash_area *fap_sec)
|
||||||
|
{
|
||||||
|
uint32_t pri_off;
|
||||||
|
uint32_t pri_up_off;
|
||||||
|
uint32_t sec_off;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pri_up_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
|
||||||
|
pri_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
|
||||||
|
sec_off = boot_img_sector_off(state, BOOT_SECONDARY_SLOT, idx - 1);
|
||||||
|
|
||||||
|
if (bs->state == BOOT_STATUS_STATE_0) {
|
||||||
|
rc = boot_erase_region(fap_pri, pri_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_copy_region(state, fap_sec, fap_pri, sec_off, pri_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_status(state, bs);
|
||||||
|
bs->state = BOOT_STATUS_STATE_1;
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->state == BOOT_STATUS_STATE_1) {
|
||||||
|
rc = boot_erase_region(fap_sec, sec_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_status(state, bs);
|
||||||
|
bs->idx++;
|
||||||
|
bs->state = BOOT_STATUS_STATE_0;
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When starting a revert the swap status exists in the primary slot, and
|
||||||
|
* the status in the secondary slot is erased. To start the swap, the status
|
||||||
|
* area in the primary slot must be re-initialized; if during the small
|
||||||
|
* window of time between re-initializing it and writing the first metadata
|
||||||
|
* a reset happens, the swap process is broken and cannot be resumed.
|
||||||
|
*
|
||||||
|
* This function handles the issue by making the revert look like a permanent
|
||||||
|
* upgrade (by initializing the secondary slot).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fixup_revert(const struct boot_loader_state *state, struct boot_status *bs,
|
||||||
|
const struct flash_area *fap_sec)
|
||||||
|
{
|
||||||
|
struct boot_swap_state swap_state;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1)
|
||||||
|
(void)state;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* No fixup required */
|
||||||
|
if (bs->swap_type != BOOT_SWAP_TYPE_REVERT ||
|
||||||
|
bs->op != BOOT_STATUS_OP_MOVE ||
|
||||||
|
bs->idx != BOOT_STATUS_IDX_0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(fap_sec, &swap_state);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
BOOT_LOG_SWAP_STATE("Secondary image", &swap_state);
|
||||||
|
|
||||||
|
if (swap_state.magic == BOOT_MAGIC_UNSET) {
|
||||||
|
rc = swap_erase_trailer_sectors(state, fap_sec);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_image_ok(fap_sec);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_swap_size(fap_sec, bs->swap_size);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_magic(fap_sec);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
swap_run(struct boot_loader_state *state, struct boot_status *bs,
|
||||||
|
uint32_t copy_size)
|
||||||
|
{
|
||||||
|
uint32_t sz;
|
||||||
|
uint32_t sector_sz;
|
||||||
|
uint32_t idx;
|
||||||
|
uint32_t trailer_sz;
|
||||||
|
uint32_t first_trailer_idx;
|
||||||
|
uint32_t last_idx;
|
||||||
|
uint8_t image_index;
|
||||||
|
const struct flash_area *fap_pri;
|
||||||
|
const struct flash_area *fap_sec;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Starting swap using move algorithm.");
|
||||||
|
|
||||||
|
last_idx = find_last_idx(state, copy_size);
|
||||||
|
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When starting a new swap upgrade, check that there is enough space.
|
||||||
|
*/
|
||||||
|
if (boot_status_is_reset(bs)) {
|
||||||
|
sz = 0;
|
||||||
|
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
|
||||||
|
first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
sz += sector_sz;
|
||||||
|
if (sz >= trailer_sz) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first_trailer_idx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_idx >= first_trailer_idx) {
|
||||||
|
BOOT_LOG_WRN("Not enough free space to run swap upgrade");
|
||||||
|
BOOT_LOG_WRN("required %d bytes but only %d are available",
|
||||||
|
(last_idx + 1) * sector_sz,
|
||||||
|
first_trailer_idx * sector_sz);
|
||||||
|
bs->swap_type = BOOT_SWAP_TYPE_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_pri);
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
fixup_revert(state, bs, fap_sec);
|
||||||
|
|
||||||
|
if (bs->op == BOOT_STATUS_OP_MOVE) {
|
||||||
|
idx = last_idx;
|
||||||
|
while (idx > 0) {
|
||||||
|
if (idx <= (last_idx - bs->idx + 1)) {
|
||||||
|
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
|
||||||
|
}
|
||||||
|
idx--;
|
||||||
|
}
|
||||||
|
bs->idx = BOOT_STATUS_IDX_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs->op = BOOT_STATUS_OP_SWAP;
|
||||||
|
|
||||||
|
idx = 1;
|
||||||
|
while (idx <= last_idx) {
|
||||||
|
if (idx >= bs->idx) {
|
||||||
|
boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_area_close(fap_pri);
|
||||||
|
flash_area_close(fap_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int app_max_size(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
uint32_t sector_sz_primary;
|
||||||
|
uint32_t sector_sz_secondary;
|
||||||
|
uint32_t sz_primary;
|
||||||
|
uint32_t sz_secondary;
|
||||||
|
|
||||||
|
sector_sz_primary = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
|
||||||
|
sector_sz_secondary = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0);
|
||||||
|
|
||||||
|
/* Account for image flags and move sector */
|
||||||
|
sz_primary = app_max_sectors(state) * sector_sz_primary - sector_sz_primary;
|
||||||
|
sz_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) * sector_sz_secondary;
|
||||||
|
|
||||||
|
return (sz_primary <= sz_secondary ? sz_primary : sz_secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
70
bootloader/mcuboot/boot/bootutil/src/swap_nsib.c
Normal file
70
bootloader/mcuboot/boot/bootutil/src/swap_nsib.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "swap_priv.h"
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
|
||||||
|
void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
uint32_t sector_sz;
|
||||||
|
uint8_t image_index;
|
||||||
|
const struct flash_area *fap_pri;
|
||||||
|
const struct flash_area *fap_sec;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Starting swap using nsib algorithm.");
|
||||||
|
|
||||||
|
sector_sz = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0);
|
||||||
|
|
||||||
|
#if (CONFIG_NCS_IS_VARIANT_IMAGE)
|
||||||
|
rc = flash_area_open(PM_S0_ID, &fap_pri);
|
||||||
|
#else
|
||||||
|
rc = flash_area_open(PM_S1_ID, &fap_pri);
|
||||||
|
#endif
|
||||||
|
assert (rc == 0);
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
rc = boot_erase_region(fap_pri, 0, fap_pri->fa_size);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_copy_region(state, fap_sec, fap_pri, 0, 0, fap_pri->fa_size);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = swap_erase_trailer_sectors(state, fap_sec);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_erase_region(fap_sec, 0, MIN((fap_pri->fa_size + sector_sz), fap_sec->fa_size));
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
flash_area_close(fap_pri);
|
||||||
|
flash_area_close(fap_sec);
|
||||||
|
}
|
||||||
117
bootloader/mcuboot/boot/bootutil/src/swap_priv.h
Normal file
117
bootloader/mcuboot/boot/bootutil/src/swap_priv.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 JUUL Labs
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_SWAP_PRIV_
|
||||||
|
#define H_SWAP_PRIV_
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the amount of space required to store the trailer, and erases
|
||||||
|
* all sectors required for this storage in the given flash_area.
|
||||||
|
*/
|
||||||
|
int swap_erase_trailer_sectors(const struct boot_loader_state *state,
|
||||||
|
const struct flash_area *fap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the given flash_area with the metadata required to start a new
|
||||||
|
* swap upgrade.
|
||||||
|
*/
|
||||||
|
int swap_status_init(const struct boot_loader_state *state,
|
||||||
|
const struct flash_area *fap,
|
||||||
|
const struct boot_status *bs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to locate an interrupted swap status (metadata). If not metadata
|
||||||
|
* was found returns BOOT_STATUS_SOURCE_NONE.
|
||||||
|
*
|
||||||
|
* Must return one of:
|
||||||
|
* - BOOT_STATUS_SOURCE_NONE
|
||||||
|
* - BOOT_STATUS_SOURCE_SCRATCH
|
||||||
|
* - BOOT_STATUS_SOURCE_PRIMARY_SLOT
|
||||||
|
*/
|
||||||
|
int swap_status_source(struct boot_loader_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the boot status from the flash. The boot status contains
|
||||||
|
* the current state of an interrupted image copy operation. If the boot
|
||||||
|
* status is not present, or it indicates that previous copy finished,
|
||||||
|
* there is no operation in progress.
|
||||||
|
*/
|
||||||
|
int swap_read_status(struct boot_loader_state *state, struct boot_status *bs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over the swap status bytes in the given flash_area and populate
|
||||||
|
* the given boot_status with the calculated index where a swap upgrade was
|
||||||
|
* interrupted.
|
||||||
|
*/
|
||||||
|
int swap_read_status_bytes(const struct flash_area *fap,
|
||||||
|
struct boot_loader_state *state,
|
||||||
|
struct boot_status *bs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the image in the primary slot as fully copied.
|
||||||
|
*/
|
||||||
|
int swap_set_copy_done(uint8_t image_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a reverted image in the primary slot as confirmed. This is necessary to
|
||||||
|
* ensure the status bytes from the image revert operation don't get processed
|
||||||
|
* on a subsequent boot.
|
||||||
|
*
|
||||||
|
* NOTE: image_ok is tested before writing because if there's a valid permanent
|
||||||
|
* image installed on the primary slot and the new image to be upgrade to has a
|
||||||
|
* bad sig, image_ok would be overwritten.
|
||||||
|
*/
|
||||||
|
int swap_set_image_ok(uint8_t image_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new or resume an interrupted swap according to the parameters
|
||||||
|
* found in the given boot_status.
|
||||||
|
*/
|
||||||
|
void swap_run(struct boot_loader_state *state,
|
||||||
|
struct boot_status *bs,
|
||||||
|
uint32_t copy_size);
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
#define BOOT_SCRATCH_AREA(state) ((state)->scratch.area)
|
||||||
|
|
||||||
|
static inline size_t boot_scratch_area_size(const struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
return flash_area_get_size(BOOT_SCRATCH_AREA(state));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum size of an application that can be loaded to a slot.
|
||||||
|
*/
|
||||||
|
int app_max_size(struct boot_loader_state *state);
|
||||||
|
|
||||||
|
#if defined(PM_S1_ADDRESS) && !defined(MCUBOOT_OVERWRITE_ONLY) && \
|
||||||
|
(CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED))
|
||||||
|
/**
|
||||||
|
* Performs an NSIB update
|
||||||
|
*/
|
||||||
|
void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* H_SWAP_PRIV_ */
|
||||||
992
bootloader/mcuboot/boot/bootutil/src/swap_scratch.c
Normal file
992
bootloader/mcuboot/boot/bootutil/src/swap_scratch.c
Normal file
@@ -0,0 +1,992 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 JUUL Labs
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
#include "swap_priv.h"
|
||||||
|
#include "bootutil/bootutil_log.h"
|
||||||
|
|
||||||
|
#include "mcuboot_config/mcuboot_config.h"
|
||||||
|
|
||||||
|
BOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_SWAP_USING_MOVE)
|
||||||
|
|
||||||
|
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
|
||||||
|
/*
|
||||||
|
* FIXME: this might have to be updated for threaded sim
|
||||||
|
*/
|
||||||
|
int boot_status_fails = 0;
|
||||||
|
#define BOOT_STATUS_ASSERT(x) \
|
||||||
|
do { \
|
||||||
|
if (!(x)) { \
|
||||||
|
boot_status_fails++; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define BOOT_STATUS_ASSERT(x) ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
|
||||||
|
/**
|
||||||
|
* Reads the status of a partially-completed swap, if any. This is necessary
|
||||||
|
* to recover in case the boot lodaer was reset in the middle of a swap
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
swap_read_status_bytes(const struct flash_area *fap,
|
||||||
|
struct boot_loader_state *state, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
uint32_t off;
|
||||||
|
uint8_t status;
|
||||||
|
int max_entries;
|
||||||
|
int found;
|
||||||
|
int found_idx;
|
||||||
|
int invalid;
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
off = boot_status_off(fap);
|
||||||
|
max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
|
||||||
|
if (max_entries < 0) {
|
||||||
|
return BOOT_EBADARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
found_idx = 0;
|
||||||
|
invalid = 0;
|
||||||
|
for (i = 0; i < max_entries; i++) {
|
||||||
|
rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(state),
|
||||||
|
&status, 1);
|
||||||
|
if (rc < 0) {
|
||||||
|
return BOOT_EFLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootutil_buffer_is_erased(fap, &status, 1)) {
|
||||||
|
if (found && !found_idx) {
|
||||||
|
found_idx = i;
|
||||||
|
}
|
||||||
|
} else if (!found) {
|
||||||
|
found = 1;
|
||||||
|
} else if (found_idx) {
|
||||||
|
invalid = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid) {
|
||||||
|
/* This means there was an error writing status on the last
|
||||||
|
* swap. Tell user and move on to validation!
|
||||||
|
*/
|
||||||
|
#if !defined(__BOOTSIM__)
|
||||||
|
BOOT_LOG_ERR("Detected inconsistent status!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
|
||||||
|
/* With validation of the primary slot disabled, there is no way
|
||||||
|
* to be sure the swapped primary slot is OK, so abort!
|
||||||
|
*/
|
||||||
|
assert(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
if (!found_idx) {
|
||||||
|
found_idx = i;
|
||||||
|
}
|
||||||
|
bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
|
||||||
|
bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
boot_status_internal_off(const struct boot_status *bs, int elem_sz)
|
||||||
|
{
|
||||||
|
int idx_sz;
|
||||||
|
|
||||||
|
idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
|
||||||
|
|
||||||
|
return (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
|
||||||
|
(bs->state - BOOT_STATUS_STATE_0) * elem_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slots are compatible when all sectors that store up to to size of the image
|
||||||
|
* round up to sector size, in both slot's are able to fit in the scratch
|
||||||
|
* area, and have sizes that are a multiple of each other (powers of two
|
||||||
|
* presumably!).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
boot_slots_compatible(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
#ifdef PM_S1_ADDRESS
|
||||||
|
/* Patch needed for NCS. In this case, image 1 primary points to the other
|
||||||
|
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
|
||||||
|
* With this configuration, image 0 and image 1 share the secondary slot.
|
||||||
|
* Hence, the primary slot of image 1 will be *smaller* than image 1's
|
||||||
|
* secondary slot. This is not allowed in upstream mcuboot, so we need
|
||||||
|
* this patch to allow it. Also, all of these checks are redundant when
|
||||||
|
* partition manager is in use, and since we have the same sector size
|
||||||
|
* in all of our flash.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
size_t num_sectors_primary;
|
||||||
|
size_t num_sectors_secondary;
|
||||||
|
size_t sz0, sz1;
|
||||||
|
size_t primary_slot_sz, secondary_slot_sz;
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
size_t scratch_sz;
|
||||||
|
#endif
|
||||||
|
size_t i, j;
|
||||||
|
int8_t smaller;
|
||||||
|
|
||||||
|
num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
|
||||||
|
num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
|
||||||
|
if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
|
||||||
|
(num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
scratch_sz = boot_scratch_area_size(state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following loop scans all sectors in a linear fashion, assuring that
|
||||||
|
* for each possible sector in each slot, it is able to fit in the other
|
||||||
|
* slot's sector or sectors. Slot's should be compatible as long as any
|
||||||
|
* number of a slot's sectors are able to fit into another, which only
|
||||||
|
* excludes cases where sector sizes are not a multiple of each other.
|
||||||
|
*/
|
||||||
|
i = sz0 = primary_slot_sz = 0;
|
||||||
|
j = sz1 = secondary_slot_sz = 0;
|
||||||
|
smaller = 0;
|
||||||
|
while (i < num_sectors_primary || j < num_sectors_secondary) {
|
||||||
|
if (sz0 == sz1) {
|
||||||
|
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
|
||||||
|
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
} else if (sz0 < sz1) {
|
||||||
|
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
|
||||||
|
/* Guarantee that multiple sectors of the secondary slot
|
||||||
|
* fit into the primary slot.
|
||||||
|
*/
|
||||||
|
if (smaller == 2) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smaller = 1;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
size_t sector_size = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_DECOMPRESS_IMAGES
|
||||||
|
if (sector_size == 0) {
|
||||||
|
/* Since this supports decompressed images, we can safely exit if slot1 is
|
||||||
|
* smaller than slot0.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
sz1 += sector_size;
|
||||||
|
/* Guarantee that multiple sectors of the primary slot
|
||||||
|
* fit into the secondary slot.
|
||||||
|
*/
|
||||||
|
if (smaller == 1) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smaller = 2;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
if (sz0 == sz1) {
|
||||||
|
primary_slot_sz += sz0;
|
||||||
|
secondary_slot_sz += sz1;
|
||||||
|
/* Scratch has to fit each swap operation to the size of the larger
|
||||||
|
* sector among the primary slot and the secondary slot.
|
||||||
|
*/
|
||||||
|
if (sz0 > scratch_sz || sz1 > scratch_sz) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smaller = sz0 = sz1 = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_DECOMPRESS_IMAGES
|
||||||
|
if ((i != num_sectors_primary) ||
|
||||||
|
(j != num_sectors_secondary) ||
|
||||||
|
(primary_slot_sz != secondary_slot_sz)) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
#endif /* PM_S1_ADDRESS */
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOOT_LOG_SWAP_STATE(area, state) \
|
||||||
|
BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
|
||||||
|
"image_ok=0x%x", \
|
||||||
|
(area), \
|
||||||
|
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
|
||||||
|
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
|
||||||
|
"bad"), \
|
||||||
|
(state)->swap_type, \
|
||||||
|
(state)->copy_done, \
|
||||||
|
(state)->image_ok)
|
||||||
|
|
||||||
|
struct boot_status_table {
|
||||||
|
uint8_t bst_magic_primary_slot;
|
||||||
|
uint8_t bst_magic_scratch;
|
||||||
|
uint8_t bst_copy_done_primary_slot;
|
||||||
|
uint8_t bst_status_source;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This set of tables maps swap state contents to boot status location.
|
||||||
|
* When searching for a match, these tables must be iterated in order.
|
||||||
|
*/
|
||||||
|
static const struct boot_status_table boot_status_tables[] = {
|
||||||
|
{
|
||||||
|
/* | primary slot | scratch |
|
||||||
|
* ----------+--------------+--------------|
|
||||||
|
* magic | Good | Any |
|
||||||
|
* copy-done | Set | N/A |
|
||||||
|
* ----------+--------------+--------------'
|
||||||
|
* source: none |
|
||||||
|
* ----------------------------------------'
|
||||||
|
*/
|
||||||
|
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
|
||||||
|
.bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
|
||||||
|
.bst_copy_done_primary_slot = BOOT_FLAG_SET,
|
||||||
|
.bst_status_source = BOOT_STATUS_SOURCE_NONE,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
/* | primary slot | scratch |
|
||||||
|
* ----------+--------------+--------------|
|
||||||
|
* magic | Good | Any |
|
||||||
|
* copy-done | Unset | N/A |
|
||||||
|
* ----------+--------------+--------------'
|
||||||
|
* source: primary slot |
|
||||||
|
* ----------------------------------------'
|
||||||
|
*/
|
||||||
|
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
|
||||||
|
.bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
|
||||||
|
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
|
||||||
|
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
/* | primary slot | scratch |
|
||||||
|
* ----------+--------------+--------------|
|
||||||
|
* magic | Any | Good |
|
||||||
|
* copy-done | Any | N/A |
|
||||||
|
* ----------+--------------+--------------'
|
||||||
|
* source: scratch |
|
||||||
|
* ----------------------------------------'
|
||||||
|
*/
|
||||||
|
.bst_magic_primary_slot = BOOT_MAGIC_ANY,
|
||||||
|
.bst_magic_scratch = BOOT_MAGIC_GOOD,
|
||||||
|
.bst_copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||||
|
.bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* | primary slot | scratch |
|
||||||
|
* ----------+--------------+--------------|
|
||||||
|
* magic | Unset | Any |
|
||||||
|
* copy-done | Unset | N/A |
|
||||||
|
* ----------+--------------+--------------|
|
||||||
|
* source: varies |
|
||||||
|
* ----------------------------------------+--------------------------+
|
||||||
|
* This represents one of two cases: |
|
||||||
|
* o No swaps ever (no status to read, so no harm in checking). |
|
||||||
|
* o Mid-revert; status in primary slot. |
|
||||||
|
* -------------------------------------------------------------------'
|
||||||
|
*/
|
||||||
|
.bst_magic_primary_slot = BOOT_MAGIC_UNSET,
|
||||||
|
.bst_magic_scratch = BOOT_MAGIC_ANY,
|
||||||
|
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
|
||||||
|
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BOOT_STATUS_TABLES_COUNT \
|
||||||
|
(sizeof boot_status_tables / sizeof boot_status_tables[0])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines where in flash the most recent boot status is stored. The boot
|
||||||
|
* status is necessary for completing a swap that was interrupted by a boot
|
||||||
|
* loader reset.
|
||||||
|
*
|
||||||
|
* @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
|
||||||
|
* be read from.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
swap_status_source(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
const struct boot_status_table *table;
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
struct boot_swap_state state_scratch;
|
||||||
|
#endif
|
||||||
|
struct boot_swap_state state_primary_slot;
|
||||||
|
int rc;
|
||||||
|
size_t i;
|
||||||
|
uint8_t source;
|
||||||
|
uint8_t image_index;
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1)
|
||||||
|
(void)state;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
&state_primary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
|
||||||
|
assert(rc == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
|
||||||
|
#endif
|
||||||
|
for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
|
||||||
|
table = &boot_status_tables[i];
|
||||||
|
|
||||||
|
if (boot_magic_compatible_check(table->bst_magic_primary_slot,
|
||||||
|
state_primary_slot.magic) &&
|
||||||
|
#if MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
boot_magic_compatible_check(table->bst_magic_scratch,
|
||||||
|
state_scratch.magic) &&
|
||||||
|
#endif
|
||||||
|
(table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
|
||||||
|
table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
|
||||||
|
{
|
||||||
|
source = table->bst_status_source;
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER > 1) && MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
/* In case of multi-image boot it can happen that if boot status
|
||||||
|
* info is found on scratch area then it does not belong to the
|
||||||
|
* currently examined image.
|
||||||
|
*/
|
||||||
|
if (source == BOOT_STATUS_SOURCE_SCRATCH &&
|
||||||
|
state_scratch.image_num != BOOT_CURR_IMG(state)) {
|
||||||
|
source = BOOT_STATUS_SOURCE_NONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Boot source: %s",
|
||||||
|
source == BOOT_STATUS_SOURCE_NONE ? "none" :
|
||||||
|
source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
|
||||||
|
source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
|
||||||
|
"primary slot" : "BUG; can't happen");
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Boot source: none");
|
||||||
|
return BOOT_STATUS_SOURCE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
/**
|
||||||
|
* Calculates the number of sectors the scratch area can contain. A "last"
|
||||||
|
* source sector is specified because images are copied backwards in flash
|
||||||
|
* (final index to index number 0).
|
||||||
|
*
|
||||||
|
* @param last_sector_idx The index of the last source sector
|
||||||
|
* (inclusive).
|
||||||
|
* @param out_first_sector_idx The index of the first source sector
|
||||||
|
* (inclusive) gets written here.
|
||||||
|
*
|
||||||
|
* @return The number of bytes comprised by the
|
||||||
|
* [first-sector, last-sector] range.
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
boot_copy_sz(const struct boot_loader_state *state, int last_sector_idx,
|
||||||
|
int *out_first_sector_idx)
|
||||||
|
{
|
||||||
|
size_t scratch_sz;
|
||||||
|
uint32_t new_sz;
|
||||||
|
uint32_t sz;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sz = 0;
|
||||||
|
|
||||||
|
scratch_sz = boot_scratch_area_size(state);
|
||||||
|
for (i = last_sector_idx; i >= 0; i--) {
|
||||||
|
new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
|
||||||
|
/*
|
||||||
|
* The secondary slot is not being checked here, because
|
||||||
|
* `boot_slots_compatible` already provides assurance that the copy size
|
||||||
|
* will be compatible with the primary slot and scratch.
|
||||||
|
*/
|
||||||
|
if (new_sz > scratch_sz) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sz = new_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* i currently refers to a sector that doesn't fit or it is -1 because all
|
||||||
|
* sectors have been processed. In both cases, exclude sector i.
|
||||||
|
*/
|
||||||
|
*out_first_sector_idx = i + 1;
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index of the last sector in the primary slot that needs swapping.
|
||||||
|
*
|
||||||
|
* @param state Current bootloader's state.
|
||||||
|
* @param copy_size Total number of bytes to swap.
|
||||||
|
*
|
||||||
|
* @return Index of the last sector in the primary slot that needs swapping.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
find_last_sector_idx(const struct boot_loader_state *state, uint32_t copy_size)
|
||||||
|
{
|
||||||
|
int last_sector_idx;
|
||||||
|
uint32_t primary_slot_size;
|
||||||
|
uint32_t secondary_slot_size;
|
||||||
|
|
||||||
|
primary_slot_size = 0;
|
||||||
|
secondary_slot_size = 0;
|
||||||
|
last_sector_idx = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Knowing the size of the largest image between both slots, here we
|
||||||
|
* find what is the last sector in the primary slot that needs swapping.
|
||||||
|
* Since we already know that both slots are compatible, the secondary
|
||||||
|
* slot's last sector is not really required after this check is finished.
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
if ((primary_slot_size < copy_size) ||
|
||||||
|
(primary_slot_size < secondary_slot_size)) {
|
||||||
|
primary_slot_size += boot_img_sector_size(state,
|
||||||
|
BOOT_PRIMARY_SLOT,
|
||||||
|
last_sector_idx);
|
||||||
|
}
|
||||||
|
if ((secondary_slot_size < copy_size) ||
|
||||||
|
(secondary_slot_size < primary_slot_size)) {
|
||||||
|
secondary_slot_size += boot_img_sector_size(state,
|
||||||
|
BOOT_SECONDARY_SLOT,
|
||||||
|
last_sector_idx);
|
||||||
|
}
|
||||||
|
if (primary_slot_size >= copy_size &&
|
||||||
|
secondary_slot_size >= copy_size &&
|
||||||
|
primary_slot_size == secondary_slot_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_sector_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return last_sector_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the number of swap operations that have to be performed to swap the two images.
|
||||||
|
*
|
||||||
|
* @param state Current bootloader's state.
|
||||||
|
* @param copy_size Total number of bytes to swap.
|
||||||
|
*
|
||||||
|
* @return The number of swap operations that have to be performed.
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
find_swap_count(const struct boot_loader_state *state, uint32_t copy_size)
|
||||||
|
{
|
||||||
|
int first_sector_idx;
|
||||||
|
int last_sector_idx;
|
||||||
|
uint32_t swap_count;
|
||||||
|
|
||||||
|
last_sector_idx = find_last_sector_idx(state, copy_size);
|
||||||
|
|
||||||
|
swap_count = 0;
|
||||||
|
|
||||||
|
while (last_sector_idx >= 0) {
|
||||||
|
boot_copy_sz(state, last_sector_idx, &first_sector_idx);
|
||||||
|
|
||||||
|
last_sector_idx = first_sector_idx - 1;
|
||||||
|
swap_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return swap_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the contents of two flash regions within the two image slots.
|
||||||
|
*
|
||||||
|
* @param idx The index of the first sector in the range of
|
||||||
|
* sectors being swapped.
|
||||||
|
* @param sz The number of bytes to swap.
|
||||||
|
* @param bs The current boot status. This struct gets
|
||||||
|
* updated according to the outcome.
|
||||||
|
*
|
||||||
|
* @return 0 on success; nonzero on failure.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
|
||||||
|
struct boot_status *bs)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap_primary_slot;
|
||||||
|
const struct flash_area *fap_secondary_slot;
|
||||||
|
const struct flash_area *fap_scratch;
|
||||||
|
uint32_t copy_sz;
|
||||||
|
uint32_t trailer_sz;
|
||||||
|
uint32_t sector_sz;
|
||||||
|
uint32_t img_off;
|
||||||
|
uint32_t scratch_trailer_off;
|
||||||
|
struct boot_swap_state swap_state;
|
||||||
|
size_t last_sector;
|
||||||
|
bool erase_scratch;
|
||||||
|
uint8_t image_index;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Calculate offset from start of image area. */
|
||||||
|
img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
|
||||||
|
|
||||||
|
copy_sz = sz;
|
||||||
|
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
|
||||||
|
|
||||||
|
/* sz in this function is always sized on a multiple of the sector size.
|
||||||
|
* The check against the start offset of the last sector
|
||||||
|
* is to determine if we're swapping the last sector. The last sector
|
||||||
|
* needs special handling because it's where the trailer lives. If we're
|
||||||
|
* copying it, we need to use scratch to write the trailer temporarily.
|
||||||
|
*
|
||||||
|
* NOTE: `use_scratch` is a temporary flag (never written to flash) which
|
||||||
|
* controls if special handling is needed (swapping last sector).
|
||||||
|
*/
|
||||||
|
last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
|
||||||
|
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, last_sector);
|
||||||
|
|
||||||
|
if (sector_sz < trailer_sz) {
|
||||||
|
uint32_t trailer_sector_sz = sector_sz;
|
||||||
|
|
||||||
|
while (trailer_sector_sz < trailer_sz) {
|
||||||
|
/* Consider that the image trailer may span across sectors of
|
||||||
|
* different sizes.
|
||||||
|
*/
|
||||||
|
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, --last_sector);
|
||||||
|
|
||||||
|
trailer_sector_sz += sector_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((img_off + sz) >
|
||||||
|
boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
|
||||||
|
copy_sz -= trailer_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
|
||||||
|
|
||||||
|
image_index = BOOT_CURR_IMG(state);
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||||
|
&fap_primary_slot);
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
|
||||||
|
&fap_secondary_slot);
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
if (bs->state == BOOT_STATUS_STATE_0) {
|
||||||
|
BOOT_LOG_DBG("erasing scratch area");
|
||||||
|
rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch));
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if (bs->idx == BOOT_STATUS_IDX_0) {
|
||||||
|
/* Write a trailer to the scratch area, even if we don't need the
|
||||||
|
* scratch area for status. We need a temporary place to store the
|
||||||
|
* `swap-type` while we erase the primary trailer.
|
||||||
|
*/
|
||||||
|
rc = swap_status_init(state, fap_scratch, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if (!bs->use_scratch) {
|
||||||
|
/* Prepare the primary status area... here it is known that the
|
||||||
|
* last sector is not being used by the image data so it's safe
|
||||||
|
* to erase.
|
||||||
|
*/
|
||||||
|
rc = swap_erase_trailer_sectors(state, fap_primary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = swap_status_init(state, fap_primary_slot, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
/* Erase the temporary trailer from the scratch area. */
|
||||||
|
rc = boot_erase_region(fap_scratch, 0,
|
||||||
|
flash_area_get_size(fap_scratch));
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
|
||||||
|
img_off, 0, copy_sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_status(state, bs);
|
||||||
|
bs->state = BOOT_STATUS_STATE_1;
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->state == BOOT_STATUS_STATE_1) {
|
||||||
|
rc = boot_erase_region(fap_secondary_slot, img_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
|
||||||
|
img_off, img_off, copy_sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
|
||||||
|
/* If not all sectors of the slot are being swapped,
|
||||||
|
* guarantee here that only the primary slot will have the state.
|
||||||
|
*/
|
||||||
|
rc = swap_erase_trailer_sectors(state, fap_secondary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_write_status(state, bs);
|
||||||
|
bs->state = BOOT_STATUS_STATE_2;
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->state == BOOT_STATUS_STATE_2) {
|
||||||
|
rc = boot_erase_region(fap_primary_slot, img_off, sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
/* NOTE: If this is the final sector, we exclude the image trailer from
|
||||||
|
* this copy (copy_sz was truncated earlier).
|
||||||
|
*/
|
||||||
|
rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
|
||||||
|
0, img_off, copy_sz);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if (bs->use_scratch) {
|
||||||
|
scratch_trailer_off = boot_status_off(fap_scratch);
|
||||||
|
|
||||||
|
/* copy current status that is being maintained in scratch */
|
||||||
|
rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
|
||||||
|
scratch_trailer_off, img_off + copy_sz,
|
||||||
|
(BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(fap_scratch, &swap_state);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
if (swap_state.image_ok == BOOT_FLAG_SET) {
|
||||||
|
rc = boot_write_image_ok(fap_primary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
|
||||||
|
rc = boot_write_swap_info(fap_primary_slot,
|
||||||
|
swap_state.swap_type, image_index);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_ENC_IMAGES
|
||||||
|
rc = boot_write_enc_key(fap_primary_slot, 0, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
rc = boot_write_enc_key(fap_primary_slot, 1, bs);
|
||||||
|
assert(rc == 0);
|
||||||
|
#endif
|
||||||
|
rc = boot_write_magic(fap_primary_slot);
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we wrote a trailer to the scratch area, erase it after we persist
|
||||||
|
* a trailer to the primary slot. We do this to prevent mcuboot from
|
||||||
|
* reading a stale status from the scratch area in case of immediate
|
||||||
|
* reset.
|
||||||
|
*/
|
||||||
|
erase_scratch = bs->use_scratch;
|
||||||
|
bs->use_scratch = 0;
|
||||||
|
|
||||||
|
rc = boot_write_status(state, bs);
|
||||||
|
bs->idx++;
|
||||||
|
bs->state = BOOT_STATUS_STATE_0;
|
||||||
|
BOOT_STATUS_ASSERT(rc == 0);
|
||||||
|
|
||||||
|
if (erase_scratch) {
|
||||||
|
rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch));
|
||||||
|
assert(rc == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_area_close(fap_primary_slot);
|
||||||
|
flash_area_close(fap_secondary_slot);
|
||||||
|
flash_area_close(fap_scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
swap_run(struct boot_loader_state *state, struct boot_status *bs,
|
||||||
|
uint32_t copy_size)
|
||||||
|
{
|
||||||
|
uint32_t sz;
|
||||||
|
int first_sector_idx;
|
||||||
|
int last_sector_idx;
|
||||||
|
uint32_t swap_idx;
|
||||||
|
|
||||||
|
BOOT_LOG_INF("Starting swap using scratch algorithm.");
|
||||||
|
|
||||||
|
last_sector_idx = find_last_sector_idx(state, copy_size);
|
||||||
|
|
||||||
|
swap_idx = 0;
|
||||||
|
while (last_sector_idx >= 0) {
|
||||||
|
sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
|
||||||
|
if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
|
||||||
|
boot_swap_sectors(first_sector_idx, sz, state, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_sector_idx = first_sector_idx - 1;
|
||||||
|
swap_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* !MCUBOOT_OVERWRITE_ONLY */
|
||||||
|
|
||||||
|
int app_max_size(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
size_t num_sectors_primary;
|
||||||
|
size_t num_sectors_secondary;
|
||||||
|
size_t sz0, sz1;
|
||||||
|
size_t primary_slot_sz, secondary_slot_sz;
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
size_t scratch_sz;
|
||||||
|
#endif
|
||||||
|
size_t i, j;
|
||||||
|
int8_t smaller;
|
||||||
|
|
||||||
|
num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
|
||||||
|
num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
scratch_sz = boot_scratch_area_size(state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following loop scans all sectors in a linear fashion, assuring that
|
||||||
|
* for each possible sector in each slot, it is able to fit in the other
|
||||||
|
* slot's sector or sectors. Slot's should be compatible as long as any
|
||||||
|
* number of a slot's sectors are able to fit into another, which only
|
||||||
|
* excludes cases where sector sizes are not a multiple of each other.
|
||||||
|
*/
|
||||||
|
i = sz0 = primary_slot_sz = 0;
|
||||||
|
j = sz1 = secondary_slot_sz = 0;
|
||||||
|
smaller = 0;
|
||||||
|
while (i < num_sectors_primary || j < num_sectors_secondary) {
|
||||||
|
if (sz0 == sz1) {
|
||||||
|
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
|
||||||
|
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
} else if (sz0 < sz1) {
|
||||||
|
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
|
||||||
|
/* Guarantee that multiple sectors of the secondary slot
|
||||||
|
* fit into the primary slot.
|
||||||
|
*/
|
||||||
|
if (smaller == 2) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smaller = 1;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
|
||||||
|
/* Guarantee that multiple sectors of the primary slot
|
||||||
|
* fit into the secondary slot.
|
||||||
|
*/
|
||||||
|
if (smaller == 1) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smaller = 2;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
#ifndef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
if (sz0 == sz1) {
|
||||||
|
primary_slot_sz += sz0;
|
||||||
|
secondary_slot_sz += sz1;
|
||||||
|
/* Scratch has to fit each swap operation to the size of the larger
|
||||||
|
* sector among the primary slot and the secondary slot.
|
||||||
|
*/
|
||||||
|
if (sz0 > scratch_sz || sz1 > scratch_sz) {
|
||||||
|
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smaller = sz0 = sz1 = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_OVERWRITE_ONLY
|
||||||
|
return (sz1 < sz0 ? sz1 : sz0);
|
||||||
|
#else
|
||||||
|
return (secondary_slot_sz < primary_slot_sz ? secondary_slot_sz : primary_slot_sz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int app_max_size(struct boot_loader_state *state)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
int fa_id;
|
||||||
|
int rc;
|
||||||
|
uint32_t active_slot;
|
||||||
|
int primary_sz, secondary_sz;
|
||||||
|
|
||||||
|
active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
|
||||||
|
|
||||||
|
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
|
||||||
|
rc = flash_area_open(fa_id, &fap);
|
||||||
|
assert(rc == 0);
|
||||||
|
primary_sz = flash_area_get_size(fap);
|
||||||
|
flash_area_close(fap);
|
||||||
|
|
||||||
|
if (active_slot == BOOT_PRIMARY_SLOT) {
|
||||||
|
active_slot = BOOT_SECONDARY_SLOT;
|
||||||
|
} else {
|
||||||
|
active_slot = BOOT_PRIMARY_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
|
||||||
|
rc = flash_area_open(fa_id, &fap);
|
||||||
|
assert(rc == 0);
|
||||||
|
secondary_sz = flash_area_get_size(fap);
|
||||||
|
flash_area_close(fap);
|
||||||
|
|
||||||
|
return (secondary_sz < primary_sz ? secondary_sz : primary_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
|
||||||
|
|
||||||
|
int
|
||||||
|
boot_read_image_header(struct boot_loader_state *state, int slot,
|
||||||
|
struct image_header *out_hdr, struct boot_status *bs)
|
||||||
|
{
|
||||||
|
const struct flash_area *fap;
|
||||||
|
#ifdef MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
uint32_t swap_count;
|
||||||
|
uint32_t swap_size;
|
||||||
|
#endif
|
||||||
|
int area_id;
|
||||||
|
int hdr_slot;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
#ifndef MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
(void)bs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (BOOT_IMAGE_NUMBER == 1)
|
||||||
|
(void)state;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hdr_slot = slot;
|
||||||
|
|
||||||
|
#ifdef MCUBOOT_SWAP_USING_SCRATCH
|
||||||
|
/* If the slots are being swapped, the headers might have been moved to scratch area or to the
|
||||||
|
* other slot depending on the progress of the swap process.
|
||||||
|
*/
|
||||||
|
if (bs && !boot_status_is_reset(bs)) {
|
||||||
|
rc = boot_find_status(BOOT_CURR_IMG(state), &fap);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_size(fap, &swap_size);
|
||||||
|
flash_area_close(fap);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_count = find_swap_count(state, swap_size);
|
||||||
|
|
||||||
|
if (bs->idx - BOOT_STATUS_IDX_0 >= swap_count) {
|
||||||
|
/* If all segments have been swapped, the header is located in the other slot */
|
||||||
|
hdr_slot = (slot == BOOT_PRIMARY_SLOT) ? BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
|
||||||
|
} else if (bs->idx - BOOT_STATUS_IDX_0 == swap_count - 1) {
|
||||||
|
/* If the last swap operation is in progress, the headers are currently being swapped
|
||||||
|
* since the first segment of each slot is the last to be processed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (slot == BOOT_SECONDARY_SLOT && bs->state >= BOOT_STATUS_STATE_1) {
|
||||||
|
/* After BOOT_STATUS_STATE_1, the secondary image's header has been moved to the
|
||||||
|
* scratch area.
|
||||||
|
*/
|
||||||
|
hdr_slot = BOOT_NUM_SLOTS;
|
||||||
|
} else if (slot == BOOT_PRIMARY_SLOT && bs->state >= BOOT_STATUS_STATE_2) {
|
||||||
|
/* After BOOT_STATUS_STATE_2, the primary image's header has been moved to the
|
||||||
|
* secondary slot.
|
||||||
|
*/
|
||||||
|
hdr_slot = BOOT_SECONDARY_SLOT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr_slot == BOOT_NUM_SLOTS) {
|
||||||
|
area_id = FLASH_AREA_IMAGE_SCRATCH;
|
||||||
|
} else {
|
||||||
|
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), hdr_slot);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), hdr_slot);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = flash_area_open(area_id, &fap);
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
|
||||||
|
flash_area_close(fap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = BOOT_EFLASH;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !MCUBOOT_SWAP_USING_MOVE */
|
||||||
154
bootloader/mcuboot/boot/bootutil/src/tlv.c
Normal file
154
bootloader/mcuboot/boot/bootutil/src/tlv.c
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 JUUL Labs
|
||||||
|
* Copyright (c) 2020 Arm Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "bootutil/bootutil.h"
|
||||||
|
#include "bootutil/image.h"
|
||||||
|
#include "bootutil_priv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a TLV iterator.
|
||||||
|
*
|
||||||
|
* @param it An iterator struct
|
||||||
|
* @param hdr image_header of the slot's image
|
||||||
|
* @param fap flash_area of the slot which is storing the image
|
||||||
|
* @param type Type of TLV to look for
|
||||||
|
* @param prot true if TLV has to be stored in the protected area, false otherwise
|
||||||
|
*
|
||||||
|
* @returns 0 if the TLV iterator was successfully started
|
||||||
|
* -1 on errors
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
bootutil_tlv_iter_begin(struct image_tlv_iter *it, const struct image_header *hdr,
|
||||||
|
const struct flash_area *fap, uint16_t type, bool prot)
|
||||||
|
{
|
||||||
|
uint32_t off_;
|
||||||
|
struct image_tlv_info info;
|
||||||
|
|
||||||
|
if (it == NULL || hdr == NULL || fap == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_ = BOOT_TLV_OFF(hdr);
|
||||||
|
if (LOAD_IMAGE_DATA(hdr, fap, off_, &info, sizeof(info))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
|
||||||
|
if (hdr->ih_protect_tlv_size != info.it_tlv_tot) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOAD_IMAGE_DATA(hdr, fap, off_ + info.it_tlv_tot,
|
||||||
|
&info, sizeof(info))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (hdr->ih_protect_tlv_size != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->hdr = hdr;
|
||||||
|
it->fap = fap;
|
||||||
|
it->type = type;
|
||||||
|
it->prot = prot;
|
||||||
|
it->prot_end = off_ + it->hdr->ih_protect_tlv_size;
|
||||||
|
it->tlv_end = off_ + it->hdr->ih_protect_tlv_size + info.it_tlv_tot;
|
||||||
|
// position on first TLV
|
||||||
|
it->tlv_off = off_ + sizeof(info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find next TLV
|
||||||
|
*
|
||||||
|
* @param it The image TLV iterator struct
|
||||||
|
* @param off The offset of the TLV's payload in flash
|
||||||
|
* @param len The length of the TLV's payload
|
||||||
|
* @param type If not NULL returns the type of TLV found
|
||||||
|
*
|
||||||
|
* @returns 0 if a TLV with with matching type was found
|
||||||
|
* 1 if no more TLVs with matching type are available
|
||||||
|
* -1 on errors
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, uint16_t *len,
|
||||||
|
uint16_t *type)
|
||||||
|
{
|
||||||
|
struct image_tlv tlv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (it == NULL || it->hdr == NULL || it->fap == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (it->tlv_off < it->tlv_end) {
|
||||||
|
if (it->hdr->ih_protect_tlv_size > 0 && it->tlv_off == it->prot_end) {
|
||||||
|
it->tlv_off += sizeof(struct image_tlv_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = LOAD_IMAGE_DATA(it->hdr, it->fap, it->tlv_off, &tlv, sizeof tlv);
|
||||||
|
if (rc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No more TLVs in the protected area */
|
||||||
|
if (it->prot && it->tlv_off >= it->prot_end) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->type == IMAGE_TLV_ANY || tlv.it_type == it->type) {
|
||||||
|
if (type != NULL) {
|
||||||
|
*type = tlv.it_type;
|
||||||
|
}
|
||||||
|
*off = it->tlv_off + sizeof(tlv);
|
||||||
|
*len = tlv.it_len;
|
||||||
|
it->tlv_off += sizeof(tlv) + tlv.it_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->tlv_off += sizeof(tlv) + tlv.it_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return if a TLV entry is in the protected area.
|
||||||
|
*
|
||||||
|
* @param it The image TLV iterator struct
|
||||||
|
* @param off The offset of the entry to check.
|
||||||
|
*
|
||||||
|
* @return 0 if this TLV iterator entry is not protected.
|
||||||
|
* 1 if this TLV iterator entry is in the protected region
|
||||||
|
* -1 if the iterator is invalid.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
bootutil_tlv_iter_is_prot(struct image_tlv_iter *it, uint32_t off)
|
||||||
|
{
|
||||||
|
if (it == NULL || it->hdr == NULL || it->fap == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off < it->prot_end;
|
||||||
|
}
|
||||||
46
bootloader/mcuboot/boot/bootutil/zephyr/CMakeLists.txt
Normal file
46
bootloader/mcuboot/boot/bootutil/zephyr/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
if(CONFIG_MCUBOOT_BOOTUTIL_LIB)
|
||||||
|
|
||||||
|
zephyr_interface_library_named(MCUBOOT_BOOTUTIL)
|
||||||
|
|
||||||
|
target_include_directories(MCUBOOT_BOOTUTIL INTERFACE
|
||||||
|
../
|
||||||
|
../include
|
||||||
|
../../zephyr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_library_named(mcuboot_util)
|
||||||
|
zephyr_library_sources(
|
||||||
|
../src/bootutil_public.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Sensitivity to the TEST_BOOT_IMAGE_ACCESS_HOOKS define is implemented for
|
||||||
|
# allowing the test-build with the hooks feature enabled.
|
||||||
|
if(TEST_BOOT_IMAGE_ACCESS_HOOKS)
|
||||||
|
zephyr_library_sources(
|
||||||
|
${APPLICATION_SOURCE_DIR}/hooks_sample.c
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_BOOT_USE_PSA_CRYPTO)
|
||||||
|
target_include_directories(MCUBOOT_BOOTUTIL INTERFACE
|
||||||
|
${ZEPHYR_MBEDTLS_MODULE_DIR}/include
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO AND NOT CONFIG_PSA_CORE_OBERON)
|
||||||
|
zephyr_link_libraries(mbedTLS)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
41
bootloader/mcuboot/boot/cypress/.gitignore
vendored
Normal file
41
bootloader/mcuboot/boot/cypress/.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
outdir/
|
||||||
|
.*.swp
|
||||||
|
target.sh
|
||||||
|
*.pyc
|
||||||
|
tags
|
||||||
|
rusty-tags.*
|
||||||
|
|
||||||
|
# mynewt
|
||||||
|
/repos/
|
||||||
|
/project.state
|
||||||
|
/bin/
|
||||||
|
/targets/
|
||||||
|
**/build/**/*
|
||||||
|
|
||||||
|
#Eclipse project files
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
|
||||||
|
# Compiled python modules.
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Setuptools distribution folder.
|
||||||
|
/scripts/dist/
|
||||||
|
|
||||||
|
# Python egg metadata, regenerated from source files by setuptools.
|
||||||
|
/scripts/*.egg-info
|
||||||
|
/scripts/*.egg
|
||||||
|
|
||||||
|
# Build dirs
|
||||||
|
*out/*/*
|
||||||
|
*out/obj/*
|
||||||
|
|
||||||
|
# Build files
|
||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
*.map
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.hex
|
||||||
|
*.log
|
||||||
|
*.lst
|
||||||
132
bootloader/mcuboot/boot/cypress/BlinkyApp/BlinkyApp.mk
Normal file
132
bootloader/mcuboot/boot/cypress/BlinkyApp/BlinkyApp.mk
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
################################################################################
|
||||||
|
# \file BlinkyApp.mk
|
||||||
|
# \version 1.0
|
||||||
|
#
|
||||||
|
# \brief
|
||||||
|
# Makefile to describe demo application BlinkyApp for Cypress MCUBoot based applications.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
# \copyright
|
||||||
|
# Copyright 2018-2019 Cypress Semiconductor Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
include host.mk
|
||||||
|
|
||||||
|
# Cypress' MCUBoot Application supports GCC ARM only at this moment
|
||||||
|
# Set defaults to:
|
||||||
|
# - compiler GCC
|
||||||
|
# - build configuration to Debug
|
||||||
|
# - image type to BOOT
|
||||||
|
COMPILER ?= GCC_ARM
|
||||||
|
IMG_TYPE ?= BOOT
|
||||||
|
|
||||||
|
# For which core this application is built
|
||||||
|
CORE ?= CM4
|
||||||
|
|
||||||
|
# image type can be BOOT or UPGRADE
|
||||||
|
IMG_TYPES = BOOT UPGRADE
|
||||||
|
|
||||||
|
# possible values are 0 and 0xff
|
||||||
|
# internal Flash by default
|
||||||
|
ERASED_VALUE ?= 0
|
||||||
|
|
||||||
|
ifneq ($(COMPILER), GCC_ARM)
|
||||||
|
$(error Only GCC ARM is supported at this moment)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CUR_APP_PATH = $(PRJ_DIR)/$(APP_NAME)
|
||||||
|
|
||||||
|
include $(PRJ_DIR)/platforms.mk
|
||||||
|
include $(PRJ_DIR)/common_libs.mk
|
||||||
|
include $(PRJ_DIR)/toolchains.mk
|
||||||
|
|
||||||
|
# Application-specific DEFINES
|
||||||
|
ifeq ($(IMG_TYPE), BOOT)
|
||||||
|
DEFINES_APP := -DBOOT_IMG
|
||||||
|
else
|
||||||
|
DEFINES_APP := -DUPGRADE_IMG
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Define start of application, RAM start and size, slot size
|
||||||
|
ifeq ($(PLATFORM), PSOC_062_2M)
|
||||||
|
DEFINES_APP += -DRAM_START=0x08040000
|
||||||
|
DEFINES_APP += -DRAM_SIZE=0x10000
|
||||||
|
else ifeq ($(PLATFORM), PSOC_062_1M)
|
||||||
|
DEFINES_APP += -DRAM_START=0x08020000
|
||||||
|
DEFINES_APP += -DRAM_SIZE=0x10000
|
||||||
|
else ifeq ($(PLATFORM), PSOC_062_512K)
|
||||||
|
DEFINES_APP += -DRAM_START=0x08020000
|
||||||
|
DEFINES_APP += -DRAM_SIZE=0x10000
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
DEFINES_APP += -DRAM_SIZE=0x10000
|
||||||
|
DEFINES_APP += -DUSER_APP_START=0x10018000
|
||||||
|
SLOT_SIZE ?= 0x10000
|
||||||
|
|
||||||
|
|
||||||
|
# Collect Test Application sources
|
||||||
|
SOURCES_APP_SRC := $(wildcard $(CUR_APP_PATH)/*.c)
|
||||||
|
# Collect all the sources
|
||||||
|
SOURCES_APP += $(SOURCES_APP_SRC)
|
||||||
|
|
||||||
|
# Collect includes for BlinkyApp
|
||||||
|
INCLUDE_DIRS_APP := $(addprefix -I, $(CURDIR))
|
||||||
|
INCLUDE_DIRS_APP += $(addprefix -I, $(CUR_APP_PATH))
|
||||||
|
|
||||||
|
# Overwite path to linker script if custom is required, otherwise default from BSP is used
|
||||||
|
ifeq ($(COMPILER), GCC_ARM)
|
||||||
|
LINKER_SCRIPT := $(subst /cygdrive/c,c:,$(CUR_APP_PATH)/linker/$(APP_NAME).ld)
|
||||||
|
else
|
||||||
|
$(error Only GCC ARM is supported at this moment)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ASM_FILES_APP :=
|
||||||
|
ASM_FILES_APP += $(ASM_FILES_STARTUP)
|
||||||
|
|
||||||
|
# We still need this for MCUBoot apps signing
|
||||||
|
IMGTOOL_PATH ?= ../../scripts/imgtool.py
|
||||||
|
|
||||||
|
SIGN_ARGS := sign --header-size 1024 --pad-header --align 8 -v "2.0" -S $(SLOT_SIZE) -M 512 --overwrite-only -R $(ERASED_VALUE) -k keys/$(SIGN_KEY_FILE).pem
|
||||||
|
|
||||||
|
# Output folder
|
||||||
|
OUT := $(APP_NAME)/out
|
||||||
|
# Output folder to contain build artifacts
|
||||||
|
OUT_TARGET := $(OUT)/$(PLATFORM)
|
||||||
|
|
||||||
|
OUT_CFG := $(OUT_TARGET)/$(BUILDCFG)
|
||||||
|
|
||||||
|
# Set build directory for BOOT and UPGRADE images
|
||||||
|
ifeq ($(IMG_TYPE), UPGRADE)
|
||||||
|
ifeq ($(ENC_IMG), 1)
|
||||||
|
SIGN_ARGS += --encrypt ../../$(ENC_KEY_FILE).pem
|
||||||
|
endif
|
||||||
|
SIGN_ARGS += --pad
|
||||||
|
UPGRADE_SUFFIX :=_upgrade
|
||||||
|
OUT_CFG := $(OUT_CFG)/upgrade
|
||||||
|
else
|
||||||
|
OUT_CFG := $(OUT_CFG)/boot
|
||||||
|
endif
|
||||||
|
|
||||||
|
pre_build:
|
||||||
|
$(info [PRE_BUILD] - Generating linker script for application $(CUR_APP_PATH)/linker/$(APP_NAME).ld)
|
||||||
|
@$(CC) -E -x c $(CFLAGS) $(INCLUDE_DIRS) $(CUR_APP_PATH)/linker/$(APP_NAME)_template.ld | grep -v '^#' >$(CUR_APP_PATH)/linker/$(APP_NAME).ld
|
||||||
|
|
||||||
|
# Post build action to execute after main build job
|
||||||
|
post_build: $(OUT_CFG)/$(APP_NAME).hex
|
||||||
|
$(info [POST_BUILD] - Executing post build script for $(APP_NAME))
|
||||||
|
mv -f $(OUT_CFG)/$(APP_NAME).hex $(OUT_CFG)/$(APP_NAME)_unsigned.hex
|
||||||
|
$(PYTHON_PATH) $(IMGTOOL_PATH) $(SIGN_ARGS) $(OUT_CFG)/$(APP_NAME)_unsigned.hex $(OUT_CFG)/$(APP_NAME)$(UPGRADE_SUFFIX).hex
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<launchConfiguration type="ilg.gnumcueclipse.debug.gdbjtag.openocd.launchConfigurationType">
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doContinue" value="false"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doDebugInRam" value="false"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doFirstReset" value="true"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doGdbServerAllocateConsole" value="true"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doGdbServerAllocateTelnetConsole" value="false"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doSecondReset" value="false"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doStartGdbCLient" value="true"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doStartGdbServer" value="true"/>
|
||||||
|
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.enableSemihosting" value="true"/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.firstResetType" value="init"/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbClientOtherCommands" value="set mem inaccessible-by-default off"/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbClientOtherOptions" value=""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerConnectionAddress" value=""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerExecutable" value="${cy_tools_path:openocd}/bin/openocd"/>
|
||||||
|
<intAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerGdbPortNumber" value="3333"/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerLog" value=""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerOther" value="-s "${cy_tools_path:openocd}/scripts" -s "${workspace_loc}/BlinkyLED_config/GeneratedSource" -c "source [find interface/kitprog3.cfg]" -c "source [find target/psoc6_2m.cfg]" -c "gdb_port 3332" -c "puts stderr {Started by GNU MCU Eclipse}" -c "init; reset init""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerTclPortNumber" value="6666"/>
|
||||||
|
<intAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerTelnetPortNumber" value="4444"/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.otherInitCommands" value=""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.otherRunCommands" value=""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.secondResetType" value=""/>
|
||||||
|
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.svdPath" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageFileName" value="/Users/rnok/repos/cy_mcuboot_project/cy_mcuboot/boot/cypress/BlinkyApp/out/boot/CY8CKIT-064S2-4343W/Debug/BlinkyApp.elf"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageOffset" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.ipAddress" value="localhost"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.jtagDevice" value="GNU MCU OpenOCD"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadImage" value="false"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadSymbols" value="true"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.pcRegister" value=""/>
|
||||||
|
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.portNumber" value="3333"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setPcRegister" value="false"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setResume" value="false"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setStopAt" value="false"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.stopAt" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsFileName" value="/Users/rnok/repos/cy_mcuboot_project/cy_mcuboot/boot/cypress/BlinkyApp/out/CY8CKIT-064S2-4343W/Debug/boot/BlinkyApp.elf"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsOffset" value=""/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForImage" value="false"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForSymbols" value="false"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForImage" value="true"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForSymbols" value="true"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useRemoteTarget" value="true"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="${cy_sdk_install_dir}/tools/gcc-7.2.1-1.0/bin/arm-none-eabi-gdb${cy_exe_platform_ext}"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.UPDATE_THREADLIST_ON_SUSPEND" value="false"/>
|
||||||
|
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="boot/cypress/BlinkyApp/out/PSOC_062_2M/Debug/boot/BlinkyApp.elf"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="cy_mcuboot"/>
|
||||||
|
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="true"/>
|
||||||
|
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="ilg.gnuarmeclipse.managedbuild.cross.toolchain.base.1139973781"/>
|
||||||
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||||
|
<listEntry value="/cy_mcuboot"/>
|
||||||
|
</listAttribute>
|
||||||
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||||
|
<listEntry value="4"/>
|
||||||
|
</listAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList context="Context string"> <memoryBlockExpression address="268566528" label="0x10020000"/> <memoryBlockExpression address="268632064" label="0x10030000"/> </memoryBlockExpressionList> "/>
|
||||||
|
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
|
||||||
|
</launchConfiguration>
|
||||||
165
bootloader/mcuboot/boot/cypress/BlinkyApp/Readme.md
Normal file
165
bootloader/mcuboot/boot/cypress/BlinkyApp/Readme.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
### Blinking LED test application for MCUboot bootloader
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Implements simple Blinky LED CM4 application to demonstrate MCUboot Application operation in terms of BOOT and UPGRADE process.
|
||||||
|
|
||||||
|
It is started by MCUboot Application which is running on CM0p.
|
||||||
|
|
||||||
|
Functionality:
|
||||||
|
|
||||||
|
* Blinks RED led with 2 different rates, depending on type of image - BOOT or UPGRADE.
|
||||||
|
* Prints debug info and version of itself to terminal at 115200 baud.
|
||||||
|
* Can be built for BOOT slot or UPGRADE slot of bootloader.
|
||||||
|
|
||||||
|
Currently supported platforms
|
||||||
|
|
||||||
|
* PSOC_062_2M
|
||||||
|
* PSOC_062_1M
|
||||||
|
* PSOC_062_512K
|
||||||
|
|
||||||
|
### Hardware limitations
|
||||||
|
|
||||||
|
Since this application is created to demonstrate MCUboot library features and not as reference examples some considerations are taken.
|
||||||
|
|
||||||
|
1. Port/pin `P5_0` and `P5_1` used to configure serial port for debug prints. These pins are the most commonly used for serial port connection among available Cypress PSoC 6 kits. If you try to use custom hardware with this application - change definitions of `CY_DEBUG_UART_TX` and `CY_DEBUG_UART_RX` in `main.c` of BlinkyApp to port/pin pairs corresponding to your design.
|
||||||
|
2. Port `GPIO_PRT13` pin `7U` used to define user connection LED. This pin is the most commonly used for USER_LED connection among available Cypress PSoC 6 kits. If you try to use custom hardware with this application - change definitions of `LED_PORT` and `LED_PIN` in `main.c` of BlinkyApp to port/pin pairs corresponding to your design.
|
||||||
|
|
||||||
|
### Pre-build action
|
||||||
|
|
||||||
|
Pre-build action is implemented for defining start address and size of flash, as well as RAM start address and size for BlinkyApp.
|
||||||
|
These values are set by specifing following macros: `-DUSER_APP_SIZE`, `-DUSER_APP_START`, `-DRAM_SIZE`, `-DRAM_START` in makefile.
|
||||||
|
|
||||||
|
Pre-build action calls GCC preprocessor which intantiates defines for particular values in `BlinkyApp_template.ld`.
|
||||||
|
|
||||||
|
Default values set for currently supported targets:
|
||||||
|
* `BlinkyApp.mk` to `-DUSER_APP_START=0x10018000`
|
||||||
|
|
||||||
|
**Important**: make sure RAM areas of CM4-based BlinkyApp and CM0p-based MCUBootApp bootloader do not overlap.
|
||||||
|
Memory (stack) corruption of CM0p application can cause failure if SystemCall-served operations invoked from CM4.
|
||||||
|
|
||||||
|
### Building an application
|
||||||
|
|
||||||
|
Root directory for build is **boot/cypress.**
|
||||||
|
|
||||||
|
The following command will build regular HEX file of a BlinkyApp for BOOT slot. Substitute `PLATFORM=` to a paltform name you use in all following commands.
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=BOOT
|
||||||
|
|
||||||
|
This have following defaults suggested:
|
||||||
|
|
||||||
|
BUILDCFG=Debug
|
||||||
|
IMG_TYPE=BOOT
|
||||||
|
|
||||||
|
To build UPGRADE image use following command:
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x10000
|
||||||
|
|
||||||
|
Note: HEADER_OFFSET=%SLOT_SIZE%
|
||||||
|
|
||||||
|
Example command-line for single-image:
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=BOOT
|
||||||
|
|
||||||
|
**Building Multi-Image**
|
||||||
|
|
||||||
|
`BlinkyApp` can be built to use in multi-image bootloader configuration.
|
||||||
|
|
||||||
|
To get appropriate artifacts to use with multi image MCUBootApp, makefile flag `HEADER_OFFSET=` can be used.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
Considering default config:
|
||||||
|
|
||||||
|
* first image BOOT (PRIMARY) slot start `0x10018000`
|
||||||
|
* slot size `0x10000`
|
||||||
|
* second image BOOT (PRIMARY) slot start `0x10038000`
|
||||||
|
|
||||||
|
To get appropriate artifact for second image PRIMARY slot run this command:
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=BOOT HEADER_OFFSET=0x20000
|
||||||
|
|
||||||
|
*Note:* only 2 images are supported at the moment.
|
||||||
|
|
||||||
|
**How to build upgrade image for external memory:**
|
||||||
|
|
||||||
|
To prepare MCUBootApp for work with external memory please refer to `MCUBootApp/ExternalMemory.md`.
|
||||||
|
|
||||||
|
For build BlinkyApp upgrade image for external memory use command:
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x7FE8000 ERASED_VALUE=0xff
|
||||||
|
|
||||||
|
`HEADER_OFFSET` defines the offset from original boot image address. This one in line above suggests secondary slot will start from `0x18000000`.
|
||||||
|
|
||||||
|
`ERASED_VALUE` defines the memory cell contents in erased state. It is `0x00` for PSoC6's internal Flash and `0xff` for S25FL512S.
|
||||||
|
|
||||||
|
In case of using muti-image configuration, upgrade image for second application can be built using next command:
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x8028000 ERASED_VALUE=0xff
|
||||||
|
|
||||||
|
Note: for S25FL512S block address shuld be mutiple by 0x40000
|
||||||
|
|
||||||
|
**How to build encrypted upgrade image :**
|
||||||
|
|
||||||
|
To prepare MCUBootApp for work with encrypted upgrade image please refer to `MCUBootApp/Readme.md`.
|
||||||
|
|
||||||
|
To obtain encrypted upgrade image of BlinkyApp extra flag `ENC_IMG=1` should be passed in command line, for example:
|
||||||
|
|
||||||
|
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x20000 ENC_IMG=1
|
||||||
|
|
||||||
|
This also suggests user already placed corresponing `*.pem` key in `\keys` folder. The key variables are defined in root `Makefile` as `SIGN_KEY_FILE` and `ENC_KEY_FILE`
|
||||||
|
|
||||||
|
### Post-build
|
||||||
|
|
||||||
|
Post build action is executed at compile time for `BlinkyApp`. In case of build for `PSOC_062_2M` platform it calls `imgtool` from `MCUboot` scripts and adds signature to compiled image.
|
||||||
|
|
||||||
|
Flags passed to `imgtool` for signature are defined in `SIGN_ARGS` variable in BlinkyApp.mk.
|
||||||
|
|
||||||
|
### How to program an application
|
||||||
|
|
||||||
|
Use any preferred tool for programming hex files.
|
||||||
|
|
||||||
|
Hex file names to use for programming:
|
||||||
|
|
||||||
|
`BlinkyApp` always produce build artifacts in 2 separate folders - `boot` and `upgrade`.
|
||||||
|
|
||||||
|
`BlinkyApp` built to run with `MCUBootApp` produces files with name BlinkyApp.hex in `boot` directory and `BlinkyApp_upgrade.hex` in `upgrade` folder. These files are ready to be flashed to the board.
|
||||||
|
|
||||||
|
`BlinkyApp_unsigned.hex` hex file is also preserved in both cases for possible troubleshooting.
|
||||||
|
|
||||||
|
Files to use for programming are:
|
||||||
|
|
||||||
|
`BOOT` - boot/BlinkyApp.hex
|
||||||
|
`UPGRADE` - upgrade/BlinkyApp_upgrade.hex
|
||||||
|
|
||||||
|
**Flags:**
|
||||||
|
- `BUILDCFG` - configuration **Release** or **Debug**
|
||||||
|
- `MAKEINFO` - 0 (default) - less build info, 1 - verbose output of compilation.
|
||||||
|
- `HEADER_OFFSET` - 0 (default) - no offset of output hex file, 0x%VALUE% - offset for output hex file. Value 0x10000 is slot size MCUboot Bootloader in this example.
|
||||||
|
- `IMG_TYPE` - `BOOT` (default) - build image for BOOT slot of MCUboot Bootloader, `UPGRADE` - build image for UPGRADE slot of MCUboot Bootloader.
|
||||||
|
- `ENC_IMG` - 0 (default) - build regular upgrade image, `1` - build encrypted upgrade image (MCUBootApp should also be built with this flash set 1)
|
||||||
|
|
||||||
|
**NOTE**: In case of `UPGRADE` image `HEADER_OFFSET` should be set to MCUboot Bootloader slot size.
|
||||||
|
|
||||||
|
### Example terminal output
|
||||||
|
|
||||||
|
When user application programmed in BOOT slot:
|
||||||
|
|
||||||
|
===========================
|
||||||
|
[BlinkyApp] BlinkyApp v1.0 [CM4]
|
||||||
|
===========================
|
||||||
|
[BlinkyApp] GPIO initialized
|
||||||
|
[BlinkyApp] UART initialized
|
||||||
|
[BlinkyApp] Retarget I/O set to 115200 baudrate
|
||||||
|
[BlinkyApp] Red led blinks with 1 sec period
|
||||||
|
|
||||||
|
When user application programmed in UPRADE slot and upgrade procedure was successful:
|
||||||
|
|
||||||
|
===========================
|
||||||
|
[BlinkyApp] BlinkyApp v2.0 [+]
|
||||||
|
===========================
|
||||||
|
|
||||||
|
[BlinkyApp] GPIO initialized
|
||||||
|
[BlinkyApp] UART initialized
|
||||||
|
[BlinkyApp] Retarget I/O set to 115200 baudrate
|
||||||
|
[BlinkyApp] Red led blinks with 0.25 sec period
|
||||||
60
bootloader/mcuboot/boot/cypress/BlinkyApp/libs.mk
Normal file
60
bootloader/mcuboot/boot/cypress/BlinkyApp/libs.mk
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
################################################################################
|
||||||
|
# \file libs.mk
|
||||||
|
# \version 1.0
|
||||||
|
#
|
||||||
|
# \brief
|
||||||
|
# Makefile to describe libraries needed for Cypress MCUBoot based applications.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
# \copyright
|
||||||
|
# Copyright 2018-2019 Cypress Semiconductor Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# PDL library
|
||||||
|
################################################################################
|
||||||
|
PDL_VERSION = 121
|
||||||
|
#
|
||||||
|
CUR_LIBS_PATH = $(PRJ_DIR)/libs
|
||||||
|
|
||||||
|
# Collect source files for Retarget-io
|
||||||
|
SOURCES_RETARGET_IO := $(wildcard $(CUR_LIBS_PATH)/retarget-io/*.c)
|
||||||
|
SOURCES_WATCHDOG := $(wildcard $(CUR_LIBS_PATH)/watchdog/*.c)
|
||||||
|
|
||||||
|
# Collect source files for HAL
|
||||||
|
SOURCES_HAL := $(wildcard $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/source/*.c)
|
||||||
|
SOURCES_HAL += $(wildcard $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/source/triggers/*.c)
|
||||||
|
SOURCES_HAL += $(wildcard $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/source/pin_packages/*.c)
|
||||||
|
|
||||||
|
# Retarget-io related include directories
|
||||||
|
INCLUDE_DIRS_RETARGET_IO := $(CUR_LIBS_PATH)/retarget-io
|
||||||
|
INCLUDE_DIRS_WATCHDOG := $(CUR_LIBS_PATH)/watchdog
|
||||||
|
|
||||||
|
# Collect dirrectories containing headers for PSOC6 HAL
|
||||||
|
INCLUDE_DIRS_HAL := $(CUR_LIBS_PATH)/psoc6hal/include
|
||||||
|
INCLUDE_DIRS_HAL += $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/include
|
||||||
|
INCLUDE_DIRS_HAL += $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/include/pin_packages
|
||||||
|
INCLUDE_DIRS_HAL += $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/include/triggers
|
||||||
|
|
||||||
|
# Collected source files for libraries
|
||||||
|
SOURCES_LIBS += $(SOURCES_RETARGET_IO)
|
||||||
|
SOURCES_LIBS += $(SOURCES_WATCHDOG)
|
||||||
|
SOURCES_LIBS += $(SOURCES_HAL)
|
||||||
|
|
||||||
|
# Collected include directories for libraries
|
||||||
|
INCLUDE_DIRS_LIBS += $(addprefix -I,$(INCLUDE_DIRS_RETARGET_IO))
|
||||||
|
INCLUDE_DIRS_LIBS += $(addprefix -I,$(INCLUDE_DIRS_WATCHDOG))
|
||||||
|
INCLUDE_DIRS_LIBS += $(addprefix -I,$(INCLUDE_DIRS_HAL))
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user