From b8a27eadca95670f6c1f3b12b0007ba1411bae05 Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Wed, 2 Jan 2019 20:59:37 -0500 Subject: [PATCH] small improvements --- targets/stm32l442/Makefile | 8 ++-- targets/stm32l442/bootloader/main.c | 14 +++---- targets/stm32l442/merge_hex.py | 19 ++++++--- targets/stm32l442/src/device.c | 16 ++++++++ targets/stm32l442/src/init.c | 1 - tools/solotool.py | 60 ++++++++++++++++++++++------- 6 files changed, 88 insertions(+), 30 deletions(-) diff --git a/targets/stm32l442/Makefile b/targets/stm32l442/Makefile index b038069..f65e709 100644 --- a/targets/stm32l442/Makefile +++ b/targets/stm32l442/Makefile @@ -12,17 +12,17 @@ all-locked: $(MAKE) -f application.mk -j8 solo.hex EXTRA_DEFINES='-DFLASH_ROP=2' debugboot-app: - $(MAKE) -f application.mk -j8 solo.hex DEBUG=1 \ + $(MAKE) -f application.mk -j8 solo.hex DEBUG=2 \ LDSCRIPT=linker/stm32l4xx_extra.ld EXTRA_DEFINES='-DAPPLICATION_START_PAGE=16 -DSOLO_HACKER' debugboot-boot: $(MAKE) -f bootloader.mk -j8 bootloader.hex DEBUG=1 \ LDSCRIPT=linker/bootloader_stm32l4xx_extra.ld EXTRA_DEFINES='-DAPPLICATION_START_PAGE=16 -DSOLO_HACKER' -boot: - $(MAKE) -f bootloader.mk -j8 bootloader.hex DEBUG=$(DEBUG) +boot-sig-checking: + $(MAKE) -f bootloader.mk -j8 bootloader.hex -boot-hacker: +boot-no-sig: $(MAKE) -f bootloader.mk -j8 bootloader.hex EXTRA_DEFINES='-DSOLO_HACKER' clean: diff --git a/targets/stm32l442/bootloader/main.c b/targets/stm32l442/bootloader/main.c index 19e930c..afdc15f 100644 --- a/targets/stm32l442/bootloader/main.c +++ b/targets/stm32l442/bootloader/main.c @@ -1,21 +1,21 @@ /* * Copyright (C) 2018 SoloKeys, Inc. - * + * * This file is part of Solo. - * + * * Solo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * Solo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with Solo. If not, see - * + * * This code is available under licenses for commercial use. * Please contact SoloKeys for more information. */ @@ -114,10 +114,10 @@ int main(int argc, char * argv[]) } else { + printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR); } start_bootloader: - usbhid_init(); printf1(TAG_GEN,"init usb\n"); @@ -155,7 +155,7 @@ int main(int argc, char * argv[]) device_reboot(); } #ifdef SOLO_HACKER - // Boot ST bootloader if button is held for 2s + // Boot ST bootloader if button is held for 5s if (!device_is_button_pressed()) { stboot_time = millis(); diff --git a/targets/stm32l442/merge_hex.py b/targets/stm32l442/merge_hex.py index 5e46e03..397a72b 100644 --- a/targets/stm32l442/merge_hex.py +++ b/targets/stm32l442/merge_hex.py @@ -1,21 +1,21 @@ # # Copyright (C) 2018 SoloKeys, Inc. -# +# # This file is part of Solo. -# +# # Solo is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # Solo is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with Solo. If not, see -# +# # This code is available under licenses for commercial use. # Please contact SoloKeys for more information. # @@ -59,6 +59,14 @@ for i in range(2, len(args)-1): print('merging %s with ' % (args[1]), args[i]) first.merge(IntelHex( args[i] ), overlap = 'replace') +first [ flash_addr(APPLICATION_END_PAGE-1) ] = 0x41 +first [ flash_addr(APPLICATION_END_PAGE-1)+1 ] = 0x41 + +first[AUTH_WORD_ADDR-4] = 0 +first[AUTH_WORD_ADDR-1] = 0 +first[AUTH_WORD_ADDR-2] = 0 +first[AUTH_WORD_ADDR-3] = 0 + first[AUTH_WORD_ADDR] = 0 first[AUTH_WORD_ADDR+1] = 0 first[AUTH_WORD_ADDR+2] = 0 @@ -69,6 +77,7 @@ first[AUTH_WORD_ADDR+5] = 0xff first[AUTH_WORD_ADDR+6] = 0xff first[AUTH_WORD_ADDR+7] = 0xff + if secret_attestation_key is not None: key = unhexlify(secret_attestation_key) diff --git a/targets/stm32l442/src/device.c b/targets/stm32l442/src/device.c index 94d024c..7bc5f48 100644 --- a/targets/stm32l442/src/device.c +++ b/targets/stm32l442/src/device.c @@ -124,6 +124,22 @@ void usb_init(void); void usbhid_init() { usb_init(); + +#if DEBUG_LEVEL>1 + wait_for_usb_tether(); +#endif + +} + +void wait_for_usb_tether() +{ + while (USBD_OK != CDC_Transmit_FS("tethered\r\n", 10) ) + ; + while (USBD_OK != CDC_Transmit_FS("tethered\r\n", 10) ) + ; + delay(10); + while (USBD_OK != CDC_Transmit_FS("tethered\r\n", 10) ) + ; } int usbhid_recv(uint8_t * msg) diff --git a/targets/stm32l442/src/init.c b/targets/stm32l442/src/init.c index 0004318..daa81d0 100644 --- a/targets/stm32l442/src/init.c +++ b/targets/stm32l442/src/init.c @@ -210,7 +210,6 @@ void usb_init() USBD_Composite_Set_Classes(&USBD_HID, &USBD_CDC); - // USBD_Composite_Set_Classes(&USBD_CDC, &USBD_CDC); in_endpoint_to_class[HID_EPIN_ADDR & 0x7F] = 0; out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0; diff --git a/tools/solotool.py b/tools/solotool.py index dbd5bc6..3a579eb 100644 --- a/tools/solotool.py +++ b/tools/solotool.py @@ -170,7 +170,10 @@ class SoloClient(): ret = data[0] if ret != CtapError.ERR.SUCCESS: - raise RuntimeError('Device returned non-success code %02x' % ret) + str = '' + if ret == CtapError.ERR.NOT_ALLOWED: + str = 'Out of bounds write' + raise RuntimeError('Device returned non-success code %02x: %s' % (ret,str)) return data[1:] @@ -184,7 +187,10 @@ class SoloClient(): ret = res.signature[0] if ret != CtapError.ERR.SUCCESS: - raise RuntimeError('Device returned non-success code %02x' % ret) + str = '' + if ret == CtapError.ERR.NOT_ALLOWED: + str = 'Out of bounds write' + raise RuntimeError('Device returned non-success code %02x: %s' % (ret,str)) return res.signature[1:] @@ -506,7 +512,7 @@ def attempt_to_find_device(p): return found def attempt_to_boot_bootloader(p): - print('Bootloader not active. Attempting to boot into bootloader mode...') + try: p.enter_solo_bootloader() except OSError: @@ -520,8 +526,8 @@ def attempt_to_boot_bootloader(p): print('Solo rebooted. Reconnecting...') time.sleep(.500) if not attempt_to_find_device(p): - print('Failed to reconnect!') - sys.exit(1) + raise RuntimeError('Failed to reconnect!') + def solo_main(): parser = argparse.ArgumentParser() @@ -636,10 +642,16 @@ def sign_main(): def use_dfu(args): fw = args.__dict__['[firmware]'] - dfu = DFUDevice() - try: - dfu.find(ser = args.dfu_serial) - except RuntimeError: + + for i in range(0,8): + dfu = DFUDevice() + try: + dfu.find(ser = args.dfu_serial) + except RuntimeError: + time.sleep(0.25) + dfu = None + + if dfu is None: print('No STU DFU device found. ') if args.dfu_serial: print('Serial number used: ', args.dfu_serial) @@ -652,7 +664,7 @@ def use_dfu(args): chunk = 2048 seg = ih.segments()[0] - size = sum([x[1] - x[0] for x in ih.segments()]) + size = sum([max(x[1] - x[0],chunk) for x in ih.segments()]) total = 0 t1 = time.time()*1000 @@ -672,20 +684,27 @@ def use_dfu(args): dfu.write_page(i,data) total += chunk progress = total/float(size)*100 + sys.stdout.write('downloading %.2f%% %08x - %08x ... \r' % (progress,i,i+page)) # time.sleep(0.100) # print('done') # print(dfu.read_mem(i,16)) t2 = time.time()*1000 - + print() print('time: %d ms' %(t2 - t1)) print('verifying...') + progress = 0 for start,end in ih.segments(): for i in range(start, end, chunk): data1 = (dfu.read_mem(i,2048)) data2 = ih.tobinarray(start=i,size = chunk) - assert(data1 == data2) + total += chunk + progress = total/float(size)*100 + sys.stdout.write('reading %.2f%% %08x - %08x ... \r' % (progress,i,i+page)) + if (end-start) == chunk: + assert(data1 == data2) + print() print('firmware readback verified.') if args.detach: dfu.detach() @@ -706,19 +725,31 @@ def programmer_main(): parser.add_argument("--disable", action="store_true", help = 'Disable the Solo bootloader. Cannot be undone. No future updates can be applied.') parser.add_argument("--detach", action="store_true", help = 'Detach from ST DFU and boot from main flash. Must be in DFU mode.') parser.add_argument("--dfu-serial", default='', help = 'Specify a serial number for a specific DFU device to connect to.') + parser.add_argument("--use-dfu", action="store_true", help = 'Boot to ST-DFU before continuing.') args = parser.parse_args() fw = args.__dict__['[firmware]'] p = SoloClient() + + + try: p.find_device() + if args.use_dfu: + print('entering dfu..') + try: + attempt_to_boot_bootloader(p) + p.enter_st_dfu() + except RuntimeError: + # already in DFU mode? + pass except RuntimeError: + print('No Solo device detected.') if fw or args.detach: use_dfu(args) sys.exit(0) else: - print('No Solo device detected.') sys.exit(1) if args.detach: @@ -732,6 +763,7 @@ def programmer_main(): p.set_reboot(False) if args.enter_bootloader: + print('Attempting to boot into bootloader mode...') attempt_to_boot_bootloader(p) sys.exit(0) @@ -758,10 +790,12 @@ def programmer_main(): p.version() except CtapError as e: if e.code == CtapError.ERR.INVALID_COMMAND: + print('Bootloader not active. Attempting to boot into bootloader mode...') attempt_to_boot_bootloader(p) else: raise(e) except ApduError: + print('Bootloader not active. Attempting to boot into bootloader mode...') attempt_to_boot_bootloader(p) if args.reset_only: