commit
ed6da0ba1e
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
6
Makefile
6
Makefile
@ -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
|
||||||
|
|
||||||
|
@ -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}
|
|
||||||
|
|
43
fido2/ctap.c
43
fido2/ctap.c
@ -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,7 +777,18 @@ 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);
|
||||||
GA->creds[i].credential.id.count = 0; // invalidate
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -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);
|
||||||
|
|
||||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL, 0);
|
#ifdef ENABLE_U2F_EXTENSIONS
|
||||||
check_retr(ret);
|
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);
|
||||||
|
check_retr(ret);
|
||||||
|
}
|
||||||
|
|
||||||
/*for (int j = 0; j < GA.credLen; j++)*/
|
/*for (int j = 0; j < GA.credLen; j++)*/
|
||||||
/*{*/
|
/*{*/
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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_ */
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -47,7 +47,7 @@ struct logtag tagtable[] = {
|
|||||||
{TAG_WALLET,"[1;34mWALLET[0m"},
|
{TAG_WALLET,"[1;34mWALLET[0m"},
|
||||||
{TAG_STOR,"[1;35mSTOR[0m"},
|
{TAG_STOR,"[1;35mSTOR[0m"},
|
||||||
{TAG_BOOT,"[1;36mBOOT[0m"},
|
{TAG_BOOT,"[1;36mBOOT[0m"},
|
||||||
{TAG_BOOT,"[1;37mEXT[0m"},
|
{TAG_EXT,"[1;37mEXT[0m"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
37
in-docker-build.sh
Executable 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
|
@ -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'
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
return USBD_StrDesc;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user