option to disable solo bootloader

This commit is contained in:
Conor Patrick 2018-12-05 00:14:28 -05:00
parent b9ebde22e5
commit beedc24839
6 changed files with 101 additions and 23 deletions

View File

@ -24,6 +24,7 @@ typedef enum
BootVersion = 0x44, BootVersion = 0x44,
BootReboot = 0x45, BootReboot = 0x45,
BootBootloader = 0x46, BootBootloader = 0x46,
BootDisable = 0x47,
} BootOperation; } BootOperation;
@ -46,12 +47,30 @@ static void erase_application()
} }
} }
#define LAST_ADDR (APPLICATION_END_ADDR-2048 + 8)
#define LAST_PAGE (APPLICATION_END_PAGE-1)
static void disable_bootloader()
{
uint8_t page[PAGE_SIZE];
memmove(page, (uint8_t*)LAST_ADDR, PAGE_SIZE);
memset(page+PAGE_SIZE -4, 0, 4);
flash_erase_page(LAST_PAGE);
flash_write(LAST_ADDR, page, PAGE_SIZE);
}
static void authorize_application() static void authorize_application()
{ {
uint32_t zero = 0; // uint32_t zero = 0;
uint32_t * ptr; // uint32_t * ptr;
ptr = (uint32_t *)AUTH_WORD_ADDR; // ptr = (uint32_t *)AUTH_WORD_ADDR;
flash_write((uint32_t)ptr, (uint8_t *)&zero, 4); // flash_write((uint32_t)ptr, (uint8_t *)&zero, 4);
uint8_t page[PAGE_SIZE];
if (is_authorized_to_boot())
return;
memmove(page, (uint8_t*)LAST_ADDR, PAGE_SIZE);
memset(page+PAGE_SIZE -8, 0, 4);
flash_erase_page(LAST_PAGE);
flash_write(LAST_ADDR, page, PAGE_SIZE);
} }
int is_authorized_to_boot() int is_authorized_to_boot()
@ -60,6 +79,12 @@ int is_authorized_to_boot()
return *auth == 0; return *auth == 0;
} }
int is_bootloader_disabled()
{
uint32_t * auth = (uint32_t *)(AUTH_WORD_ADDR+4);
return *auth == 0;
}
int bootloader_bridge(int klen, uint8_t * keyh) int bootloader_bridge(int klen, uint8_t * keyh)
{ {
static int has_erased = 0; static int has_erased = 0;
@ -150,7 +175,22 @@ int bootloader_bridge(int klen, uint8_t * keyh)
break; break;
case BootReboot: case BootReboot:
printf1(TAG_BOOT, "BootReboot.\r\n"); printf1(TAG_BOOT, "BootReboot.\r\n");
device_reboot(); REBOOT_FLAG = 1;
break;
case BootDisable:
printf1(TAG_BOOT, "BootDisable %08lx.\r\n", *(uint32_t *)(AUTH_WORD_ADDR+4));
if (req->payload[0] == 0xcd && req->payload[1] == 0xde
&& req->payload[2] == 0xba && req->payload[3] == 0xaa)
{
disable_bootloader();
version = 0;
u2f_response_writeback(&version,1);
}
else
{
version = CTAP2_ERR_OPERATION_DENIED;
u2f_response_writeback(&version,1);
}
break; break;
#ifdef SOLO_HACKER #ifdef SOLO_HACKER
case BootBootloader: case BootBootloader:

View File

@ -95,22 +95,26 @@ int main(int argc, char * argv[])
} }
} }
#ifdef SOLO_HACKER #ifdef SOLO_HACKER
if (!is_bootloader_disabled())
{
stboot_time = millis(); stboot_time = millis();
if ( RCC->CSR & (1<<29) )// check if there was independent watchdog reset if ( RCC->CSR & (1<<29) )// check if there was independent watchdog reset
{ {
RCC->CSR |= (1<<23); // clear reset flags RCC->CSR |= (1<<23); // clear reset flags
goto start_bootloader; goto start_bootloader;
} }
}
#endif #endif
if (boot && is_authorized_to_boot()) if (is_authorized_to_boot() && (boot || is_bootloader_disabled()))
{ {
BOOT_boot(); BOOT_boot();
} }
else else
{ {
printf1(TAG_RED,"Not authorized to boot\r\n"); printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR);
} }
start_bootloader: start_bootloader:
@ -156,7 +160,7 @@ int main(int argc, char * argv[])
{ {
stboot_time = millis(); stboot_time = millis();
} }
if ((millis() - stboot_time) > 2000) if ((millis() - stboot_time) > 5000)
{ {
boot_st_bootloader(); boot_st_bootloader();
} }

View File

@ -25,4 +25,9 @@ first[AUTH_WORD_ADDR+1] = 0
first[AUTH_WORD_ADDR+2] = 0 first[AUTH_WORD_ADDR+2] = 0
first[AUTH_WORD_ADDR+3] = 0 first[AUTH_WORD_ADDR+3] = 0
first[AUTH_WORD_ADDR+4] = 0xff
first[AUTH_WORD_ADDR+5] = 0xff
first[AUTH_WORD_ADDR+6] = 0xff
first[AUTH_WORD_ADDR+7] = 0xff
first.tofile(sys.argv[len(sys.argv)-1], format='hex') first.tofile(sys.argv[len(sys.argv)-1], format='hex')

View File

