This commit is contained in:
Conor Patrick 2018-12-03 20:06:44 -05:00
parent aece05b2e8
commit e107a9aa86
7 changed files with 213 additions and 192 deletions

View File

@ -44,7 +44,7 @@ void usbhid_close();
void main_loop_delay();
void heartbeat();
void bootloader_heartbeat();
void authenticator_read_state(AuthenticatorState * );
@ -94,13 +94,10 @@ void ctap_store_rk(int index,CTAP_residentKey * rk);
void ctap_load_rk(int index,CTAP_residentKey * rk);
void ctap_overwrite_rk(int index,CTAP_residentKey * rk);
// Boot laoder application
int bootloader_bridge(uint8_t klen, uint8_t * keyh);
// Trigger software reset
void device_reboot();
// for bootloader
int is_authorized_to_boot();
#endif

View File

@ -25,4 +25,6 @@
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len);
int bootloader_bridge(uint8_t klen, uint8_t * keyh);
#endif /* EXTENSIONS_H_ */

View File

@ -4,7 +4,8 @@ SZ=arm-none-eabi-size
AR=arm-none-eabi-ar
# ST related
SRC = bootloader/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
SRC = bootloader/main.c bootloader/bootloader.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 += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c)

View File

@ -0,0 +1,162 @@
#include <stdint.h>
#include <stdlib.h>
#include APP_CONFIG
#include "uECC.h"
#include "u2f.h"
#include "device.h"
#include "flash.h"
#include "crypto.h"
#include "led.h"
#include "memory_layout.h"
#include "ctap_errors.h"
#include "log.h"
extern uint8_t REBOOT_FLAG;
typedef enum
{
BootWrite = 0x40,
BootDone = 0x41,
BootCheck = 0x42,
BootErase = 0x43,
BootVersion = 0x44,
} BootOperation;
typedef struct {
uint8_t op;
uint8_t addr[3];
uint8_t tag[4];
uint8_t len;
uint8_t payload[255 - 9];
} __attribute__((packed)) BootloaderReq;
static void erase_application()
{
int page;
for(page = APPLICATION_START_PAGE; page < APPLICATION_END_PAGE; page++)
{
flash_erase_page(page);
}
}
static void authorize_application()
{
uint32_t zero = 0;
uint32_t * ptr;
ptr = (uint32_t *)AUTH_WORD_ADDR;
flash_write((uint32_t)ptr, (uint8_t *)&zero, 4);
}
int is_authorized_to_boot()
{
uint32_t * auth = (uint32_t *)AUTH_WORD_ADDR;
return *auth == 0;
}
int bootloader_bridge(uint8_t klen, uint8_t * keyh)
{
static int has_erased = 0;
BootloaderReq * req = (BootloaderReq * )keyh;
uint8_t payload[256];
uint8_t hash[32];
uint8_t version = 1;
uint8_t * pubkey = (uint8_t*)"\x85\xaa\xce\xda\xd4\xb4\xd8\x0d\xf7\x0e\xe8\x91\x6d\x69\x8e\x00\x7a\x27\x40\x76\x93\x7a\x1d\x63\xb1\xcf\xe8\x22\xdd\x9f\xbc\x43\x3e\x34\x0a\x05\x9d\x8a\x9d\x72\xdc\xc2\x4b\x56\x9c\x64\x3d\xc1\x0d\x14\x64\x69\x52\x31\xd7\x54\xa3\xb6\x69\xa7\x6f\x6b\x81\x8d";
const struct uECC_Curve_t * curve = NULL;
if (req->len > 255-9)
{
return CTAP1_ERR_INVALID_LENGTH;
}
memset(payload, 0xff, sizeof(payload));
memmove(payload, req->payload, req->len);
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
uint32_t * ptr = (uint32_t *)addr;
switch(req->op){
case BootWrite:
printf1(TAG_BOOT, "BootWrite: %08lx\r\n",(uint32_t)ptr);
if ((uint32_t)ptr < APPLICATION_START_ADDR || (uint32_t)ptr >= APPLICATION_END_ADDR
|| ((uint32_t)ptr+req->len) > APPLICATION_END_ADDR)
{
printf1(TAG_BOOT,"Bound exceeded [%08lx, %08lx]\r\n",APPLICATION_START_ADDR,APPLICATION_END_ADDR);
return CTAP2_ERR_NOT_ALLOWED;
}
if (!has_erased || is_authorized_to_boot())
{
erase_application();
has_erased = 1;
}
if (is_authorized_to_boot())
{
printf2(TAG_ERR, "Error, boot check bypassed\n");
exit(1);
}
flash_write((uint32_t)ptr,payload, req->len);
break;
case BootDone:
printf1(TAG_BOOT, "BootDone: ");
dump_hex1(TAG_BOOT, payload, 32);
ptr = (uint32_t *)APPLICATION_START_ADDR;
crypto_sha256_init();
crypto_sha256_update((uint8_t*)ptr, APPLICATION_END_ADDR-APPLICATION_START_ADDR);
crypto_sha256_final(hash);
curve = uECC_secp256r1();
if (! uECC_verify(pubkey,
hash,
32,
payload,
curve))
{
return CTAP2_ERR_OPERATION_DENIED;
}
authorize_application();
REBOOT_FLAG = 1;
break;
case BootCheck:
return 0;
break;
case BootErase:
printf1(TAG_BOOT, "BootErase.\r\n");
erase_application();
return 0;
break;
case BootVersion:
printf1(TAG_BOOT, "BootVersion.\r\n");
u2f_response_writeback(&version,1);
return 0;
break;
default:
return CTAP1_ERR_INVALID_COMMAND;
}
return 0;
}
void bootloader_heartbeat()
{
static int state = 0;
static uint32_t val = 0x10;
if (state)
{
val--;
}
else
{
val++;
}
if (val > 30 || val < 1)
{
state = !state;
}
led_rgb((val * 3)<<8 | (val*10) << 16);
}

View File

@ -22,11 +22,6 @@
#define DISABLE_CTAPHID_WINK
#define DISABLE_CTAPHID_CBOR
void printing_init();
void hw_init(void);
//#define TEST
//#define TEST_POWER
#define LED_INIT_VALUE 0x101000
@ -37,4 +32,13 @@ void hw_init(void);
#define SKIP_BUTTON_CHECK_WITH_DELAY 0
#define SKIP_BUTTON_CHECK_FAST 1
void printing_init();
void hw_init(void);
// Trigger software reset
void device_reboot();
int is_authorized_to_boot();
void bootloader_heartbeat();
#endif

View File

@ -18,30 +18,11 @@
#include "ctaphid.h"
#include "ctap.h"
#include "crypto.h"
#include "uECC.h"
#include "u2f.h"
#include "memory_layout.h"
#define PAGE_SIZE 2048
#define PAGES 128
// Pages 119-127 are data
#define COUNTER2_PAGE (PAGES - 4)
#define COUNTER1_PAGE (PAGES - 3)
#define STATE2_PAGE (PAGES - 2)
#define STATE1_PAGE (PAGES - 1)
#define RK_NUM_PAGES 10
#define RK_START_PAGE (PAGES - 14)
#define RK_END_PAGE (PAGES - 14 + RK_NUM_PAGES)
#define APPLICATION_START_PAGE (16)
#define APPLICATION_START_ADDR flash_addr(APPLICATION_START_PAGE)
#define APPLICATION_END_PAGE ((PAGES - 19)) // 119 is NOT included in application
#define APPLICATION_END_ADDR (flash_addr(APPLICATION_END_PAGE)-8) // NOT included in application
#define AUTH_WORD_ADDR (flash_addr(APPLICATION_END_PAGE)-8)
uint32_t __90_ms = 0;
uint32_t __device_status = 0;
@ -509,162 +490,3 @@ void _Error_Handler(char *file, int line)
{
}
}
#ifdef IS_BOOTLOADER
extern uint8_t REBOOT_FLAG;
typedef enum
{
BootWrite = 0x40,
BootDone = 0x41,
BootCheck = 0x42,
BootErase = 0x43,
BootVersion = 0x44,
} BootOperation;
typedef struct {
uint8_t op;
uint8_t addr[3];
uint8_t tag[4];
uint8_t len;
uint8_t payload[255 - 9];
} __attribute__((packed)) BootloaderReq;
//#define APPLICATION_START_ADDR 0x8000
//#define APPLICATION_START_PAGE (0x8000/PAGE_SIZE)
//#define APPLICATION_END_ADDR (PAGE_SIZE*125-4) // NOT included in application
static void erase_application()
{
int page;
for(page = APPLICATION_START_PAGE; page < APPLICATION_END_PAGE; page++)
{
flash_erase_page(page);
}
}
static void authorize_application()
{
uint32_t zero = 0;
uint32_t * ptr;
ptr = (uint32_t *)AUTH_WORD_ADDR;
flash_write((uint32_t)ptr, (uint8_t *)&zero, 4);
}
int is_authorized_to_boot()
{
uint32_t * auth = (uint32_t *)AUTH_WORD_ADDR;
return *auth == 0;
}
int bootloader_bridge(uint8_t klen, uint8_t * keyh)
{
static int has_erased = 0;
BootloaderReq * req = (BootloaderReq * )keyh;
uint8_t payload[256];
uint8_t hash[32];
uint8_t version = 1;
uint8_t * pubkey = (uint8_t*)"\x85\xaa\xce\xda\xd4\xb4\xd8\x0d\xf7\x0e\xe8\x91\x6d\x69\x8e\x00\x7a\x27\x40\x76\x93\x7a\x1d\x63\xb1\xcf\xe8\x22\xdd\x9f\xbc\x43\x3e\x34\x0a\x05\x9d\x8a\x9d\x72\xdc\xc2\x4b\x56\x9c\x64\x3d\xc1\x0d\x14\x64\x69\x52\x31\xd7\x54\xa3\xb6\x69\xa7\x6f\x6b\x81\x8d";
const struct uECC_Curve_t * curve = NULL;
if (req->len > 255-9)
{
return CTAP1_ERR_INVALID_LENGTH;
}
memset(payload, 0xff, sizeof(payload));
memmove(payload, req->payload, req->len);
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
uint32_t * ptr = (uint32_t *)addr;
switch(req->op){
case BootWrite:
printf1(TAG_BOOT, "BootWrite: %08lx\r\n",(uint32_t)ptr);
if ((uint32_t)ptr < APPLICATION_START_ADDR || (uint32_t)ptr >= APPLICATION_END_ADDR
|| ((uint32_t)ptr+req->len) > APPLICATION_END_ADDR)
{
printf1(TAG_BOOT,"Bound exceeded [%08lx, %08lx]\r\n",APPLICATION_START_ADDR,APPLICATION_END_ADDR);
return CTAP2_ERR_NOT_ALLOWED;
}
if (!has_erased || is_authorized_to_boot())
{
erase_application();
has_erased = 1;
}
if (is_authorized_to_boot())
{
printf2(TAG_ERR, "Error, boot check bypassed\n");
exit(1);
}
flash_write((uint32_t)ptr,payload, req->len);
break;
case BootDone:
printf1(TAG_BOOT, "BootDone: ");
dump_hex1(TAG_BOOT, payload, 32);
ptr = (uint32_t *)APPLICATION_START_ADDR;
crypto_sha256_init();
crypto_sha256_update((uint8_t*)ptr, APPLICATION_END_ADDR-APPLICATION_START_ADDR);
crypto_sha256_final(hash);
curve = uECC_secp256r1();
if (! uECC_verify(pubkey,
hash,
32,
payload,
curve))
{
return CTAP2_ERR_OPERATION_DENIED;
}
authorize_application();
REBOOT_FLAG = 1;
break;
case BootCheck:
return 0;
break;
case BootErase:
printf1(TAG_BOOT, "BootErase.\r\n");
erase_application();
return 0;
break;
case BootVersion:
printf1(TAG_BOOT, "BootVersion.\r\n");
u2f_response_writeback(&version,1);
return 0;
break;
default:
return CTAP1_ERR_INVALID_COMMAND;
}
return 0;
}
void bootloader_heartbeat()
{
static int state = 0;
static uint32_t val = 0x10;
int but = IS_BUTTON_PRESSED();
if (state)
{
val--;
}
else
{
val++;
}
if (val > 30 || val < 1)
{
state = !state;
}
led_rgb((val * 3)<<8 | (val*10) << 16);
}
#endif

