psram restore, soon sdcard recovery

This commit is contained in:
Peter D. Gray 2021-06-04 08:51:40 -04:00
parent 639409cd71
commit 7ec6093865
No known key found for this signature in database
GPG Key ID: F0E6CC6AFC16CF7B
22 changed files with 2248 additions and 125 deletions

View File

@ -26,15 +26,16 @@ TARGET_NAME = bootloader
# Source files. Important: Add them also to link-script.ld to control placement.
OBJS += startup.o assets/screens.o
OBJS += firewall.o main.o dispatch.o verify.o oled.o clocks.o storage.o constant_time.o rng.o ae.o
OBJS += delay.o gpio.o pins.o version.o sflash.o console.o psram.o
OBJS += delay.o gpio.o pins.o version.o console.o psram.o sdcard.o
OBJS += faster_sha256.o micro-ecc/uECC.o hal_glue.o
# Have to have copies of these because the DMA and interrupt stuff
# needs to be commented-out.
OBJS += stm32l4xx_hal_firewall.o stm32l4xx_hal_gpio.o stm32l4xx_hal_spi.o
OBJS += stm32l4xx_hal_rcc.o stm32l4xx_hal_rcc_ex.o
OBJS += stm32l4xx_hal_hash.o # stm32l4xx_hal_usart.o
OBJS += stm32l4xx_hal_hash.o
OBJS += stm32l4xx_hal_ospi.o
OBJS += stm32l4xx_hal_sd.o stm32l4xx_ll_sdmmc.o
#OBJS = $(addsuffix .o, $(basename $(C_SRCS) $(ASM_SRCS)))

View File

@ -0,0 +1 @@
../bootloader/README.md

View File

@ -2,6 +2,7 @@
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
*/
#include "constant_time.h"
#include "rng.h"
// check_all_ones()
//
@ -17,6 +18,7 @@ check_all_ones(const void *ptrV, int len)
rv &= *ptr;
}
rng_delay();
return (rv == 0xff);
}
@ -34,6 +36,7 @@ check_all_zeros(const void *ptrV, int len)
rv |= *ptr;
}
rng_delay();
return (rv == 0x00);
}
@ -53,6 +56,7 @@ check_equal(const void *aV, const void *bV, int len)
diff |= (left[i] ^ right[i]);
}
rng_delay();
return (diff == 0);
}

View File

@ -25,4 +25,14 @@ delay_ms(int ms)
}
}
// HAL_Delay()
//
// Replace HAL version which needs interrupts
//
void
HAL_Delay(uint32_t Delay)
{
delay_ms(Delay);
}
// EOF

View File

@ -229,6 +229,7 @@ firewall_dispatch(int method_num, uint8_t *buf_io, int len_in,
}
wipe_all_sram();
psram_wipe();
if(arg2 == 2) {
// need some time to show OLED contents
@ -240,8 +241,6 @@ firewall_dispatch(int method_num, uint8_t *buf_io, int len_in,
// NOT-REACHED (but ok if it does)
}
psram_wipe();
// wait for an interrupt which will never happen (ie. sleep)
LOCKUP_FOREVER()
break;
@ -266,7 +265,7 @@ firewall_dispatch(int method_num, uint8_t *buf_io, int len_in,
uint8_t fw_digest[32], world_digest[32];
// takes time, shows progress bar
checksum_flash(fw_digest, world_digest);
checksum_flash(fw_digest, world_digest, 0);
rv = ae_set_gpio_secure(world_digest);
@ -371,6 +370,10 @@ firewall_dispatch(int method_num, uint8_t *buf_io, int len_in,
rv = pin_long_secret(args);
break;
case 7: // new for Mk4
rv = pin_firmware_upgrade(args);
break;
default:
rv = ENOENT;
break;

View File

@ -78,6 +78,15 @@ gpio_setup(void)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, 0); // turn LED off
}
// SD card detect switch: PC13
{ GPIO_InitTypeDef setup = {
.Pin = GPIO_PIN_13,
.Mode = GPIO_MODE_INPUT,
.Pull = GPIO_PULLUP,
.Speed = GPIO_SPEED_FREQ_LOW,
};
HAL_GPIO_Init(GPIOC, &setup);
}
#if 0

View File

@ -179,4 +179,9 @@ HAL_StatusTypeDef HAL_PWREx_ControlVoltageScaling(uint32_t VoltageScaling)
return HAL_OK;
}
__weak void HAL_SDEx_DriveTransceiver_1_8V_Callback(FlagStatus status)
{
// unused?
}

View File