@ -170,7 +170,7 @@ void heartbeat()
{ {
state = !state; state = !state;
} }
if (but) led_rgb((val*b)); if (but) led_rgb(((val * r)<<8) | ((val*b) << 16) | (val*g));
else else
led_rgb(((val * g)<<8) | ((val*r) << 16) | (val*b)); led_rgb(((val * g)<<8) | ((val*r) << 16) | (val*b));
} }

View File

@ -20,8 +20,13 @@ static void flash_unlock()
// Locks flash and turns off DFU // Locks flash and turns off DFU
void flash_option_bytes_init(int boot_from_dfu) void flash_option_bytes_init(int boot_from_dfu)
{ {
#if DEBUG_LEVEL #ifndef FLASH_ROP
#define FLASH_ROP 0
#endif
#if FLASH_ROP == 0
uint32_t val = 0xfffff8aa; uint32_t val = 0xfffff8aa;
#elif FLASH_ROP == 2
uint32_t val = 0xfffff8cc;
#else #else
uint32_t val = 0xfffff8b9; uint32_t val = 0xfffff8b9;
#endif #endif

View File

@ -24,6 +24,7 @@ class SoloBootloader:
version = 0x44 version = 0x44
reboot = 0x45 reboot = 0x45
st_dfu = 0x46 st_dfu = 0x46
disable = 0x47
HIDCommandBoot = 0x50 HIDCommandBoot = 0x50
HIDCommandEnterBoot = 0x51 HIDCommandEnterBoot = 0x51
@ -136,21 +137,24 @@ class Programmer():
self.send_data_hid(CTAPHID.INIT, '\x11\x11\x11\x11\x11\x11\x11\x11') self.send_data_hid(CTAPHID.INIT, '\x11\x11\x11\x11\x11\x11\x11\x11')
self.send_data_hid(SoloBootloader.HIDCommandEnterBoot, '') self.send_data_hid(SoloBootloader.HIDCommandEnterBoot, '')
def is_solo_bootloader(self,):
try:
p.version()
return True
except CtapError as e:
if e.code == CtapError.ERR.INVALID_COMMAND:
pass
else:
raise (e)
return False
def enter_st_dfu(self,): def enter_st_dfu(self,):
""" """
If solo is configured as solo hacker or something similar, If solo is configured as solo hacker or something similar,
this command will tell the token to boot directly to the st DFU this command will tell the token to boot directly to the st DFU
so it can be reprogrammed. Warning, you could brick your device. so it can be reprogrammed. Warning, you could brick your device.
""" """
soloboot = False soloboot = self.is_solo_bootloader()
try:
p.version()
soloboot = True
except CtapError as e:
if e.code == CtapError.ERR.INVALID_COMMAND:
pass
else:
raise (e)
if soloboot or self.exchange == self.exchange_u2f: if soloboot or self.exchange == self.exchange_u2f:
req = Programmer.format_request(SoloBootloader.st_dfu) req = Programmer.format_request(SoloBootloader.st_dfu)
@ -158,6 +162,21 @@ class Programmer():
else: else:
self.send_only_hid(SoloBootloader.HIDCommandEnterSTBoot, '') self.send_only_hid(SoloBootloader.HIDCommandEnterSTBoot, '')
def disable_solo_bootloader(self,):
"""
Disables the Solo bootloader. Only do this if you want to void the possibility
of any updates.
If you've started from a solo hacker, make you you've programmed a final/production build!
"""
ret = self.exchange(SoloBootloader.disable, 0, b'\xcd\xde\xba\xaa') # magic number
if ret[0] != CtapError.ERR.SUCCESS:
print('Failed to disable bootloader')
return False
time.sleep(0.1)
self.exchange(SoloBootloader.reboot)
return True
def program_file(self,name): def program_file(self,name):
if name.lower().endswith('.json'): if name.lower().endswith('.json'):
@ -246,6 +265,7 @@ if __name__ == '__main__':
parser.add_argument("--reboot", action="store_true", help = 'Tell bootloader to reboot.') parser.add_argument("--reboot", action="store_true", help = 'Tell bootloader to reboot.')
parser.add_argument("--enter-bootloader", action="store_true", help = 'Don\'t write anything, try to enter bootloader. Typically only supported by Solo Hacker builds.') parser.add_argument("--enter-bootloader", action="store_true", help = 'Don\'t write anything, try to enter bootloader. Typically only supported by Solo Hacker builds.')
parser.add_argument("--st-dfu", action="store_true", help = 'Don\'t write anything, try to enter ST DFU. Warning, you could brick your Solo if you overwrite everything. You should reprogram the option bytes just to be safe (boot to Solo bootloader first, then run this command).') parser.add_argument("--st-dfu", action="store_true", help = 'Don\'t write anything, try to enter ST DFU. Warning, you could brick your Solo if you overwrite everything. You should reprogram the option bytes just to be safe (boot to Solo bootloader first, then run this command).')
parser.add_argument("--disable", action="store_true", help = 'Disable the Solo bootloader. Cannot be undone. No future updates can be applied.')
args = parser.parse_args() args = parser.parse_args()
print() print()
@ -271,6 +291,10 @@ if __name__ == '__main__':
p.enter_st_dfu() p.enter_st_dfu()
sys.exit(0) sys.exit(0)
if args.disable:
p.disable_solo_bootloader()
sys.exit(0)
try: try:
print('version is ', p.version()) print('version is ', p.version())
except CtapError as e: except CtapError as e: