Merge pull request #111 from solokeys/fido2-ext

Fido2 ext
This commit is contained in:
Conor Patrick 2019-02-17 15:51:57 -05:00 committed by GitHub
commit ed6da0ba1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 212 additions and 55 deletions

View File

@ -10,9 +10,12 @@ LABEL="mm_usb_device_blacklist_end"
# Solo # Solo
## access ## bootloader + firmware access
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev"
## DFU access
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess", GROUP="plugdev"
## Solo Secure symlink ## Solo Secure symlink
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo [1-9]*", SYMLINK+="solokey" SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo [1-9]*", SYMLINK+="solokey"
## Solo Hacker symlink ## Solo Hacker symlink

View File

@ -28,5 +28,4 @@ RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python3
RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python
# 3. Source code # 3. Source code
RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input

View File

@ -75,10 +75,12 @@ fido2-test: venv
venv/bin/python tools/ctap_test.py venv/bin/python tools/ctap_test.py
DOCKER_IMAGE := "solokeys/solo-firmware:local" DOCKER_IMAGE := "solokeys/solo-firmware:local"
SOLO_VERSION := "master" SOLO_VERSIONISH := "master"
docker-build: docker-build:
docker build -t $(DOCKER_IMAGE) . docker build -t $(DOCKER_IMAGE) .
docker run --rm -v$(PWD)/builds:/builds -v$(PWD)/docker-build.sh:/build.sh $(DOCKER_IMAGE) /build.sh $(SOLO_VERSION) docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) /in-docker-build.sh $(SOLO_VERSIONISH)
CPPCHECK_FLAGS=--quiet --error-exitcode=2 CPPCHECK_FLAGS=--quiet --error-exitcode=2

View File

@ -1,21 +0,0 @@
#!/bin/bash -xe
version=${1:-master}
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
cd /solo/targets/stm32l432
git checkout ${version}
version=$(git describe)
make cbor
make all-hacker
cd /
out_dir="builds"
out_hex="solo-${version}.hex"
out_sha2="solo-${version}.sha2"
cp /solo/targets/stm32l432/solo.hex ${out_dir}/${out_hex}
cd ${out_dir}
sha256sum ${out_hex} > ${out_sha2}

View File