@ -24,8 +24,9 @@
#include "pins.h"
#include "verify.h"
#include "storage.h"
#include "sflash.h"
//#include "sflash.h"
#include "psram.h"
#include "sdcard.h"
#include "dispatch.h"
#include "constant_time.h"
#include "assets/screens.h"
@ -46,7 +47,7 @@ reboot_seed_setup(void)
extern uint8_t reboot_seed_base[1024]; // see link-script.ld
// lots of manual memory alloc here...
uint8_t *reboot_seed = &reboot_seed_base[0]; // 32 bytes
uint8_t *reboot_seed = &reboot_seed_base[0]; // 32 bytes
// populate seed w/ some noise
ASSERT(((uint32_t)reboot_seed) == 0x20001c00);
@ -147,10 +148,15 @@ system_startup(void)
puts2("AE setup: ");
// secure element setup
ae_setup();
ae_set_gpio(0); // not checking return on purpose
ae_set_gpio(0); // not checking return on purpose XXX maybe move elsewhere/skip?
puts("done");
if(sdcard_is_inserted()) {
puts2("SDCard: ");
sdcard_setup();
}
#if 0
{ uint8_t config[128] = {0};
int x = ae_config_read(config);
@ -168,23 +174,30 @@ system_startup(void)
// - may also do one-time setup of 508a
// - note: ae_setup must already be called, since it can talk to that
flash_setup();
puts("flash setup done");
// maybe upgrade to a firmware image found in sflash
sf_firmware_upgrade();
puts("Flash: setup done");
//puts("PSRAM setup");
psram_setup();
// Check firmware is legit; else enter DFU
// - may die due to downgrade attack or unsigned/badly signed image
// - may die due to downgrade attack or badly signed image
puts2("Verify: ");
verify_firmware();
bool main_ok = verify_firmware();
// load a blank screen, so that if the firmware crashes, we are showing
// something reasonable and not misleading.
oled_show(screen_blankish);
if(main_ok) {
// load a blank screen, so that if the firmware crashes, we are showing
// something reasonable and not misleading.
oled_show(screen_blankish);
return;
}
// try to recover, from an image hanging around in PSRAM
// .. will reboot if it works; only helps w/ reset pulses, not power downs.
psram_recover_firmware();
// plan B?
enter_dfu();
}
// fatal_error(const char *msg)

View File

@ -14,6 +14,7 @@
#include "constant_time.h"
#include "storage.h"
#include "clocks.h"
#include "psram.h"
// Number of iterations for KDF
#define KDF_ITER_WORDS 12
@ -1187,7 +1188,7 @@ pin_firmware_greenlight(pinAttempt_t *args)
// step 1: calc the value to use
uint8_t fw_check[32], world_check[32];
checksum_flash(fw_check, world_check);
checksum_flash(fw_check, world_check, 0);
// step 2: write it out to chip.
if(warmup_ae()) return EPIN_I_AM_BRICK;
@ -1215,5 +1216,88 @@ pin_firmware_greenlight(pinAttempt_t *args)
return 0;
}
// pin_firmware_upgrade()
//
// Update the system firmware via file in PSRAM. Arrange for
// light to stay green through out process.
//
int
pin_firmware_upgrade(pinAttempt_t *args)
{
// Validate args and signature
int rv = _validate_attempt(args, false);
if(rv) return rv;
if((args->state_flags & PA_SUCCESSFUL) != PA_SUCCESSFUL) {
// must come here with a successful PIN login
return EPIN_WRONG_SUCCESS;
}
if(args->change_flags != CHANGE_FIRMWARE) {
return EPIN_BAD_REQUEST;
}
// expecting start/length relative to psram start
uint32_t *about = (uint32_t *)args->secret;
uint32_t start = about[0];
uint32_t len = about[1];
if(len < 32768) return EPIN_RANGE_ERR;
if(len > 2<<20) return EPIN_RANGE_ERR;
if(start+len > PSRAM_SIZE) return EPIN_RANGE_ERR;
const uint8_t *data = (const uint8_t *)PSRAM_BASE+start;
// verify a firmware image that's in RAM, and calc its digest
// - also applies watermark policy, etc
uint8_t world_check[32];
bool ok = verify_firmware_in_ram(data, len, world_check);
if(!ok) {
return EPIN_AUTH_FAIL;
}
// load existing PIN's hash
uint8_t digest[32];
pin_cache_restore(args, digest);
// step 1: calc the value to use, see above
// step 2: write it out to chip.
if(warmup_ae()) return EPIN_I_AM_BRICK;
// under duress, we can't fake this, but we go through the motions,
bool is_duress = get_is_duress(args);
if(!is_duress) {
rv = ae_encrypted_write(KEYNUM_firmware, KEYNUM_main_pin, digest, world_check, 32);
if(rv) {
ae_reset_chip();
return EPIN_AE_FAIL;
}
}
// turn on light? maybe not idk
rv = ae_set_gpio_secure(world_check);
if(rv) {
ae_reset_chip();
return EPIN_AE_FAIL;
}
// -- point of no return --
// TODO backup to SPI flash??
// TODO backup to SPI flash??
// TODO backup to SPI flash??
// burn it, shows progress
psram_do_upgrade(data, len);
// done
NVIC_SystemReset();
return 0;
}
// EOF

