diff --git a/fido2/extensions/extensions.c b/fido2/extensions/extensions.c index a84db8b..cc56d51 100644 --- a/fido2/extensions/extensions.c +++ b/fido2/extensions/extensions.c @@ -4,10 +4,12 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. + #include #include "extensions.h" #include "u2f.h" #include "wallet.h" +#include "solo.h" #include "device.h" #include "log.h" @@ -54,6 +56,8 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen ret = bootloader_bridge(klen, keyh); #elif defined(WALLET_EXTENSION) ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh); +#else + ret = bridge_u2f_to_solo(_chal, _appid, klen, keyh); #endif if (ret != 0) diff --git a/fido2/extensions/solo.c b/fido2/extensions/solo.c new file mode 100644 index 0000000..6b36fe2 --- /dev/null +++ b/fido2/extensions/solo.c @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#include +#include "extensions.h" +#include "u2f.h" +#include "wallet.h" +#include "device.h" +#include "ctap.h" +#include "ctap_errors.h" + +#include "log.h" +#include APP_CONFIG + +int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh) +{ + static uint8_t msg_buf[72]; + int reqlen = klen; + int i; + int8_t ret = 0; + + wallet_request * req = (wallet_request *) keyh; + + printf1(TAG_WALLET, "u2f-solo [%d]: ", reqlen); dump_hex1(TAG_WALLET, keyh, reqlen); + + switch(req->operation) + { + case WalletVersion: + msg_buf[0] = SOLO_VERSION_MAJ; + msg_buf[1] = SOLO_VERSION_MIN; + msg_buf[2] = SOLO_VERSION_PATCH; + u2f_response_writeback(msg_buf, 3); + break; + case WalletRng: + printf1(TAG_WALLET,"SoloRng\n"); + + ret = ctap_generate_rng(msg_buf, 72); + if (ret != 1) + { + printf1(TAG_WALLET,"Rng failed\n"); + ret = CTAP2_ERR_PROCESSING; + goto cleanup; + } + ret = 0; + + u2f_response_writeback((uint8_t *)msg_buf,72); + break; + + default: + printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation); + ret = CTAP1_ERR_INVALID_COMMAND; + break; + } + +cleanup: + + return ret; +} diff --git a/fido2/extensions/solo.h b/fido2/extensions/solo.h new file mode 100644 index 0000000..04e9d8d --- /dev/null +++ b/fido2/extensions/solo.h @@ -0,0 +1,27 @@ +/* + * 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. + */ +#ifndef SOLO_H_ +#define SOLO_H_ + +int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh); + +#endif diff --git a/targets/stm32l432/Makefile b/targets/stm32l432/Makefile index 017998f..9c23cec 100644 --- a/targets/stm32l432/Makefile +++ b/targets/stm32l432/Makefile @@ -2,30 +2,33 @@ ifndef DEBUG DEBUG=0 endif +APPMAKE=build/application.mk +BOOTMAKE=build/application.mk + merge_hex=python ../../tools/solotool.py mergehex all: - $(MAKE) -f application.mk -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DFLASH_ROP=1' + $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DFLASH_ROP=1' all-hacker: - $(MAKE) -f application.mk -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' + $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' all-locked: - $(MAKE) -f application.mk -j8 solo.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DFLASH_ROP=2' + $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DFLASH_ROP=2' debugboot-app: - $(MAKE) -f application.mk -j8 solo.hex DEBUG=2 PREFIX=$(PREFIX)\ + $(MAKE) -f $(APPMAKE) -j8 solo.hex DEBUG=2 PREFIX=$(PREFIX)\ LDSCRIPT=linker/stm32l4xx_extra.ld EXTRA_DEFINES='-DAPPLICATION_START_PAGE=16 -DSOLO_HACKER' debugboot-boot: - $(MAKE) -f bootloader.mk -j8 bootloader.hex PREFIX=$(PREFIX) DEBUG=1 \ + $(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) DEBUG=1 \ LDSCRIPT=linker/bootloader_stm32l4xx_extra.ld EXTRA_DEFINES='-DAPPLICATION_START_PAGE=16 -DSOLO_HACKER' boot-sig-checking: - $(MAKE) -f bootloader.mk -j8 bootloader.hex PREFIX=$(PREFIX) DEBUG=0 + $(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) DEBUG=0 boot-no-sig: - $(MAKE) -f bootloader.mk -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0 + $(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0 build-release-locked: clean2 boot-sig-checking clean all-locked $(merge_hex) solo.hex bootloader.hex all.hex @@ -38,12 +41,12 @@ build-hacker: clean2 boot-no-sig clean all-hacker $(merge_hex) solo.hex bootloader.hex all.hex clean: - $(MAKE) -f application.mk clean - $(MAKE) -f bootloader.mk clean + $(MAKE) -f $(APPMAKE) clean + $(MAKE) -f $(BOOTMAKE) clean clean2: rm -f solo.hex bootloader.hex all.hex - $(MAKE) -f application.mk clean - $(MAKE) -f bootloader.mk clean + $(MAKE) -f $(APPMAKE) clean + $(MAKE) -f $(BOOTMAKE) clean flash: solo.hex bootloader.hex diff --git a/targets/stm32l432/bootloader/bootloader.c b/targets/stm32l432/bootloader/bootloader.c index cc9cb85..1c619bc 100644 --- a/targets/stm32l432/bootloader/bootloader.c +++ b/targets/stm32l432/bootloader/bootloader.c @@ -4,6 +4,7 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. + #include #include @@ -176,8 +177,12 @@ int bootloader_bridge(int klen, uint8_t * keyh) case BootVersion: has_erased = 0; printf1(TAG_BOOT, "BootVersion.\r\n"); + version = BOOT_VERSION_MAJ; + u2f_response_writeback(&version,1); + version = BOOT_VERSION_MIN; + u2f_response_writeback(&version,1); + version = BOOT_VERSION_PATCH; u2f_response_writeback(&version,1); - return 0; break; case BootReboot: printf1(TAG_BOOT, "BootReboot.\r\n"); diff --git a/targets/stm32l432/bootloader/bootloader.h b/targets/stm32l432/bootloader/bootloader.h index 90c64fa..9335f8d 100644 --- a/targets/stm32l432/bootloader/bootloader.h +++ b/targets/stm32l432/bootloader/bootloader.h @@ -4,9 +4,11 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. + #ifndef _APP_H_ #define _APP_H_ #include +#include "version.h" #define DEBUG_UART USART1 @@ -50,6 +52,8 @@ #define SKIP_BUTTON_CHECK_WITH_DELAY 0 #define SKIP_BUTTON_CHECK_FAST 1 +#define SOLO_PRODUCT_NAME "Solo Bootloader " VERSION + void printing_init(); void hw_init(void); diff --git a/targets/stm32l432/application.mk b/targets/stm32l432/build/application.mk similarity index 93% rename from targets/stm32l432/application.mk rename to targets/stm32l432/build/application.mk index 89ece0d..8dd59b1 100644 --- a/targets/stm32l432/application.mk +++ b/targets/stm32l432/build/application.mk @@ -1,7 +1,4 @@ -CC=$(PREFIX)arm-none-eabi-gcc -CP=$(PREFIX)arm-none-eabi-objcopy -SZ=$(PREFIX)arm-none-eabi-size -AR=$(PREFIX)arm-none-eabi-ar +include build/common.mk # ST related SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c @@ -13,6 +10,7 @@ SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c) SRC += ../../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/extensions/extensions.c ../../fido2/extensions/solo.c # Crypto libs SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c @@ -45,7 +43,7 @@ endif DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES) # DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1 -CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW) -g +CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS) LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor diff --git a/targets/stm32l432/bootloader.mk b/targets/stm32l432/build/bootloader.mk similarity index 91% rename from targets/stm32l432/bootloader.mk rename to targets/stm32l432/build/bootloader.mk index 3931dde..0849086 100644 --- a/targets/stm32l432/bootloader.mk +++ b/targets/stm32l432/build/bootloader.mk @@ -1,7 +1,4 @@ -CC=$(PREFIX)arm-none-eabi-gcc -CP=$(PREFIX)arm-none-eabi-objcopy -SZ=$(PREFIX)arm-none-eabi-size -AR=$(PREFIX)arm-none-eabi-ar +include build/common.mk # ST related SRC = bootloader/main.c bootloader/bootloader.c @@ -44,9 +41,9 @@ endif DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"bootloader.h\" $(EXTRA_DEFINES) # DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1 -CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW) -g +CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS) LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys -LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic +LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic .PRECIOUS: %.o diff --git a/targets/stm32l432/build/common.mk b/targets/stm32l432/build/common.mk new file mode 100644 index 0000000..86469b3 --- /dev/null +++ b/targets/stm32l432/build/common.mk @@ -0,0 +1,19 @@ +CC=$(PREFIX)arm-none-eabi-gcc +CP=$(PREFIX)arm-none-eabi-objcopy +SZ=$(PREFIX)arm-none-eabi-size +AR=$(PREFIX)arm-none-eabi-ar + +VERSION=$(shell git describe --abbrev=0 ) +VERSION_FULL=$(shell git describe) +VERSION_MAJ=$(shell python -c 'print("$(VERSION)".split(".")[0])') +VERSION_MIN=$(shell python -c 'print("$(VERSION)".split(".")[1])') +VERSION_PAT=$(shell python -c 'print("$(VERSION)".split(".")[2])') + +VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \ + -DSOLO_VERSION_PATCH=$(VERSION_PAT) -DVERSION=\"$(VERSION_FULL)\" + +_all: + echo $(VERSION_FULL) + echo $(VERSION_MAJ) + echo $(VERSION_MIN) + echo $(VERSION_PAT) diff --git a/targets/stm32l432/lib/usbd/usbd_desc.c b/targets/stm32l432/lib/usbd/usbd_desc.c index bd0ed90..88b920d 100644 --- a/targets/stm32l432/lib/usbd/usbd_desc.c +++ b/targets/stm32l432/lib/usbd/usbd_desc.c @@ -53,19 +53,10 @@ #define USBD_VID 0x0483 #define USBD_PID 0xA2CA #define USBD_LANGID_STRING 0x409 -#ifndef SOLO_HACKER -#define USBD_MANUFACTURER_STRING "Solo Keys" -#define USBD_PRODUCT_FS_STRING "Solo" -#ifndef USBD_SERIAL_NUM +#define USBD_MANUFACTURER_STRING "SoloKeys" +#define USBD_PRODUCT_FS_STRING SOLO_PRODUCT_NAME #define USBD_SERIAL_NUM "0123456789ABCDEF" -#endif -#else -#define USBD_MANUFACTURER_STRING "Solo Keys" -#define USBD_PRODUCT_FS_STRING "Solo HACKER (Unlocked)" -#ifndef USBD_SERIAL_NUM -#define USBD_SERIAL_NUM "0123456789ABCDEF" -#endif -#endif + uint8_t *USBD_HID_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); uint8_t *USBD_HID_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h index 0b00649..8be24fd 100644 --- a/targets/stm32l432/src/app.h +++ b/targets/stm32l432/src/app.h @@ -7,6 +7,7 @@ #ifndef _APP_H_ #define _APP_H_ #include +#include "version.h" #define DEBUG_UART USART1 @@ -21,7 +22,7 @@ //#define USING_DEV_BOARD -//#define ENABLE_U2F_EXTENSIONS +#define ENABLE_U2F_EXTENSIONS #define ENABLE_U2F @@ -29,6 +30,13 @@ // #define DISABLE_CTAPHID_WINK // #define DISABLE_CTAPHID_CBOR + +#if defined(SOLO_HACKER) +#define SOLO_PRODUCT_NAME "Solo Hacker " VERSION +#else +#define SOLO_PRODUCT_NAME "Solo " VERSION +#endif + void printing_init(); void hw_init(void); diff --git a/targets/stm32l432/src/version.h b/targets/stm32l432/src/version.h new file mode 100644 index 0000000..ea97314 --- /dev/null +++ b/targets/stm32l432/src/version.h @@ -0,0 +1,21 @@ +#ifndef _VERSION_H_ +#define _VERSION_H_ + + +#ifndef SOLO_VERSION_MAJ + +#define SOLO_VERSION_MAJ 0 +#define SOLO_VERSION_MIN 0 +#define SOLO_VERSION_PATCH 0 + +#endif + +#define __STR_HELPER(x) #x +#define __STR(x) __STR_HELPER(x) + +#ifndef VERSION +#define VERSION __STR(SOLO_VERSION_MAJ) "." __STR(SOLO_VERSION_MIN) "." __STR(SOLO_VERSION_PATCH) +#endif + + +#endif diff --git a/tools/solotool.py b/tools/solotool.py index 758714a..4db5f8c 100755 --- a/tools/solotool.py +++ b/tools/solotool.py @@ -90,6 +90,9 @@ def get_firmware_object(sk_name, hex_file): msg = {'firmware': fw, 'signature': sig} return msg +class SoloExtension: + version= 0x14 + rng = 0x15 class SoloBootloader: write = 0x40 @@ -196,10 +199,16 @@ class SoloClient: return res.signature[1:] - def version(self,): + def bootloader_version(self,): data = self.exchange(SoloBootloader.version) + if len(data) > 2: + return (data[0],data[1],data[2]) return data[0] + def solo_version(self,): + data = self.exchange_u2f(SoloExtension.version) + return (data[0],data[1],data[2]) + def write_flash(self, addr, data): self.exchange(SoloBootloader.write, addr, data) @@ -256,7 +265,7 @@ class SoloClient: def is_solo_bootloader(self,): try: - self.version() + self.bootloader_version() return True except CtapError as e: if e.code == CtapError.ERR.INVALID_COMMAND: @@ -583,7 +592,7 @@ def solo_main(): ) parser.add_argument("--wink", action="store_true", help='HID Wink command.') parser.add_argument("--reset", action="store_true", help='Issue a FIDO2 reset command. Warning: your credentials will be lost.') - parser.add_argument("--verify-solo", action="store_true", help='Verify that the Solo firmware is from SoloKeys.') + parser.add_argument("--verify-solo", action="store_true", help='Verify that the Solo firmware is from SoloKeys. Check firmware version.') args = parser.parse_args() p = SoloClient() @@ -604,12 +613,22 @@ def solo_main(): if args.verify_solo: cert = p.make_credential() + solo_fingerprint = b'r\xd5\x831&\xac\xfc\xe9\xa8\xe8&`\x18\xe6AI4\xc8\xbeJ\xb8h_\x91\xb0\x99!\x13\xbb\xd42\x95' + hacker_fingerprint = b"\xd0ml\xcb\xda}\xe5j\x16'\xc2\xa7\x89\x9c5\xa2\xa3\x16\xc8Q\xb3j\xd8\xed~\xd7\x84y\xbbx~\xf7" if (cert.fingerprint(hashes.SHA256()) == solo_fingerprint): - print('Valid firmware from SoloKeys') + print('Valid SOLO firmware from SoloKeys') + elif (cert.fingerprint(hashes.SHA256()) == hacker_fingerprint): + print('Valid HACKER firmware') else: - print('This is either a Solo Hacker or a invalid Solo.') + print('Unknown fingerprint! ', cert.fingerprint(hashes.SHA256())) + + try: + v = p.solo_version() + print('Version: ', v) + except ApduError: + print('Firmware is out of date.') def asked_for_help(): @@ -909,7 +928,7 @@ def programmer_main(): sys.exit(1) try: - p.version() + p.bootloader_version() except CtapError as e: if e.code == CtapError.ERR.INVALID_COMMAND: print('Bootloader not active. Attempting to boot into bootloader mode...')