View File

@ -0,0 +1,33 @@
#ifndef _MEMORY_LAYOUT_H_
#define _MEMORY_LAYOUT_H_
#define PAGE_SIZE 2048
#define PAGES 128
// Pages 119-127 are data
// Location of counter page and it's backup page
// The flash is wear leveled and counter should be fault tolerant
#define COUNTER2_PAGE (PAGES - 4)
#define COUNTER1_PAGE (PAGES - 3)
// State of FIDO2 application
#define STATE2_PAGE (PAGES - 2)
#define STATE1_PAGE (PAGES - 1)
// Storage of FIDO2 resident keys
#define RK_NUM_PAGES 10
#define RK_START_PAGE (PAGES - 14)
#define RK_END_PAGE (PAGES - 14 + RK_NUM_PAGES)
// Start of application code
#define APPLICATION_START_PAGE (16)
#define APPLICATION_START_ADDR flash_addr(APPLICATION_START_PAGE)
// End of application code. Leave some extra room for future data storage.
#define APPLICATION_END_PAGE ((PAGES - 19)) // 119 is NOT included in application
#define APPLICATION_END_ADDR (flash_addr(APPLICATION_END_PAGE)-8) // NOT included in application
// Bootloader state.
#define AUTH_WORD_ADDR (flash_addr(APPLICATION_END_PAGE)-8)
#endif