View File

@ -28,8 +28,9 @@
#define CHANGE_SECRET 0x008
#define CHANGE_DURESS_SECRET 0x010
#define CHANGE_SECONDARY_WALLET_PIN 0x020 // when used from main wallet only (obsolete)
#define CHANGE_FIRMWARE 0x040 // when providing firmware via PSRAM
#define CHANGE_LS_OFFSET 0xf00 // v2: which 32-byte part of long-secret to affect
#define CHANGE__MASK 0xf3f
#define CHANGE__MASK 0xf7f
// Magic value and/or version number.
#define PA_MAGIC_V1 0x2eaf6311 // before v3.0.0 of main firmware (508a, mk1/2)
@ -115,4 +116,7 @@ int pin_prefix_words(const char *pin_prefix, int prefix_len, uint32_t *result);
// Read/write the long secret. 32 bytes at a time.
int pin_long_secret(pinAttempt_t *args);
// Start firmware upgrade using data in PSRAM.
int pin_firmware_upgrade(pinAttempt_t *args);
// EOF

View File

@ -2,32 +2,45 @@
* (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
*
* Setup and talk with the ESP-PSRAM64H chip, new on Mk4.
* See stm32l4xx_hal_ospi.h
*
* CAUTION: All writes must be word aligned.
*
* CAUTION: All writes must be word aligned. Unaligned read okay.
*
*/
#include "psram.h"
#include "oled.h"
#include "clocks.h"
#include "sigheader.h"
#include "ae.h"
#include "ae_config.h"
#include "assets/screens.h"
#include <string.h>
#include "delay.h"
#include "rng.h"
#include "storage.h"
#include "sigheader.h"
#include "stm32l4xx_hal.h"
#include "verify.h"
#include "console.h"
#include "faster_sha256.h"
#include "misc.h"
#undef INCL_SELFTEST
uint8_t psram_chip_eid[8];
#ifdef INCL_SELFTEST
static void psram_memtest(bool simple);
#endif
// Stash some data in PSRAM to survive brief power outages
#define RECHDR_POS (recovery_header_t *)(PSRAM_BASE + PSRAM_SIZE - 2048)
#define RECHDR_MAGIC1 0xdbcc8350
#define RECHDR_MAGIC2 0xbafcfba3
typedef struct {
uint32_t magic1;
const uint8_t *start;
uint32_t size;
uint32_t magic2;
} recovery_header_t;
// psram_send_byte()
//
void
@ -118,6 +131,7 @@ psram_setup(void)
// Read Electronic ID
// - length not clear from datasheet, but repeats after 8 bytes
uint8_t psram_chip_eid[8];
{ OSPI_RegularCmdTypeDef cmd = {
.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG,
@ -140,10 +154,11 @@ psram_setup(void)
if(rv != HAL_OK) goto fail;
}
puts2("PSRAM EID: ");
hex_dump(psram_chip_eid, sizeof(psram_chip_eid));
//puts2("PSRAM EID: ");
//hex_dump(psram_chip_eid, sizeof(psram_chip_eid));
ASSERT(psram_chip_eid[0] == 0x0d);
ASSERT(psram_chip_eid[1] == 0x5d);
// .. other bits seem pretty similar between devices, they don't claim they are UUID
// Put into Quad mode
psram_send_byte(&qh, 0x35, false); // 0x35 = Enter Quad Mode
@ -234,6 +249,106 @@ psram_wipe(void)
puts("done");
}
// recover_from_psram()
//
// Try to recover from interrupt PSRAM-based firmware upgrade.
//
bool
psram_recover_firmware(void)
{
volatile recovery_header_t *h = RECHDR_POS;
// Check header is valid.
if( (h->magic1 != RECHDR_MAGIC1)
|| (h->magic2 != RECHDR_MAGIC2)
|| ((uint32_t)h->start < PSRAM_BASE)
|| ((uint32_t)h->start >= PSRAM_BASE+(PSRAM_SIZE/2))
|| (h->size > FW_MAX_LENGTH_MK4)
|| (h->size < FW_MIN_LENGTH)
) {
puts("PSR: nada");
return false;
}
// Re-verify bytes and factory signature; will catch any bitrot in our
// PSRAM copy of firmware
uint8_t world_check[32];
bool ok = verify_firmware_in_ram(h->start, h->size, world_check);
if(!ok) {
puts("PSR: !check");
return false;
}
// Check we have the **right** firmware, based on the world check sum
// but don't set the light at this point.
// - this includes check over bootrom (ourselves)
ae_setup();
ae_pair_unlock();
if(ae_checkmac_hard(KEYNUM_firmware, world_check) != 0) {
puts("PSR: version");
return false;
}
// Re-do the upgrade.
psram_do_upgrade(h->start, h->size);
// done
NVIC_SystemReset();
// not-reached
return true;
}
// psram_do_upgrade()
//
// Copy from PSRAM to real flash, at final executable location.
//
// NOTE: incoming start address is typically not aligned.
//
void
psram_do_upgrade(const uint8_t *start, uint32_t size)
{
ASSERT(size >= FW_MIN_LENGTH);
// In case of reset/crash, we can recover, so save
// what we need for that -- yes, we will re-verify signatures
volatile recovery_header_t *h = RECHDR_POS;
h->start = start;
h->size = size;
h->magic1 = RECHDR_MAGIC1;
h->magic2 = RECHDR_MAGIC2;
flash_setup0();
flash_unlock();
int rv;
// one uint64_t at a time = 8 bytes
uint64_t tmp;
for(uint32_t pos=0; pos < size; pos += 8) {
uint32_t dest = FIRMWARE_START+pos;
if(dest % (4*FLASH_PAGE_SIZE) == 0) {
// show some progress
oled_show_progress(screen_upgrading, pos*100/size);
}
if(dest % FLASH_PAGE_SIZE == 0) {
// page erase as we go
rv = flash_page_erase(dest);
ASSERT(rv == 0);
}
memcpy(&tmp, start+pos, 8);
rv = flash_burn(dest, tmp);
ASSERT(rv == 0);
}
flash_lock();
}
#ifdef INCL_SELFTEST
// psram_memtest()
//
@ -283,3 +398,4 @@ psram_memtest(bool simple)
#endif
// EOF

View File

@ -8,11 +8,12 @@
#define PSRAM_BASE 0x90000000
#define PSRAM_SIZE 0x00800000
// 8 bytes of unique data from chip
extern uint8_t psram_chip_eid[8];
extern void psram_setup(void);
extern void psram_wipe(void);
bool psram_recover_firmware(void);
void psram_do_upgrade(const uint8_t *start, uint32_t size);
// EOF

View File

@ -0,0 +1,114 @@
/*
* (c) Copyright 2021 by Coinkite Inc. This file is covered by license found in COPYING-CC.
*
* Setup and read from the SD Card. Used in recovery mode only.
*
*/
#include "oled.h"
#include "clocks.h"
#include "sigheader.h"
#include "assets/screens.h"
#include <string.h>
#include "delay.h"
#include "rng.h"
#include "storage.h"
#include "sigheader.h"
#include "stm32l4xx_hal.h"
#include "verify.h"
#include "console.h"
#include "misc.h"
#include "sdcard.h"
#include "psram.h"
SD_HandleTypeDef hsd;
// sdcard_setup()
//
void
sdcard_setup(void)
{
// pinout setup
__HAL_RCC_SDMMC1_CLK_ENABLE();
// Configure pins: Port C: C8-C13, PD2=CMD
// - C7 (light), and C13 (detect) setup in gpio_setup
{ GPIO_InitTypeDef setup = {
.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12,
.Mode = GPIO_MODE_AF_PP, // not sure
.Pull = GPIO_PULLUP,
.Speed = GPIO_SPEED_FREQ_VERY_HIGH,
.Alternate = GPIO_AF12_SDMMC1,
};
HAL_GPIO_Init(GPIOC, &setup);
}
// PD2 = CMD
{ GPIO_InitTypeDef setup = {
.Pin = GPIO_PIN_2,
.Mode = GPIO_MODE_AF_PP, // not sure
.Pull = GPIO_PULLUP,
.Speed = GPIO_SPEED_FREQ_VERY_HIGH,
.Alternate = GPIO_AF12_SDMMC1,
};
HAL_GPIO_Init(GPIOD, &setup);
}
// reset module
__HAL_RCC_SDMMC1_FORCE_RESET();
__HAL_RCC_SDMMC1_RELEASE_RESET();
sdcard_probe();
}
bool
sdcard_probe(void)
{
memset(&hsd, 0, sizeof(SD_HandleTypeDef));
puts2("SDCard: ");
hsd.Instance = SDMMC1;
hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE;
hsd.Init.BusWide = SDMMC_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV;
int rv = HAL_SD_Init(&hsd);
if(rv != HAL_OK) {
puts("init fail");
return false;
}
// configure the SD bus width for 4-bit wide operation
rv = HAL_SD_ConfigWideBusOperation(&hsd, SDMMC_BUS_WIDE_4B);
if(rv != HAL_OK) {
puts("wide");
return false;
}
uint8_t blk[512];
rv = HAL_SD_ReadBlocks(&hsd, blk, 0, 1, 60000);
if(rv != HAL_OK) {
puts("read fail");
return false;
}
puts("ok");
hex_dump(blk, 512);
return true;
}
// sdcard_is_inserted()
//
bool
sdcard_is_inserted(void)
{
return !!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
}
// EOF

View File

@ -0,0 +1,7 @@
#pragma once
void sdcard_setup(void);
bool sdcard_is_inserted(void);
bool sdcard_probe(void);

View File

@ -336,6 +336,7 @@ sf_calc_checksum(const coldcardFirmwareHeader_t *hdr, uint8_t fw_digest[32])
sha256_final(&ctx, fw_digest);
}
#if 0
// sf_firmware_upgrade()
//
// maybe upgrade to a firmware image found in sflash
@ -355,7 +356,6 @@ sf_firmware_upgrade(void)
if(!verify_header(&hdr)) {
// something wrong with it. might be noise, blank or otherwise. Not an error.
puts("SPI flash: nope");
return;
}
@ -432,5 +432,6 @@ puts("SPI flash: nope");
// Tell python, ultimately, that it worked.
shared_bootflags |= RBF_FRESH_VERSION;
}
#endif
// EOF

View File

@ -75,7 +75,7 @@
#define HAL_RNG_MODULE_ENABLED
//#define HAL_RTC_MODULE_ENABLED
//#define HAL_SAI_MODULE_ENABLED
//#define HAL_SD_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
//#define HAL_SMARTCARD_MODULE_ENABLED
//#define HAL_SMBUS_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED

View File

@ -311,8 +311,10 @@ static uint32_t SD_WideBus_Enable (SD_HandleTypeDef *hsd);
static uint32_t SD_WideBus_Disable(SD_HandleTypeDef *hsd);
static uint32_t SD_FindSCR (SD_HandleTypeDef *hsd, uint32_t *pSCR);
static void SD_PowerOFF (SD_HandleTypeDef *hsd);
#if 0
static void SD_Write_IT (SD_HandleTypeDef *hsd);
static void SD_Read_IT (SD_HandleTypeDef *hsd);
#endif
#if !defined(STM32L4P5xx) && !defined(STM32L4Q5xx) && !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx)
static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void SD_DMAReceiveCplt (DMA_HandleTypeDef *hdma);
@ -1693,6 +1695,7 @@ HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, ui
}
}
#if 0
/**
* @brief This function handles SD card interrupt request.
* @param hsd Pointer to SD handle
@ -2001,6 +2004,7 @@ void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd)
/* Nothing to do */
}
}
#endif
/**
* @brief return the SD state
@ -4018,6 +4022,7 @@ static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR)
return HAL_SD_ERROR_NONE;
}
#if 0
/**
* @brief Wrap up reading in non-blocking mode.
* @param hsd pointer to a SD_HandleTypeDef structure that contains
@ -4056,7 +4061,9 @@ static void SD_Read_IT(SD_HandleTypeDef *hsd)
hsd->RxXferSize = dataremaining;
}
}
#endif
#if 0
/**
* @brief Wrap up writing in non-blocking mode.
* @param hsd pointer to a SD_HandleTypeDef structure that contains
@ -4095,6 +4102,7 @@ static void SD_Write_IT(SD_HandleTypeDef *hsd)
hsd->TxXferSize = dataremaining;
}
}
#endif
#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx)
/**

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,16 @@
#include "stm32l4xx_hal.h"
#include "constant_time.h"
const uint32_t num_pages_locked = ((BL_FLASH_SIZE + BL_NVROM_SIZE) / 0x800)-1; // == 15
#if defined (STM32L4P5xx) || defined (STM32L4Q5xx) || defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
#define FLASH_NB_DOUBLE_WORDS_IN_ROW 64
#else
#define FLASH_NB_DOUBLE_WORDS_IN_ROW 32
#endif
// Number of flash pages to write-protect (ie. our size in flash pages)
// - written into FLASH->WRP1AR
// - once done, can't change bootrom via DFU (no error given, but doesn't change)
const uint32_t num_pages_locked = ((BL_FLASH_SIZE + BL_NVROM_SIZE) / FLASH_PAGE_SIZE)-1; // == 15
// flash_setup0()
//
@ -190,6 +199,55 @@ flash_burn(uint32_t address, uint64_t val)
return 0;
}
#if 0
// flash_burn_fast()
//
// My simplified version of FLASH_Program_Fast()
//
// NOTES:
// - this function **AND** everything it calls, must be in RAM
// - interrupts are already off here (entire bootloader)
// - return non-zero on failure; don't try to handle anything
// - needs 128 bytes
// - PROBLEM: Requires bank erase, and we can't do that in any case.
//
__attribute__((section(".ramfunc")))
__attribute__((noinline))
int
flash_burn_fast(uint32_t address, const uint32_t values[2*FLASH_NB_DOUBLE_WORDS_IN_ROW])
{
uint32_t rv;
// just in case?
_flash_wait_done();
// clear any and all errors
FLASH->SR = FLASH->SR & 0xffff;
// disable data cache
__HAL_FLASH_DATA_CACHE_DISABLE();
// Set FSTPG bit
SET_BIT(FLASH->CR, FLASH_CR_FSTPG);
for(int i=0; i<2*FLASH_NB_DOUBLE_WORDS_IN_ROW; i++, address++) {
*(__IO uint32_t *)(address) = values[i];
}
rv = _flash_wait_done();
if(rv) return rv;
// If the program operation is completed, disable the FSTPG Bit
CLEAR_BIT(FLASH->CR, FLASH_CR_FSTPG);
// Flush the caches to be sure of data consistency, and reenable.
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_DATA_CACHE_ENABLE();
return 0;
}
#endif
// flash_page_erase()
//
// See HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
@ -199,7 +257,7 @@ flash_burn(uint32_t address, uint64_t val)
int
flash_page_erase(uint32_t address)
{
uint32_t page_num = (address & 0x7ffffff) / FLASH_PAGE_SIZE; // 2k pages
uint32_t page_num = (address & 0x7ffffff) / FLASH_PAGE_SIZE;
// protect ourselves!
if(page_num < ((BL_FLASH_SIZE + BL_NVROM_SIZE) / FLASH_PAGE_SIZE)) {
@ -407,9 +465,13 @@ flash_setup(void)
STATIC_ASSERT(sizeof(rom_secrets_t) <= 2048);
// see if we have picked a pairing secret yet.
// NOTE: critical section for glitching (at least in past versions)
// - check_all.. functions have a rng_delay in them already
rng_delay();
bool blank_ps = check_all_ones(rom_secrets->pairing_secret, 32);
bool blank_xor = check_all_ones(rom_secrets->pairing_secret_xor, 32);
bool blank_ae = (~rom_secrets->ae_serial_number[0] == 0);
rng_delay();
if(blank_ps) {
// get some good entropy, save it.
@ -423,6 +485,7 @@ flash_setup(void)
// configure and lock-down the SE
int rv = ae_setup_config();
rng_delay();
if(rv) {
// Hardware fail speaking to AE chip ... be careful not to brick here.
// Do not continue!! We might fix the board, or add missing pullup, etc.
@ -432,6 +495,7 @@ flash_setup(void)
LOCKUP_FOREVER();
}
rng_delay();
if(blank_xor) {
// write secret again, complemented, to indicate successful AE programming
confirm_pairing_secret();
@ -444,6 +508,7 @@ flash_setup(void)
LOCKUP_FOREVER();
}
rng_delay();
if(!blank_ps && !blank_xor) {
// check the XOR value also written: 2 phase commit
uint8_t tmp[32];
@ -492,7 +557,6 @@ flash_lockdown_hard(uint8_t rdp_level_code)
FLASH->WRP2AR = 0xff; // unused.
FLASH->WRP2BR = 0xff; // unused.
#if 0
// PCRO = Proprietary Code Read-Out (protection)
// - isn't useful to us (doesn't protect data, exec-only code)
// - "In case the Level 1 is configured and no PCROP area is defined,
@ -500,50 +564,14 @@ flash_lockdown_hard(uint8_t rdp_level_code)
// the RDP level is decreased from Level 1 to Level 0)."
// - D-bus access blocked, even for code running inside the PCROP area! (AN4758)
// So literal values and constant tables and such would need special linking.
//
FLASH->PCROP1ER = (1<<31); // set PCROP_RDP bit, since maybe we need to?
FLASH->PCROP1SR = 0xffff;
FLASH->PCROP2ER = (1<<31); // set PCROP_RDP bit, since maybe we need to?
FLASH->PCROP2SR = 0xffff;
#endif
// set protection level
FLASH->OPTR = 0xffeff800 | rdp_level_code; // select level X, other values as observed
uint32_t was = FLASH->OPTR & ~0xff;
FLASH->OPTR = was | rdp_level_code; // select level X, other values as observed
flash_ob_lock(true);
}
#if 0
// backup_data_get()
//
uint32_t
backup_data_get(int idx)
{
ASSERT(idx < 32);
return (&RTC->BKP0R)[idx];
}
// backup_data_set()
//
void
backup_data_set(int idx, uint32_t new_value)
{
ASSERT(idx < 32);
// unlock sequence.
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
(&RTC->BKP0R)[idx] = new_value;
// relock (any value)
// doesn't seem to work tho? stays unlocked
RTC->WPR = 0xff;
}
#endif
// record_highwater_version()
//
int

View File

@ -48,26 +48,12 @@ static inline bool flash_is_security_level2(void) {
return ((FLASH->OPTR & FLASH_OPTR_RDP_Msk) == 0xCC);
}
#if 0
// We store some values in the RTC "backup" registers
// - these are protected against accidental writes
// - not cleared by system reset, full power cycle required
// - mpy code could still change, so not secure.
// - kinda pointless, but I have no SRAM that isn't wiped at boot
// - XXX not working! no clock maybe? Reads as zero.
#define IDX_WORD_LOOKUPS_USED 0x0
#define IDX_DURESS_USED 0x1
uint32_t backup_data_get(int idx);
void backup_data_set(int idx, uint32_t new_value);
#endif
// generial purpose flash functions
void flash_setup0(void);
void flash_lock(void);
void flash_unlock(void);
int flash_burn(uint32_t address, uint64_t val);
int flash_burn_fast(uint32_t address, const uint32_t values[128]);
int flash_page_erase(uint32_t address);
// write to OTP

View File

@ -6,6 +6,7 @@
*/
#include "basics.h"
#include "verify.h"
#include "psram.h"
#include "faster_sha256.h"
#include "assets/screens.h"
#include "oled.h"
@ -21,13 +22,14 @@
#include "firmware-keys.h"
// 2 megabyte on mk4
#define MAIN_FLASH_SIZE (2<<20)
// - less the LFS2 filesystem which contains settings and such that change at runtime normally.
#define MAIN_FLASH_SIZE ((2<<20) - (512*1024))
// actual qty of bytes we check
// - minus 64 because the firmware signature is skipped
// - 0x400 of OTP area
// - plus (0x28) twice for option bytes
// - plus complete "system meory" area (boot rom with DFU)
// - plus complete "system meory" area (STM boot rom containing DFU code)
// - 12 bytes of device serial number
#define TOTAL_CHECKSUM_LEN (MAIN_FLASH_SIZE - 64 + 0x400 + (0x28 *2) + 0x7000 + 12)
@ -56,7 +58,7 @@ checksum_more(SHA256_CTX *ctx, uint32_t *total, const uint8_t *addr, int len)
// checksum_flash()
//
void
checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32])
checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32], uint32_t fw_length)
{
const uint8_t *start = (const uint8_t *)FIRMWARE_START;
@ -64,21 +66,29 @@ checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32])
SHA256_CTX ctx;
uint32_t total_len = 0;
uint8_t first[32];
sha256_init(&ctx);
if(fw_length == 0) {
uint8_t first[32];
sha256_init(&ctx);
// start of firmware (just after we end) to header
checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64);
// use length from header in flash
fw_length = FW_HDR->firmware_length;
// from after header to end
checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE,
FW_HDR->firmware_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE));
// start of firmware (just after we end) to header
checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64);
sha256_final(&ctx, first);
// from after header to end
checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE,
fw_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE));
// double SHA256
sha256_single(first, sizeof(first), fw_digest);
sha256_final(&ctx, first);
// double SHA256
sha256_single(first, sizeof(first), fw_digest);
} else {
// fw_digest should already be populated by caller
total_len = fw_length - 64;
}
// start over, and get the rest of flash. All of it.
sha256_init(&ctx);
@ -91,7 +101,7 @@ checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32])
checksum_more(&ctx, &total_len, base, start-base);
// probably-blank area after firmware, and filesystem area
const uint8_t *fs = start + FW_HDR->firmware_length;
const uint8_t *fs = start + fw_length;
const uint8_t *last = base + MAIN_FLASH_SIZE;
checksum_more(&ctx, &total_len, fs, last-fs);
@ -168,19 +178,19 @@ check_is_downgrade(const uint8_t timestamp[8], const char *version)
return (memcmp(timestamp, min, 8) < 0);
}
// check_factory_key()
// warn_bad_checksum()
//
void
check_factory_key(uint32_t pubkey_num)
warn_bad_checksum(void)
{
if(IS_FACTORY_KEY(pubkey_num)) return;
// warn the victim/altcoin user/developer
// warn the victim about corrupted flash/ident info
#if RELEASE
const int wait = 100;
#else
const int wait = 1;
const int wait = 10;
#endif
puts("WARN: Bad firmware");
for(int i=0; i < wait; i++) {
oled_show_progress(screen_devmode, (i*100)/wait);
@ -220,13 +230,66 @@ verify_signature(const coldcardFirmwareHeader_t *hdr, const uint8_t fw_check[32]
hdr->signature, uECC_secp256k1());
//puts(ok ? "Sig ok" : "Sig fail");
rng_delay();
return ok;
}
// verify_firmware_in_ram()
//
// Check hdr, and even signature of protential new firmware in PSRAM.
// Returns checksum needed for 608
//
bool
verify_firmware_in_ram(const uint8_t *start, uint32_t len, uint8_t world_check[32])
{
const coldcardFirmwareHeader_t *hdr = (const coldcardFirmwareHeader_t *)
(start + FW_HEADER_OFFSET);
uint8_t fw_digest[32];
// check basics like verison, hw compat, etc
if(!verify_header(hdr)) goto fail;
if(check_is_downgrade(hdr->timestamp, (const char *)hdr->version_string)) {
puts("downgrade");
goto fail;
}
rng_delay();
SHA256_CTX ctx;
uint32_t total_len = 0;
sha256_init(&ctx);
// start of firmware up to header's signature
checksum_more(&ctx, &total_len, start, FW_HEADER_OFFSET + FW_HEADER_SIZE - 64);
// from after header to end
checksum_more(&ctx, &total_len, start + FW_HEADER_OFFSET + FW_HEADER_SIZE,
hdr->firmware_length - (FW_HEADER_OFFSET + FW_HEADER_SIZE));
// double SHA256
sha256_final(&ctx, fw_digest);
sha256_single(fw_digest, 32, fw_digest);
rng_delay();
if(!verify_signature(hdr, fw_digest)) {
puts("sig fail");
goto fail;
}
checksum_flash(fw_digest, world_check, hdr->firmware_length);
return true;
fail:
return false;
}
// verify_firmware()
//
void
bool
verify_firmware(void)
{
STATIC_ASSERT(sizeof(coldcardFirmwareHeader_t) == FW_HEADER_SIZE);
@ -241,15 +304,13 @@ verify_firmware(void)
// measure checksum
uint8_t fw_check[32], world_check[32];
checksum_flash(fw_check, world_check);
checksum_flash(fw_check, world_check, 0);
rng_delay();
// Verify the signature
// - use pubkey_num to pick a specific key
if(!verify_signature(FW_HDR, fw_check)) goto fail;
rng_delay();
// Push the hash to the SE which might make the Genuine light green,
// but only if we arrived at same hash before. It decides.
@ -257,30 +318,27 @@ verify_firmware(void)
rng_delay();
#if 0
// XXX change this, no more dev key
// maybe show big warning if not an "approved" key
// show big/slow warning if light is not green
if(not_green) {
check_factory_key(FW_HDR->pubkey_num);
warn_bad_checksum();
}
#endif
puts("good firmware");
oled_show_progress(screen_verify, 100);
return;
return true;
fail:
puts("corrupt firmware");
oled_show(screen_corrupt);
enter_dfu();
return;
return false;
blank:
puts("no firmware");
oled_show(screen_dfu);
enter_dfu();
return;
//enter_dfu();
return false;
}
// EOF

View File

@ -11,11 +11,13 @@
// The in-flash header.
#define FW_HDR ((coldcardFirmwareHeader_t *)(FIRMWARE_START + FW_HEADER_OFFSET))
// check we have something valid, and signed, in memory
extern void verify_firmware(void);
// check we have something valid, and signed, in memory. T if okay
bool verify_firmware(void);
// read and checksum over **all** of flash memory
void checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32]);
// - fw_length is length of firmware from it's header
// - if fw_length is nonzero, then use incoming fw_digest
void checksum_flash(uint8_t fw_digest[32], uint8_t world_digest[32], uint32_t fw_length);
// do some range/sanity checking on a signed header
bool verify_header(const coldcardFirmwareHeader_t *hdr);
@ -28,6 +30,9 @@ bool verify_signature(const coldcardFirmwareHeader_t *hdr, const uint8_t fw_chec
// check if proposed version is new enough (based on OTP values)
bool check_is_downgrade(const uint8_t timestamp[8], const char *version);
// verify a firmware image that's in RAM, and provide digest needed for 608
bool verify_firmware_in_ram(const uint8_t *start, uint32_t len, uint8_t world_check[32]);
// read what the watermark is, might be all zeros
void get_min_version(uint8_t min_version[8]);