Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bootloader downgrade protection #238

Merged
merged 28 commits into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e4e0a3a
Add code responsible for firmware version verification in the bootloader
szszszsz Aug 5, 2019
d618081
Add version code
szszszsz Aug 5, 2019
beb5a58
Add linker scripts
szszszsz Aug 6, 2019
118e129
Set firmware version in the flash
szszszsz Aug 6, 2019
9248c64
Add missing is_newer and pubkey
szszszsz Aug 6, 2019
188a34d
Add missing Makefile entry. Rename pubkey file.
szszszsz Aug 7, 2019
17ceb7b
Make the public key generic
szszszsz Aug 7, 2019
efddd2f
Use the same public bootloader key as before
szszszsz Aug 7, 2019
35e52f4
Initial modification to move bootloader data after the application
szszszsz Aug 22, 2019
9ddba5d
Add extra linker script changes
szszszsz Aug 23, 2019
1100b15
Refactor. Add debug code. Use %u for unsigned. Use volatile pointer i…
szszszsz Aug 23, 2019
ea803aa
Make the flash memory structure depend on the APPLICATION_START_PAGE …
szszszsz Aug 23, 2019
7042b0b
Move app version to the end of the firmware code, without specific ad…
szszszsz Aug 24, 2019
40c3c13
Correct flash2 region. Rename _bconfig_start->bootloader_configuration.
szszszsz Aug 24, 2019
22293f8
Rename flash2 -> flash_cfg
szszszsz Aug 24, 2019
3a1ea27
Move _extra* debug linker scripts content to main
szszszsz Aug 24, 2019
7fddd58
Bootloader: get uploaded application version from the 4 last bytes of…
szszszsz Aug 24, 2019
cb13fb6
Store version in the bootloader. Debug code.
szszszsz Aug 24, 2019
9dae7b2
Makefile: fix flashboot recipe
szszszsz Aug 24, 2019
8023347
Makefile: add debug info
szszszsz Aug 24, 2019
987b045
Correct memory layout
szszszsz Aug 24, 2019
7418140
Rename last_addr->last_written_app_address
szszszsz Aug 24, 2019
e3ff136
Remove obsolete region for the app static firmware version address
szszszsz Aug 24, 2019
3c7bf5a
Remove obsolete debug messages
szszszsz Aug 24, 2019
3621f2e
Add missed doc update in the linker script
szszszsz Aug 24, 2019
a053bbc
Do not verify version for the hacker edition
szszszsz Aug 24, 2019
a5e1dc2
Correct linker documentation
szszszsz Aug 24, 2019
08658eb
Merge branch 'master' into bootloader-downgrade-protection
conorpp Oct 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions fido2/ctap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1775,8 +1775,14 @@ void ctap_load_external_keys(uint8_t * keybytes){
crypto_load_master_secret(STATE.key_space);
}

#include "version.h"
void ctap_init()
{
printf1(TAG_ERR,"Current firmware version address: %p\r\n", &firmware_version);
printf1(TAG_ERR,"Current firmware version: %d.%d.%d.%d (%02x.%02x.%02x.%02x)\r\n",
firmware_version.major, firmware_version.minor, firmware_version.patch, firmware_version.reserved,
firmware_version.major, firmware_version.minor, firmware_version.patch, firmware_version.reserved
);
crypto_ecc256_init();

authenticator_read_state(&STATE);
Expand Down
13 changes: 13 additions & 0 deletions fido2/version.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "version.h"


const version_t firmware_version __attribute__ ((section (".flag"))) __attribute__ ((__used__)) = {
.major = SOLO_VERSION_MAJ,
.minor = SOLO_VERSION_MIN,
.patch = SOLO_VERSION_PATCH,
.reserved = 0
};

// from tinycbor, for a quick static_assert
#include <compilersupport_p.h>
cbor_static_assert(sizeof(version_t) == 4);
18 changes: 18 additions & 0 deletions fido2/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,23 @@
#define SOLO_VERSION __STR(SOLO_VERSION_MAJ) "." __STR(SOLO_VERSION_MIN) "." __STR(SOLO_VERSION_PATCH)
#endif

#include <stdint.h>
#include <stdbool.h>

typedef struct {
union{
uint32_t raw;
struct {
uint8_t major;
uint8_t minor;
uint8_t patch;
uint8_t reserved;
};
};
} version_t;

bool is_newer(const version_t* const newer, const version_t* const older);
const version_t firmware_version ;


#endif
3 changes: 1 addition & 2 deletions targets/stm32l432/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ flash_dfu: solo.hex bootloader.hex
# STM32_Programmer_CLI -c port=usb1 -halt -e all --readunprotect
STM32_Programmer_CLI -c port=usb1 -halt -rdu -d all.hex

flashboot: solo.hex bootloader.hex
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
flashboot: bootloader.hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst

Expand Down
67 changes: 53 additions & 14 deletions targets/stm32l432/bootloader/bootloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
#include "ctap_errors.h"
#include "log.h"

volatile version_t current_firmware_version __attribute__ ((section (".flag2"))) __attribute__ ((__used__)) = {
.major = SOLO_VERSION_MAJ,
.minor = SOLO_VERSION_MIN,
.patch = SOLO_VERSION_PATCH,
.reserved = 0
};

extern uint8_t REBOOT_FLAG;

Expand Down Expand Up @@ -56,8 +62,6 @@ static void erase_application()
}
}

#define LAST_ADDR (APPLICATION_END_ADDR-2048 + 8)
#define LAST_PAGE (APPLICATION_END_PAGE-1)
static void disable_bootloader()
{
// Clear last 4 bytes of the last application page-1, which is 108th
Expand Down Expand Up @@ -102,6 +106,38 @@ int is_bootloader_disabled()
uint32_t * auth = (uint32_t *)(AUTH_WORD_ADDR+4);
return *auth == 0;
}
uint8_t * last_written_app_address;

#include "version.h"
bool is_firmware_version_newer_or_equal()
{

printf1(TAG_BOOT,"Current firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
);
volatile version_t * new_version = ((volatile version_t *) last_written_app_address);
printf1(TAG_BOOT,"Uploaded firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
new_version->major, new_version->minor, new_version->patch, new_version->reserved,
new_version->major, new_version->minor, new_version->patch, new_version->reserved
);

const bool allowed = is_newer(new_version, &current_firmware_version) || current_firmware_version.raw == 0xFFFFFFFF;
if (allowed){
printf1(TAG_BOOT, "Update allowed, setting new firmware version as current.\r\n");
// current_firmware_version.raw = new_version.raw;
uint8_t page[PAGE_SIZE];
memmove(page, (uint8_t*)BOOT_VERSION_ADDR, PAGE_SIZE);
memmove(page, new_version, 4);
printf1(TAG_BOOT, "Writing\r\n");
flash_erase_page(BOOT_VERSION_PAGE);
flash_write(BOOT_VERSION_ADDR, page, PAGE_SIZE);
printf1(TAG_BOOT, "Finish\r\n");
} else {
printf1(TAG_BOOT, "Firmware older - update not allowed.\r\n");
}
return allowed;
}

/**
* Execute bootloader commands
Expand All @@ -125,10 +161,7 @@ int bootloader_bridge(int klen, uint8_t * keyh)
return CTAP1_ERR_INVALID_LENGTH;
}
#ifndef SOLO_HACKER
uint8_t * pubkey = (uint8_t*)"\xd2\xa4\x2f\x8f\xb2\x31\x1c\xc1\xf7\x0c\x7e\x64\x32\xfb\xbb\xb4\xa3\xdd\x32\x20"
"\x0f\x1b\x88\x9c\xda\x62\xc2\x83\x25\x93\xdd\xb8\x75\x9d\xf9\x86\xee\x03\x6c\xce"
"\x34\x47\x71\x36\xb3\xb2\xad\x6d\x12\xb7\xbe\x49\x3e\x20\xa4\x61\xac\xc7\x71\xc7"
"\x1f\xa8\x14\xf2";
extern uint8_t *pubkey_boot;

const struct uECC_Curve_t * curve = NULL;
#endif
Expand Down Expand Up @@ -165,12 +198,11 @@ int bootloader_bridge(int klen, uint8_t * keyh)
}
// Do the actual write
flash_write((uint32_t)ptr,req->payload, len);


last_written_app_address = (uint8_t *)ptr + len - 8 + 4;
break;
case BootDone:
// Writing to flash finished. Request code validation.
printf1(TAG_BOOT, "BootDone: ");
printf1(TAG_BOOT, "BootDone: \r\n");
#ifndef SOLO_HACKER
if (len != 64)
{
Expand All @@ -185,17 +217,23 @@ int bootloader_bridge(int klen, uint8_t * keyh)
crypto_sha256_final(hash);
curve = uECC_secp256r1();
// Verify incoming signature made over the SHA256 hash
if (! uECC_verify(pubkey,
hash,
32,
req->payload,
curve))
if (
!uECC_verify(pubkey_boot, hash, 32, req->payload, curve)
)
{
printf1(TAG_BOOT, "Signature invalid\r\n");
return CTAP2_ERR_OPERATION_DENIED;
}
if (!is_firmware_version_newer_or_equal()){
printf1(TAG_BOOT, "Firmware older - update not allowed.\r\n");
printf1(TAG_BOOT, "Rebooting...\r\n");
REBOOT_FLAG = 1;
return CTAP2_ERR_OPERATION_DENIED;
}
#endif
// Set the application validated, and mark for reboot.
authorize_application();

REBOOT_FLAG = 1;
break;
case BootCheck:
Expand All @@ -218,6 +256,7 @@ int bootloader_bridge(int klen, uint8_t * keyh)
break;
case BootReboot:
printf1(TAG_BOOT, "BootReboot.\r\n");
printf1(TAG_BOOT, "Application authorized: %d.\r\n", is_authorized_to_boot());
REBOOT_FLAG = 1;
break;
case BootDisable:
Expand Down
8 changes: 8 additions & 0 deletions targets/stm32l432/bootloader/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ int main()

printf1(TAG_GEN,"recv'ing hid msg \n");

extern volatile version_t current_firmware_version;
printf1(TAG_BOOT,"Current firmware version address: %p\r\n", &current_firmware_version);
printf1(TAG_BOOT,"Current firmware version: %d.%d.%d.%d (%02x.%02x.%02x.%02x)\r\n",
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
);
dump_hex1(TAG_BOOT, (uint8_t*)(&current_firmware_version) - 16, 32);


while(1)
{
Expand Down
6 changes: 6 additions & 0 deletions targets/stm32l432/bootloader/pubkey_bootloader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "stdint.h"

uint8_t * pubkey_boot = (uint8_t*)"\xd2\xa4\x2f\x8f\xb2\x31\x1c\xc1\xf7\x0c\x7e\x64\x32\xfb\xbb\xb4\xa3\xdd\x32\x20"
"\x0f\x1b\x88\x9c\xda\x62\xc2\x83\x25\x93\xdd\xb8\x75\x9d\xf9\x86\xee\x03\x6c\xce"
"\x34\x47\x71\x36\xb3\xb2\xad\x6d\x12\xb7\xbe\x49\x3e\x20\xa4\x61\xac\xc7\x71\xc7"
"\x1f\xa8\x14\xf2";
8 changes: 8 additions & 0 deletions targets/stm32l432/bootloader/version_check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "version.h"

// FIXME test version check function
bool is_newer(const version_t* const newer, const version_t* const older){
return (newer->major > older->major) ||
(newer->major == older->major && newer->minor > older->minor) ||
(newer->major == older->major && newer->minor == older->minor && newer->patch >= older->patch);
}
2 changes: 2 additions & 0 deletions targets/stm32l432/build/application.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SRC += $(DRIVER_LIBS) $(USB_LIB)
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
SRC += ../../fido2/version.c
SRC += ../../fido2/data_migration.c
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
SRC += ../../fido2/extensions/wallet.c
Expand Down Expand Up @@ -70,6 +71,7 @@ all: $(TARGET).elf

%.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@
@echo "Built version: $(VERSION_FLAGS)"

%.hex: %.elf
$(SZ) $^
Expand Down
2 changes: 2 additions & 0 deletions targets/stm32l432/build/bootloader.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ include build/common.mk

# ST related
SRC = bootloader/main.c bootloader/bootloader.c
SRC += bootloader/pubkey_bootloader.c bootloader/version_check.c
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
SRC += src/fifo.c src/crypto.c src/attestation.c src/sense.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
Expand Down Expand Up @@ -65,6 +66,7 @@ all: $(TARGET).elf

%.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@
arm-none-eabi-size $@

%.hex: %.elf
$(CP) -O ihex $^ $(TARGET).hex
Expand Down
13 changes: 13 additions & 0 deletions targets/stm32l432/linker/bootloader_stm32l4xx.ld
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ _estack = 0x2000c000;

_MIN_STACK_SIZE = 0x400;

/*
flash_cfg is for storing bootloader data, like last used firmware version.
bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin
*/

bootloader_configuration = 0x08000000 + 216*1024+8;

MEMORY
{
flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K
flash_cfg (rx) : ORIGIN = 0x08000000 + 216*1024+8, LENGTH = 2K-8
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
}
Expand All @@ -39,6 +47,11 @@ SECTIONS
_etext = .;
} >flash

.flag2 bootloader_configuration :
{
KEEP(*(.flag2)) ;
} > flash_cfg

_sidata = LOADADDR(.data);

.data :
Expand Down
13 changes: 13 additions & 0 deletions targets/stm32l432/linker/bootloader_stm32l4xx_extra.ld
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ _estack = 0x2000c000;

_MIN_STACK_SIZE = 0x400;

/*
flash_cfg is for storing bootloader data, like last used firmware version.
bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin
*/

bootloader_configuration = 0x08000000 + 216*1024+8;

MEMORY
{
flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K
flash_cfg (rx) : ORIGIN = 0x08000000 + 216*1024+8, LENGTH = 2K-8
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
}
Expand All @@ -39,6 +47,11 @@ SECTIONS
_etext = .;
} >flash

.flag2 bootloader_configuration :
{
KEEP(*(.flag2)) ;
} > flash_cfg

_sidata = LOADADDR(.data);

.data :
Expand Down
21 changes: 17 additions & 4 deletions targets/stm32l432/linker/stm32l4xx.ld
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ _estack = 0x2000c000;
_MIN_STACK_SIZE = 0x400;

/*
Memory layout of device:
20 KB 198KB-8 38 KB
| bootloader | application | secrets/data |
len | 20 KB/10p| 196KB-8-8/98p | 2kB/1p | 38 KB/19p |
pos | 0->20 KB | 20->216KB-8-8 | 216kB -> 218 kB | 218->256 KB |
posp | 0-10 | 10-113 | 113-114 | 113-128 |
desc | bootloader | application | bootloader data | secrets/data |

Last 8 bytes in application space are occupied by bootloader flags - app
authorization and bootloader activation flag.
*/

/* Current firmware version number is concatenated to the firmware code - see .flag marker */
/* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader */

MEMORY
{
flash (rx) : ORIGIN = 0x08005000, LENGTH = 198K - 8
flash (rx) : ORIGIN = 0x08000000 + 20K, LENGTH = 216K - 20K - 8
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
}
Expand Down Expand Up @@ -56,6 +63,12 @@ SECTIONS
_edata = .;
} >ram AT> flash

.flag :
{
. = ALIGN(8);
KEEP(*(.flag)) ;
} > flash

.bss :
{
. = ALIGN(4);
Expand Down
21 changes: 20 additions & 1 deletion targets/stm32l432/linker/stm32l4xx_extra.ld
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,22 @@ _estack = 0x2000c000;

_MIN_STACK_SIZE = 0x400;

/*
len | 32 KB/16p| 184KB-8-8/92p | 2kB/1p | 38 KB/19p |
pos | 0->32 KB | 32->216KB-8-8 | 216kB -> 218 kB | 218->256 KB |
posp | 0-16 | 16-113 | 113-114 | 113-128 |
desc | bootloader | application | bootloader data | secrets/data |

Last 8 bytes in application space are occupied by bootloader flags - app
authorization and bootloader activation flag.
*/

/* Current firmware version number is concatenated to the firmware code - see .flag marker */
/* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader */

MEMORY
{
flash (rx) : ORIGIN = 0x08008000, LENGTH = 186K - 8
flash (rx) : ORIGIN = 0x08000000 + 20K + 12K, LENGTH = 216K - 20K - 12K - 8
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
}
Expand Down Expand Up @@ -50,6 +63,12 @@ SECTIONS
_edata = .;
} >ram AT> flash

.flag :
{
. = ALIGN(8);
KEEP(*(.flag)) ;
} > flash

.bss :
{
. = ALIGN(4);
Expand Down
Loading