@ -21,6 +21,7 @@
#include "device.h" #include "device.h"
#include APP_CONFIG #include APP_CONFIG
#include "wallet.h" #include "wallet.h"
#include "extensions.h"
#include "device.h" #include "device.h"
@ -776,8 +777,19 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA)
if (! ctap_authenticate_credential(&GA->rp, &GA->creds[i])) if (! ctap_authenticate_credential(&GA->rp, &GA->creds[i]))
{ {
printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.id.count); printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.id.count);
#ifdef ENABLE_U2F_EXTENSIONS
if (is_extension_request((uint8_t*)&GA->creds[i].credential.id, sizeof(CredentialId)))
{
printf1(TAG_EXT, "CRED #%d is extension\n", GA->creds[i].credential.id.count);
count++;
}
else
#endif
{
GA->creds[i].credential.id.count = 0; // invalidate GA->creds[i].credential.id.count = 0; // invalidate
} }
}
else else
{ {
// add user info if it exists // add user info if it exists
@ -856,6 +868,7 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
int ret; int ret;
uint8_t sigbuf[64]; uint8_t sigbuf[64];
uint8_t sigder[72]; uint8_t sigder[72];
int sigder_sz;
if (add_user) if (add_user)
{ {
@ -869,7 +882,16 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
crypto_ecc256_load_key((uint8_t*)&cred->credential.id, sizeof(CredentialId), NULL, 0); crypto_ecc256_load_key((uint8_t*)&cred->credential.id, sizeof(CredentialId), NULL, 0);
int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder); #ifdef ENABLE_U2F_EXTENSIONS
if ( extend_fido2(&cred->credential.id, sigder) )
{
sigder_sz = 72;
}
else
#endif
{
sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
}
{ {
ret = cbor_encode_int(map, RESP_signature); ret = cbor_encode_int(map, RESP_signature);
@ -988,8 +1010,21 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
ret = cbor_encoder_create_map(encoder, &map, map_size); ret = cbor_encoder_create_map(encoder, &map, map_size);
check_ret(ret); check_ret(ret);
#ifdef ENABLE_U2F_EXTENSIONS
if ( is_extension_request((uint8_t*)&GA.creds[validCredCount - 1].credential.id, sizeof(CredentialId)) )
{
ret = cbor_encode_int(&map,RESP_authData);
check_ret(ret);
memset(auth_data_buf,0,sizeof(auth_data_buf));
ret = cbor_encode_byte_string(&map, auth_data_buf, sizeof(auth_data_buf));
check_ret(ret);
}
else
#endif
{
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL, 0); ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL, 0);
check_retr(ret); check_retr(ret);
}
/*for (int j = 0; j < GA.credLen; j++)*/ /*for (int j = 0; j < GA.credLen; j++)*/
/*{*/ /*{*/

View File

@ -8,6 +8,7 @@
#include <stdint.h> #include <stdint.h>
#include "extensions.h" #include "extensions.h"
#include "u2f.h" #include "u2f.h"
#include "ctap.h"
#include "wallet.h" #include "wallet.h"
#include "solo.h" #include "solo.h"
#include "device.h" #include "device.h"
@ -57,7 +58,8 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
#elif defined(WALLET_EXTENSION) #elif defined(WALLET_EXTENSION)
ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh); ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh);
#else #else
ret = bridge_u2f_to_solo(_chal, _appid, klen, keyh); ret = bridge_u2f_to_solo(sig, keyh, klen);
u2f_response_writeback(sig,72);
#endif #endif
if (ret != 0) if (ret != 0)
@ -74,6 +76,21 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
return U2F_SW_NO_ERROR; return U2F_SW_NO_ERROR;
} }
// Returns 1 if this is a extension request.
// Else 0 if nothing is done.
int16_t extend_fido2(CredentialId * credid, uint8_t * output)
{
if (is_extension_request((uint8_t*)credid, sizeof(CredentialId)))
{
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
return 1;
}
else
{
return 0;
}
}
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len) int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
{ {
@ -93,7 +110,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
{ {
rcode = U2F_SW_WRONG_DATA; rcode = U2F_SW_WRONG_DATA;
} }
printf1(TAG_EXT,"Ignoring U2F request\n"); printf1(TAG_EXT,"Ignoring U2F check request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl); dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end; goto end;
} }
@ -102,7 +119,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{ {
rcode = U2F_SW_WRONG_PAYLOAD; rcode = U2F_SW_WRONG_PAYLOAD;
printf1(TAG_EXT, "Ignoring U2F request\n"); printf1(TAG_EXT, "Ignoring U2F auth request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl); dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end; goto end;
} }

View File

@ -10,6 +10,10 @@
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len); int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len);
int16_t extend_fido2(CredentialId * credid, uint8_t * output);
int bootloader_bridge(int klen, uint8_t * keyh); int bootloader_bridge(int klen, uint8_t * keyh);
int is_extension_request(uint8_t * kh, int len);
#endif /* EXTENSIONS_H_ */ #endif /* EXTENSIONS_H_ */

View File

@ -31,27 +31,26 @@
#include "log.h" #include "log.h"
#include APP_CONFIG #include APP_CONFIG
int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh) // output must be at least 71 bytes
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
{ {
static uint8_t msg_buf[72];
int8_t ret = 0; int8_t ret = 0;
wallet_request * req = (wallet_request *) keyh; wallet_request * req = (wallet_request *) keyh;
printf1(TAG_WALLET, "u2f-solo [%d]: ", klen); dump_hex1(TAG_WALLET, keyh, klen); printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen);
switch(req->operation) switch(req->operation)
{ {
case WalletVersion: case WalletVersion:
msg_buf[0] = SOLO_VERSION_MAJ; output[0] = SOLO_VERSION_MAJ;
msg_buf[1] = SOLO_VERSION_MIN; output[1] = SOLO_VERSION_MIN;
msg_buf[2] = SOLO_VERSION_PATCH; output[2] = SOLO_VERSION_PATCH;
u2f_response_writeback(msg_buf, 3);
break; break;
case WalletRng: case WalletRng:
printf1(TAG_WALLET,"SoloRng\n"); printf1(TAG_WALLET,"SoloRng\n");
ret = ctap_generate_rng(msg_buf, 72); ret = ctap_generate_rng(output, 71);
if (ret != 1) if (ret != 1)
{ {
printf1(TAG_WALLET,"Rng failed\n"); printf1(TAG_WALLET,"Rng failed\n");
@ -60,7 +59,6 @@ int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint
} }
ret = 0; ret = 0;
u2f_response_writeback((uint8_t *)msg_buf,72);
break; break;
default: default:

View File

@ -22,6 +22,6 @@
#ifndef SOLO_H_ #ifndef SOLO_H_
#define SOLO_H_ #define SOLO_H_
int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh); int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen);
#endif #endif

View File

@ -47,7 +47,7 @@ struct logtag tagtable[] = {
{TAG_WALLET,"WALLET"}, {TAG_WALLET,"WALLET"},
{TAG_STOR,"STOR"}, {TAG_STOR,"STOR"},
{TAG_BOOT,"BOOT"}, {TAG_BOOT,"BOOT"},
{TAG_BOOT,"EXT"}, {TAG_EXT,"EXT"},
}; };

View File

@ -41,7 +41,7 @@ typedef enum
TAG_STOR = (1 << 15), TAG_STOR = (1 << 15),
TAG_DUMP2 = (1 << 16), TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17), TAG_BOOT = (1 << 17),
TAG_EXT = (1 << 17), TAG_EXT = (1 << 18),
TAG_FILENO = (1u << 31) TAG_FILENO = (1u << 31)
} LOG_TAG; } LOG_TAG;

View File

@ -44,7 +44,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
rcode = extend_u2f(req, len); rcode = extend_u2f(req, len);
#endif #endif
if (rcode != U2F_SW_NO_ERROR) // If the extension didn't do anything... if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
{ {
#ifdef ENABLE_U2F #ifdef ENABLE_U2F
switch(req->ins) switch(req->ins)
@ -224,7 +224,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
} }
count = ctap_atomic_count(0); count = ctap_atomic_count(0);
hash[0] = (count >> 24) & 0xff; hash[0] = 0xff;
hash[1] = (count >> 16) & 0xff; hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff; hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff; hash[3] = (count >> 0) & 0xff;
@ -241,7 +241,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
crypto_ecc256_sign(hash, 32, sig); crypto_ecc256_sign(hash, 32, sig);
u2f_response_writeback(&up,1); u2f_response_writeback(&up,1);
hash[0] = (count >> 24) & 0xff; hash[0] = 0xff;
hash[1] = (count >> 16) & 0xff; hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff; hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff; hash[3] = (count >> 0) & 0xff;

37
in-docker-build.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/bash -xe
version=${1:-master}
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
cd /solo/targets/stm32l432
git fetch
git checkout ${version}
version=$(git describe)
make cbor
out_dir="/builds"
function build() {
part=${1}
variant=${2}
output=${3:-${part}}
what="${part}-${variant}"
make full-clean
make ${what}
out_hex="${what}-${version}.hex"
out_sha2="${what}-${version}.sha2"
mv ${output}.hex ${out_hex}
sha256sum ${out_hex} > ${out_sha2}
cp ${out_hex} ${out_sha2} ${out_dir}
}
build bootloader nonverifying
build bootloader verifying
build firmware hacker solo
build firmware secure solo

View File

@ -9,6 +9,25 @@ merge_hex=../../tools/solotool.py mergehex
.PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor test .PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor test
# The following are the main targets for reproducible builds.
# TODO: better explanation
firmware-hacker:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware-secure:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2'
bootloader-nonverifying:
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
bootloader-verifying:
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) DEBUG=0
full-clean: clean2
# The older targets, may be re-organised
all: all:
$(MAKE) -f $(APPMAKE) -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'

View File

@ -4,7 +4,7 @@ include build/common.mk
SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c SRC = src/main.c 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/fifo.c src/crypto.c src/attestation.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c) SRC += $(DRIVER_LIBS) $(USB_LIB)
# FIDO2 lib # FIDO2 lib
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c

View File

@ -5,7 +5,7 @@ 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/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/fifo.c src/crypto.c src/attestation.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c) SRC += $(DRIVER_LIBS) $(USB_LIB)
# FIDO2 lib # FIDO2 lib
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/extensions/extensions.c SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/extensions/extensions.c

View File

@ -3,6 +3,15 @@ CP=$(PREFIX)arm-none-eabi-objcopy
SZ=$(PREFIX)arm-none-eabi-size SZ=$(PREFIX)arm-none-eabi-size
AR=$(PREFIX)arm-none-eabi-ar AR=$(PREFIX)arm-none-eabi-ar
DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \
lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_rng.c lib/stm32l4xx_ll_tim.c \
lib/stm32l4xx_ll_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \
lib/stm32l4xx_ll_usart.c
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c
VERSION:=$(shell git describe --abbrev=0 ) VERSION:=$(shell git describe --abbrev=0 )
VERSION_FULL:=$(shell git describe) VERSION_FULL:=$(shell git describe)
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])') VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
@ -10,7 +19,7 @@ VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])') VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \ VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DVERSION=\"$(VERSION_FULL)\" -DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
_all: _all:
echo $(VERSION_FULL) echo $(VERSION_FULL)

View File

@ -166,6 +166,32 @@ uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *l
*/ */
uint8_t *USBD_HID_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) uint8_t *USBD_HID_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ {
USBD_GetString((uint8_t *)USBD_SERIAL_NUM, USBD_StrDesc, length); // Match the same alg as the DFU to make serial number
volatile uint8_t * UUID = (volatile uint8_t *)0x1FFF7590;
const char hexdigit[] = "0123456789ABCDEF";
uint8_t uuid[6];
uint8_t uuid_str[13];
uint8_t c;
int i;
uuid_str[12] = 0;
uuid[0] = UUID[11];
uuid[1] = UUID[10] + UUID[2];
uuid[2] = UUID[9];
uuid[3] = UUID[8] + UUID[0];
uuid[4] = UUID[7];
uuid[5] = UUID[6];
// quick method to convert to hex string
for (i = 0; i < 6; i++)
{
c = (uuid[i]>>4) & 0x0f;
uuid_str[i * 2 + 0] = hexdigit[ c ];
c = (uuid[i]>>0) & 0x0f;
uuid_str[i * 2 + 1] = hexdigit[ c ];
}
USBD_GetString((uint8_t *)uuid_str, USBD_StrDesc, length);
return USBD_StrDesc; return USBD_StrDesc;
} }

View File

@ -383,12 +383,16 @@ class Tester:
def test_u2f(self,): def test_u2f(self,):
chal = sha256(b"AAA") chal = sha256(b"AAA")
appid = sha256(b"BBB") appid = sha256(b"BBB")
lastc = 0
for i in range(0, 5): for i in range(0, 5):
reg = self.ctap1.register(chal, appid) reg = self.ctap1.register(chal, appid)
reg.verify(appid, chal) reg.verify(appid, chal)
auth = self.ctap1.authenticate(chal, appid, reg.key_handle) auth = self.ctap1.authenticate(chal, appid, reg.key_handle)
# check endianness # check endianness
assert auth.counter < 0x10000 if lastc:
assert (auth.counter - lastc) < 10
lastc = auth.counter
print(hex(lastc))
print("U2F reg + auth pass %d/5" % (i + 1)) print("U2F reg + auth pass %d/5" % (i + 1))
def test_fido2_simple(self, pin_token=None): def test_fido2_simple(self, pin_token=None):

View File

@ -201,6 +201,24 @@ class SoloClient:
return res.signature[1:] return res.signature[1:]
def exchange_fido2(self, cmd, addr=0, data=b"A" * 16):
chal = "B" * 32
req = SoloClient.format_request(cmd, addr, data)
assertions, client_data = self.client.get_assertion(
self.host, chal, [{"id": req, "type": "public-key"}]
)
if len(assertions) < 1:
raise RuntimeError("Device didn't respond to FIDO2 extended assertion")
res = assertions[0]
ret = res.signature[0]
if ret != CtapError.ERR.SUCCESS:
raise RuntimeError("Device returned non-success code %02x" % (ret,))
return res.signature[1:]
def bootloader_version(self,): def bootloader_version(self,):
data = self.exchange(SoloBootloader.version) data = self.exchange(SoloBootloader.version)
if len(data) > 2: if len(data) > 2:
@ -208,7 +226,7 @@ class SoloClient:
return data[0] return data[0]
def solo_version(self,): def solo_version(self,):
data = self.exchange_u2f(SoloExtension.version) data = self.exchange_fido2(SoloExtension.version)
return (data[0], data[1], data[2]) return (data[0], data[1], data[2])
def write_flash(self, addr, data): def write_flash(self, addr, data):
@ -585,6 +603,7 @@ def solo_main():
action="store_true", action="store_true",
help="Continuously dump random numbers generated from Solo.", help="Continuously dump random numbers generated from Solo.",
) )
parser.add_argument("--wink", action="store_true", help="HID Wink command.") parser.add_argument("--wink", action="store_true", help="HID Wink command.")
parser.add_argument( parser.add_argument(
"--reset", "--reset",
@ -596,6 +615,9 @@ def solo_main():
action="store_true", action="store_true",
help="Verify that the Solo firmware is from SoloKeys. Check firmware version.", help="Verify that the Solo firmware is from SoloKeys. Check firmware version.",
) )
parser.add_argument(
"--version", action="store_true", help="Check firmware version on Solo."
)
args = parser.parse_args() args = parser.parse_args()
p = SoloClient() p = SoloClient()
@ -627,6 +649,9 @@ def solo_main():
else: else:
print("Unknown fingerprint! ", cert.fingerprint(hashes.SHA256())) print("Unknown fingerprint! ", cert.fingerprint(hashes.SHA256()))
args.version = True
if args.version:
try: try:
v = p.solo_version() v = p.solo_version()
print("Version: ", v) print("Version: ", v)