Update to U2F managed SDK - add forks
@@ -20,30 +20,68 @@ $(error Environment variable BOLOS_SDK is not set)
|
||||
endif
|
||||
include $(BOLOS_SDK)/Makefile.defines
|
||||
|
||||
APP_LOAD_FLAGS= --appFlags 0x40 --dep Ethereum
|
||||
DEFINES_LIB = USE_LIB_ETHEREUM
|
||||
APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS)
|
||||
|
||||
APPVERSION_M=1
|
||||
APPVERSION_N=0
|
||||
APPVERSION_P=22
|
||||
APPVERSION_N=1
|
||||
APPVERSION_P=2
|
||||
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
|
||||
|
||||
|
||||
ifeq ($(CHAIN),)
|
||||
CHAIN=ethereum
|
||||
endif
|
||||
|
||||
ifeq ($(CHAIN),ethereum)
|
||||
APP_LOAD_PARAMS += --path "44'/60'" --path "44'/61'"
|
||||
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAINID_NAME=\"Ethereum\" CHAINID=$(CHAIN) CHAIN_TYPE_ETHEREUM
|
||||
APPNAME = Ethereum
|
||||
#TODO : Fix in 1.4.3
|
||||
#APP_LOAD_PARAMS += --path "44'/60'"
|
||||
APP_LOAD_PARAMS += --path "44'"
|
||||
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=0
|
||||
APPNAME = "Ethereum"
|
||||
DEFINES_LIB=
|
||||
APP_LOAD_FLAGS=--appFlags 0x840
|
||||
else ifeq ($(CHAIN),ethereum_classic)
|
||||
APP_LOAD_PARAMS += --path "44'/61'"
|
||||
DEFINES += CHAINID_UPCASE=\"ETC\" CHAINID_COINNAME=\"ETC\" CHAIN_KIND=CHAIN_KIND_ETHEREUM_CLASSIC CHAIN_ID=61
|
||||
APPNAME = "ETC"
|
||||
else ifeq ($(CHAIN),expanse)
|
||||
APP_LOAD_PARAMS += --path "44'/40'"
|
||||
DEFINES += CHAINID_UPCASE=\"EXPANSE\" CHAINID_COINNAME=\"EXP\" CHAINID_NAME=\"Expanse\" CHAINID=$(CHAIN) CHAIN_TYPE_EXPANSE
|
||||
APPNAME = Expanse
|
||||
DEFINES += CHAINID_UPCASE=\"EXPANSE\" CHAINID_COINNAME=\"EXP\" CHAIN_KIND=CHAIN_KIND_EXPANSE CHAIN_ID=2
|
||||
APPNAME = "Expanse"
|
||||
else ifeq ($(CHAIN),poa)
|
||||
APP_LOAD_PARAMS += --path "44'/60'"
|
||||
DEFINES += CHAINID_UPCASE=\"POA\" CHAINID_COINNAME=\"POA\" CHAIN_KIND=CHAIN_KIND_POA CHAIN_ID=99
|
||||
APPNAME = "POA"
|
||||
else ifeq ($(CHAIN),rsk)
|
||||
APP_LOAD_PARAMS += --path "44'/137'"
|
||||
DEFINES += CHAINID_UPCASE=\"RSK\" CHAINID_COINNAME=\"SBTC\" CHAIN_KIND=CHAIN_KIND_RSK CHAIN_ID=30
|
||||
APPNAME = "RSK"
|
||||
else ifeq ($(CHAIN),rsk_testnet)
|
||||
APP_LOAD_PARAMS += --path "44'/37310'"
|
||||
DEFINES += CHAINID_UPCASE=\"RSKTESTNET\" CHAINID_COINNAME=\"SBTC\" CHAIN_KIND=CHAIN_KIND_RSK CHAIN_ID=31
|
||||
APPNAME = "RSK Test"
|
||||
else ifeq ($(CHAIN),ubiq)
|
||||
APP_LOAD_PARAMS += --path "44'/108'"
|
||||
DEFINES += CHAINID_UPCASE=\"UBIQ\" CHAINID_COINNAME=\"UBQ\" CHAINID_NAME=\"Ubiq\" CHAINID=$(CHAIN) CHAIN_TYPE_UBIQ
|
||||
APPNAME = Ubiq
|
||||
DEFINES += CHAINID_UPCASE=\"UBIQ\" CHAINID_COINNAME=\"UBQ\" CHAIN_KIND=CHAIN_KIND_UBIQ CHAIN_ID=8
|
||||
APPNAME = "Ubiq"
|
||||
else ifeq ($(CHAIN),wanchain)
|
||||
APP_LOAD_PARAMS += --path "44'/5718350'"
|
||||
DEFINES += CHAINID_UPCASE=\"WAN\" CHAINID_COINNAME=\"WAN\" CHAIN_KIND=CHAIN_KIND_WANCHAIN CHAIN_ID=1
|
||||
APPNAME = "Wanchain"
|
||||
else ifeq ($(CHAIN),kusd)
|
||||
APP_LOAD_PARAMS += --path "44'/91927009'"
|
||||
DEFINES += CHAINID_UPCASE=\"KUSD\" CHAINID_COINNAME=\"KUSD\" CHAIN_KIND=CHAIN_KIND_KUSD CHAIN_ID=2
|
||||
APPNAME = "KUSD"
|
||||
else
|
||||
ifeq ($(filter clean,$(MAKECMDGOALS)),)
|
||||
$(error Unsupported CHAIN - use ethereum, expanse, ubiq)
|
||||
$(error Unsupported CHAIN - use ethereum, ethereum_classic, expanse, poa, rsk, rsk_testnet, ubiq, wanchain, kusd)
|
||||
endif
|
||||
endif
|
||||
APP_LOAD_PARAMS += --appFlags 0x40 --path "44'/1'" --curve secp256k1 $(COMMON_LOAD_PARAMS)
|
||||
|
||||
APP_LOAD_PARAMS += $(APP_LOAD_FLAGS) --path "44'/1'"
|
||||
DEFINES += $(DEFINES_LIB)
|
||||
|
||||
#prepare hsm generation
|
||||
ifeq ($(TARGET_NAME),TARGET_BLUE)
|
||||
@@ -66,21 +104,39 @@ DEFINES += HAVE_BAGL HAVE_SPRINTF
|
||||
#DEFINES += HAVE_PRINTF PRINTF=screen_printf
|
||||
DEFINES += PRINTF\(...\)=
|
||||
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
|
||||
DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
|
||||
DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
|
||||
|
||||
# U2F
|
||||
DEFINES += HAVE_U2F
|
||||
DEFINES += HAVE_U2F HAVE_IO_U2F
|
||||
DEFINES += U2F_PROXY_MAGIC=\"w0w\"
|
||||
DEFINES += USB_SEGMENT_SIZE=64
|
||||
DEFINES += BLE_SEGMENT_SIZE=32 #max MTU, min 20
|
||||
DEFINES += U2F_MAX_MESSAGE_SIZE=264 #257+5+2
|
||||
|
||||
WEBUSB_URL = www.ledgerwallet.com
|
||||
DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g")
|
||||
|
||||
DEFINES += UNUSED\(x\)=\(void\)x
|
||||
DEFINES += APPVERSION=\"$(APPVERSION)\"
|
||||
|
||||
DEFINES += CX_COMPLIANCE_141
|
||||
|
||||
##############
|
||||
# Compiler #
|
||||
##############
|
||||
#GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
|
||||
#CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
|
||||
ifneq ($(BOLOS_ENV),)
|
||||
$(info BOLOS_ENV=$(BOLOS_ENV))
|
||||
CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
|
||||
GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
|
||||
else
|
||||
$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH)
|
||||
endif
|
||||
ifeq ($(CLANGPATH),)
|
||||
$(info CLANGPATH is not set: clang will be used from PATH)
|
||||
endif
|
||||
ifeq ($(GCCPATH),)
|
||||
$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH)
|
||||
endif
|
||||
|
||||
CC := $(CLANGPATH)clang
|
||||
|
||||
#CFLAGS += -O0
|
||||
@@ -95,10 +151,9 @@ LDLIBS += -lm -lgcc -lc
|
||||
# import rules to compile glyphs(/pone)
|
||||
include $(BOLOS_SDK)/Makefile.glyphs
|
||||
|
||||
### computed variables
|
||||
### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
|
||||
APP_SOURCE_PATH += src_genericwallet src_common src
|
||||
SDK_SOURCE_PATH += lib_stusb
|
||||
|
||||
SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f
|
||||
|
||||
load: all
|
||||
python -m ledgerblue.loadApp $(APP_LOAD_PARAMS)
|
||||
|
||||
BIN
blue_app_ethereum_classic.gif
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
blue_app_poa.gif
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
blue_app_rsk.gif
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
blue_app_rsk_testnet.gif
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
blue_app_wanchain.gif
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
glyphs/blue_badge_ethereum_classic.gif
Normal file
|
After Width: | Height: | Size: 347 B |
BIN
glyphs/blue_badge_poa.gif
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
glyphs/blue_badge_rsk.gif
Normal file
|
After Width: | Height: | Size: 347 B |
BIN
glyphs/blue_badge_rsk_testnet.gif
Normal file
|
After Width: | Height: | Size: 347 B |
BIN
glyphs/blue_badge_wanchain.gif
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
glyphs/nanos_badge_ethereum_classic.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
glyphs/nanos_badge_kusd.gif
Normal file
|
After Width: | Height: | Size: 117 B |
BIN
glyphs/nanos_badge_poa.gif
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
glyphs/nanos_badge_rsk.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
glyphs/nanos_badge_rsk_testnet.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
glyphs/nanos_badge_wanchain.gif
Normal file
|
After Width: | Height: | Size: 80 B |
BIN
nanos_app_kusd.gif
Normal file
|
After Width: | Height: | Size: 117 B |
BIN
nanos_app_poa.gif
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
nanos_app_rsk.gif
Normal file
|
After Width: | Height: | Size: 82 B |
BIN
nanos_app_rsk_testnet.gif
Normal file
|
After Width: | Height: | Size: 82 B |
BIN
nanos_app_wanchain.gif
Normal file
|
After Width: | Height: | Size: 85 B |
@@ -46,7 +46,7 @@ uint8_t readTxByte(txContext_t *context) {
|
||||
context->currentFieldPos++;
|
||||
}
|
||||
if (!(context->processingField && context->fieldSingleByte)) {
|
||||
cx_hash((cx_hash_t *)context->sha3, 0, &data, 1, NULL);
|
||||
cx_hash((cx_hash_t*)context->sha3, 0, &data, 1, NULL);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@@ -60,8 +60,7 @@ void copyTxData(txContext_t *context, uint8_t *out, uint32_t length) {
|
||||
os_memmove(out, context->workBuffer, length);
|
||||
}
|
||||
if (!(context->processingField && context->fieldSingleByte)) {
|
||||
cx_hash((cx_hash_t *)context->sha3, 0, context->workBuffer, length,
|
||||
NULL);
|
||||
cx_hash((cx_hash_t*)context->sha3, 0, context->workBuffer, length, NULL);
|
||||
}
|
||||
context->workBuffer += length;
|
||||
context->commandLength -= length;
|
||||
@@ -81,6 +80,30 @@ static void processContent(txContext_t *context) {
|
||||
context->processingField = false;
|
||||
}
|
||||
|
||||
|
||||
static void processType(txContext_t *context) {
|
||||
if (context->currentFieldIsList) {
|
||||
PRINTF("Invalid type for RLP_TYPE\n");
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
if (context->currentFieldLength > MAX_INT256) {
|
||||
PRINTF("Invalid length for RLP_TYPE\n");
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
if (context->currentFieldPos < context->currentFieldLength) {
|
||||
uint32_t copySize =
|
||||
(context->commandLength <
|
||||
((context->currentFieldLength - context->currentFieldPos))
|
||||
? context->commandLength
|
||||
: context->currentFieldLength - context->currentFieldPos);
|
||||
copyTxData(context, NULL, copySize);
|
||||
}
|
||||
if (context->currentFieldPos == context->currentFieldLength) {
|
||||
context->currentField++;
|
||||
context->processingField = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void processNonce(txContext_t *context) {
|
||||
if (context->currentFieldIsList) {
|
||||
PRINTF("Invalid type for RLP_NONCE\n");
|
||||
@@ -111,7 +134,7 @@ static void processStartGas(txContext_t *context) {
|
||||
}
|
||||
if (context->currentFieldLength > MAX_INT256) {
|
||||
PRINTF("Invalid length for RLP_STARTGAS %d\n",
|
||||
context->currentFieldLength);
|
||||
context->currentFieldLength);
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
if (context->currentFieldPos < context->currentFieldLength) {
|
||||
@@ -183,7 +206,7 @@ static void processValue(txContext_t *context) {
|
||||
}
|
||||
}
|
||||
|
||||
static void processTo(txContext_t *context) {
|
||||
static void processTo(txContext_t *context) {
|
||||
if (context->currentFieldIsList) {
|
||||
PRINTF("Invalid type for RLP_TO\n");
|
||||
THROW(EXCEPTION);
|
||||
@@ -191,7 +214,7 @@ static void processTo(txContext_t *context) {
|
||||
if (context->currentFieldLength > MAX_ADDRESS) {
|
||||
PRINTF("Invalid length for RLP_TO\n");
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
}
|
||||
if (context->currentFieldPos < context->currentFieldLength) {
|
||||
uint32_t copySize =
|
||||
(context->commandLength <
|
||||
@@ -209,7 +232,7 @@ static void processTo(txContext_t *context) {
|
||||
}
|
||||
}
|
||||
|
||||
static void processData(txContext_t *context) {
|
||||
static void processData(txContext_t *context) {
|
||||
if (context->currentFieldIsList) {
|
||||
PRINTF("Invalid type for RLP_DATA\n");
|
||||
THROW(EXCEPTION);
|
||||
@@ -228,7 +251,7 @@ static void processData(txContext_t *context) {
|
||||
}
|
||||
}
|
||||
|
||||
static void processV(txContext_t *context) {
|
||||
static void processV(txContext_t *context) {
|
||||
if (context->currentFieldIsList) {
|
||||
PRINTF("Invalid type for RLP_V\n");
|
||||
THROW(EXCEPTION);
|
||||
@@ -236,14 +259,15 @@ static void processV(txContext_t *context) {
|
||||
if (context->currentFieldLength > MAX_V) {
|
||||
PRINTF("Invalid length for RLP_V\n");
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
}
|
||||
if (context->currentFieldPos < context->currentFieldLength) {
|
||||
uint32_t copySize =
|
||||
(context->commandLength <
|
||||
((context->currentFieldLength - context->currentFieldPos))
|
||||
? context->commandLength
|
||||
: context->currentFieldLength - context->currentFieldPos);
|
||||
copyTxData(context, context->content->v + context->currentFieldPos,
|
||||
copyTxData(context,
|
||||
context->content->v + context->currentFieldPos,
|
||||
copySize);
|
||||
}
|
||||
if (context->currentFieldPos == context->currentFieldLength) {
|
||||
@@ -253,7 +277,8 @@ static void processV(txContext_t *context) {
|
||||
}
|
||||
}
|
||||
|
||||
static parserStatus_e processTxInternal(txContext_t *context) {
|
||||
|
||||
static parserStatus_e processTxInternal(txContext_t *context, uint32_t processingFlags) {
|
||||
for (;;) {
|
||||
bool processedCustom = false;
|
||||
// EIP 155 style transasction
|
||||
@@ -261,8 +286,7 @@ static parserStatus_e processTxInternal(txContext_t *context) {
|
||||
return USTREAM_FINISHED;
|
||||
}
|
||||
// Old style transaction
|
||||
if ((context->currentField == TX_RLP_V) &&
|
||||
(context->commandLength == 0)) {
|
||||
if ((context->currentField == TX_RLP_V) && (context->commandLength == 0)) {
|
||||
context->content->vLength = 0;
|
||||
return USTREAM_FINISHED;
|
||||
}
|
||||
@@ -323,6 +347,12 @@ static parserStatus_e processTxInternal(txContext_t *context) {
|
||||
switch (context->currentField) {
|
||||
case TX_RLP_CONTENT:
|
||||
processContent(context);
|
||||
if ((processingFlags & TX_FLAG_TYPE) == 0) {
|
||||
context->currentField++;
|
||||
}
|
||||
break;
|
||||
case TX_RLP_TYPE:
|
||||
processType(context);
|
||||
break;
|
||||
case TX_RLP_NONCE:
|
||||
processNonce(context);
|
||||
@@ -356,13 +386,13 @@ static parserStatus_e processTxInternal(txContext_t *context) {
|
||||
}
|
||||
|
||||
parserStatus_e processTx(txContext_t *context, uint8_t *buffer,
|
||||
uint32_t length) {
|
||||
uint32_t length, uint32_t processingFlags) {
|
||||
parserStatus_e result;
|
||||
BEGIN_TRY {
|
||||
TRY {
|
||||
context->workBuffer = buffer;
|
||||
context->commandLength = length;
|
||||
result = processTxInternal(context);
|
||||
result = processTxInternal(context, processingFlags);
|
||||
}
|
||||
CATCH_OTHER(e) {
|
||||
result = USTREAM_FAULT;
|
||||
|
||||
@@ -23,9 +23,12 @@ struct txContext_t;
|
||||
|
||||
typedef bool (*ustreamProcess_t)(struct txContext_t *context);
|
||||
|
||||
#define TX_FLAG_TYPE 0x01
|
||||
|
||||
typedef enum rlpTxField_e {
|
||||
TX_RLP_NONE = 0,
|
||||
TX_RLP_CONTENT,
|
||||
TX_RLP_TYPE,
|
||||
TX_RLP_NONCE,
|
||||
TX_RLP_GASPRICE,
|
||||
TX_RLP_STARTGAS,
|
||||
@@ -80,6 +83,6 @@ typedef struct txContext_t {
|
||||
void initTx(txContext_t *context, cx_sha3_t *sha3, txContent_t *content,
|
||||
ustreamProcess_t customProcessor, void *extra);
|
||||
parserStatus_e processTx(txContext_t *context, uint8_t *buffer,
|
||||
uint32_t length);
|
||||
uint32_t length, uint32_t processingFlags);
|
||||
void copyTxData(txContext_t *context, uint8_t *out, uint32_t length);
|
||||
uint8_t readTxByte(txContext_t *context);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "os.h"
|
||||
#include "cx.h"
|
||||
#include <stdbool.h>
|
||||
#include "ethUtils.h"
|
||||
#include "ethUtils.h"
|
||||
|
||||
bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
|
||||
if (*buffer <= 0x7f) {
|
||||
@@ -115,14 +115,14 @@ bool rlpDecodeLength(uint8_t *buffer, uint32_t bufferLength,
|
||||
}
|
||||
|
||||
void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out,
|
||||
cx_sha3_t *sha3Context) {
|
||||
cx_sha3_t *sha3Context) {
|
||||
uint8_t hashAddress[32];
|
||||
cx_keccak_init(sha3Context, 256);
|
||||
cx_hash((cx_hash_t *)sha3Context, CX_LAST, publicKey->W + 1, 64,
|
||||
hashAddress);
|
||||
cx_hash((cx_hash_t*)sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress);
|
||||
os_memmove(out, hashAddress + 12, 20);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHECKSUM_1
|
||||
|
||||
static const uint8_t const HEXDIGITS[] = "0123456789ABCDEF";
|
||||
@@ -153,8 +153,7 @@ void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out,
|
||||
cx_sha3_t *sha3Context) {
|
||||
uint8_t hashAddress[32];
|
||||
cx_keccak_init(sha3Context, 256);
|
||||
cx_hash((cx_hash_t *)sha3Context, CX_LAST, publicKey->W + 1, 64,
|
||||
hashAddress);
|
||||
cx_hash((cx_hash_t*)sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress);
|
||||
getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context);
|
||||
}
|
||||
|
||||
@@ -163,7 +162,7 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
|
||||
uint8_t hashChecksum[32];
|
||||
uint8_t i;
|
||||
cx_keccak_init(sha3Context, 256);
|
||||
cx_hash((cx_hash_t *)sha3Context, CX_LAST, address, 20, hashChecksum);
|
||||
cx_hash((cx_hash_t*)sha3Context, CX_LAST, address, 20, hashChecksum);
|
||||
for (i = 0; i < 40; i++) {
|
||||
out[i] = convertDigit(address, i, hashChecksum);
|
||||
}
|
||||
@@ -178,8 +177,7 @@ void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out,
|
||||
cx_sha3_t *sha3Context) {
|
||||
uint8_t hashAddress[32];
|
||||
cx_keccak_init(sha3Context, 256);
|
||||
cx_hash((cx_hash_t *)sha3Context, CX_LAST, publicKey->W + 1, 64,
|
||||
hashAddress);
|
||||
cx_hash((cx_hash_t*)sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress);
|
||||
getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context);
|
||||
}
|
||||
|
||||
@@ -194,7 +192,7 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
|
||||
tmp[2 * i + 1] = HEXDIGITS[digit & 0x0f];
|
||||
}
|
||||
cx_keccak_init(sha3Context, 256);
|
||||
cx_hash((cx_hash_t *)sha3Context, CX_LAST, tmp, 40, hashChecksum);
|
||||
cx_hash((cx_hash_t*)sha3Context, CX_LAST, tmp, 40, hashChecksum);
|
||||
for (i = 0; i < 40; i++) {
|
||||
uint8_t hashDigit = hashChecksum[i / 2];
|
||||
if ((i % 2) == 0) {
|
||||
@@ -220,12 +218,12 @@ bool adjustDecimals(char *src, uint32_t srcLength, char *target,
|
||||
uint32_t offset = 0;
|
||||
if ((srcLength == 1) && (*src == '0')) {
|
||||
if (targetLength < 2) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
target[0] = '0';
|
||||
target[1] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (srcLength <= decimals) {
|
||||
uint32_t delta = decimals - srcLength;
|
||||
if (targetLength < srcLength + 1 + 2 + delta) {
|
||||
@@ -271,8 +269,8 @@ bool adjustDecimals(char *src, uint32_t srcLength, char *target,
|
||||
if (lastZeroOffset != 0) {
|
||||
target[lastZeroOffset] = '\0';
|
||||
if (target[lastZeroOffset - 1] == '.') {
|
||||
target[lastZeroOffset - 1] = '\0';
|
||||
}
|
||||
target[lastZeroOffset - 1] = '\0';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ bool rlpDecodeLength(uint8_t *buffer, uint32_t bufferLength,
|
||||
bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid);
|
||||
|
||||
void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out,
|
||||
cx_sha3_t *sha3Context);
|
||||
cx_sha3_t *sha3Context);
|
||||
|
||||
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out,
|
||||
cx_sha3_t *sha3Context);
|
||||
|
||||
32
src_genericwallet/chainConfig.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "os.h"
|
||||
|
||||
#ifndef CHAIN_CONFIG_H
|
||||
|
||||
#define CHAIN_CONFIG_H
|
||||
|
||||
typedef enum chain_kind_e {
|
||||
CHAIN_KIND_ETHEREUM,
|
||||
CHAIN_KIND_ETHEREUM_CLASSIC,
|
||||
CHAIN_KIND_EXPANSE,
|
||||
CHAIN_KIND_POA,
|
||||
CHAIN_KIND_RSK,
|
||||
CHAIN_KIND_UBIQ,
|
||||
CHAIN_KIND_WANCHAIN,
|
||||
CHAIN_KIND_KUSD
|
||||
} chain_kind_t;
|
||||
|
||||
typedef struct chain_config_s {
|
||||
const char* coinName; // ticker
|
||||
uint32_t chainId;
|
||||
chain_kind_t kind;
|
||||
|
||||
#ifdef TARGET_BLUE
|
||||
const char* header_text;
|
||||
unsigned int color_header;
|
||||
unsigned int color_dashboard;
|
||||
#endif // TARGET_BLUE
|
||||
|
||||
} chain_config_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,16 +19,24 @@
|
||||
|
||||
typedef struct tokenDefinition_t {
|
||||
uint8_t address[20];
|
||||
uint8_t ticker[6];
|
||||
uint8_t ticker[10];
|
||||
uint8_t decimals;
|
||||
} tokenDefinition_t;
|
||||
|
||||
#if defined(CHAIN_TYPE_ETHEREUM)
|
||||
#define NUM_TOKENS 340
|
||||
#elif defined(CHAIN_TYPE_UBIQ)
|
||||
#define NUM_TOKENS 6
|
||||
#elif defined(CHAIN_TYPE_EXPANSE)
|
||||
#define NUM_TOKENS 0
|
||||
#endif
|
||||
#define NUM_TOKENS_ETHEREUM 677
|
||||
#define NUM_TOKENS_ETHEREUM_CLASSIC 0
|
||||
#define NUM_TOKENS_POA 0
|
||||
#define NUM_TOKENS_RSK 0
|
||||
#define NUM_TOKENS_UBIQ 6
|
||||
#define NUM_TOKENS_EXPANSE 0
|
||||
#define NUM_TOKENS_WANCHAIN 0
|
||||
#define NUM_TOKENS_KUSD 0
|
||||
|
||||
extern tokenDefinition_t const TOKENS[NUM_TOKENS];
|
||||
extern tokenDefinition_t const TOKENS_ETHEREUM[NUM_TOKENS_ETHEREUM];
|
||||
extern tokenDefinition_t const TOKENS_ETHEREUM_CLASSIC[NUM_TOKENS_ETHEREUM_CLASSIC];
|
||||
extern tokenDefinition_t const TOKENS_POA[NUM_TOKENS_POA];
|
||||
extern tokenDefinition_t const TOKENS_RSK[NUM_TOKENS_RSK];
|
||||
extern tokenDefinition_t const TOKENS_UBIQ[NUM_TOKENS_UBIQ];
|
||||
extern tokenDefinition_t const TOKENS_EXPANSE[NUM_TOKENS_EXPANSE];
|
||||
extern tokenDefinition_t const TOKENS_WANCHAIN[NUM_TOKENS_WANCHAIN];
|
||||
extern tokenDefinition_t const TOKENS_KUSD[NUM_TOKENS_KUSD];
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#ifdef HAVE_U2F
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* Ledger Blue specific initialization
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "os.h"
|
||||
|
||||
#include "os_io_seproxyhal.h"
|
||||
|
||||
#include "u2f_io.h"
|
||||
#include "u2f_transport.h"
|
||||
|
||||
extern void u2f_reset_display(void);
|
||||
|
||||
volatile unsigned char u2fCommandSent = 0;
|
||||
volatile unsigned char u2fFirstCommand = 0;
|
||||
volatile unsigned char u2fClosed = 0;
|
||||
|
||||
void u2f_io_open_session(void) {
|
||||
// PRINTF("u2f_io_open_session\n");
|
||||
u2fCommandSent = 0;
|
||||
u2fFirstCommand = 1;
|
||||
u2fClosed = 0;
|
||||
}
|
||||
|
||||
unsigned char u2fSegment[MAX_SEGMENT_SIZE];
|
||||
|
||||
void u2f_io_send(uint8_t *buffer, uint16_t length,
|
||||
u2f_transport_media_t media) {
|
||||
if (media == U2F_MEDIA_USB) {
|
||||
os_memset(u2fSegment, 0, sizeof(u2fSegment));
|
||||
}
|
||||
os_memmove(u2fSegment, buffer, length);
|
||||
// PRINTF("u2f_io_send\n");
|
||||
if (u2fFirstCommand) {
|
||||
u2fFirstCommand = 0;
|
||||
}
|
||||
switch (media) {
|
||||
case U2F_MEDIA_USB:
|
||||
io_usb_send_apdu_data(u2fSegment, USB_SEGMENT_SIZE);
|
||||
break;
|
||||
#ifdef HAVE_BLE
|
||||
case U2F_MEDIA_BLE:
|
||||
BLE_protocol_send(buffer, length);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
PRINTF("Request to send on unsupported media %d\n", media);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void u2f_io_close_session(void) {
|
||||
// PRINTF("u2f_close_session\n");
|
||||
if (!u2fClosed) {
|
||||
// u2f_reset_display();
|
||||
u2fClosed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef __U2F_IO_H__
|
||||
|
||||
#define __U2F_IO_H__
|
||||
|
||||
#include "u2f_service.h"
|
||||
|
||||
#define EXCEPTION_DISCONNECT 0x80
|
||||
|
||||
void u2f_io_open_session(void);
|
||||
void u2f_io_send(uint8_t *buffer, uint16_t length, u2f_transport_media_t media);
|
||||
void u2f_io_close_session(void);
|
||||
|
||||
#endif
|
||||
@@ -1,281 +0,0 @@
|
||||
#ifdef HAVE_U2F
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "os.h"
|
||||
#include "cx.h"
|
||||
#include "u2f_service.h"
|
||||
#include "u2f_transport.h"
|
||||
#include "u2f_processing.h"
|
||||
|
||||
void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx);
|
||||
void u2f_proxy_response(u2f_service_t *service, unsigned int tx);
|
||||
|
||||
static const uint8_t SW_SUCCESS[] = {0x90, 0x00};
|
||||
static const uint8_t SW_PROOF_OF_PRESENCE_REQUIRED[] = {0x69, 0x85};
|
||||
static const uint8_t SW_BAD_KEY_HANDLE[] = {0x6A, 0x80};
|
||||
|
||||
static const uint8_t VERSION[] = {'U', '2', 'F', '_', 'V', '2', 0x90, 0x00};
|
||||
static const uint8_t DUMMY_ZERO[] = {0x00};
|
||||
|
||||
static const uint8_t SW_UNKNOWN_INSTRUCTION[] = {0x6d, 0x00};
|
||||
static const uint8_t SW_UNKNOWN_CLASS[] = {0x6e, 0x00};
|
||||
static const uint8_t SW_WRONG_LENGTH[] = {0x67, 0x00};
|
||||
static const uint8_t SW_INTERNAL[] = {0x6F, 0x00};
|
||||
|
||||
static const uint8_t NOTIFY_USER_PRESENCE_NEEDED[] = {
|
||||
KEEPALIVE_REASON_TUP_NEEDED};
|
||||
|
||||
static const uint8_t PROXY_MAGIC[] = {'w', '0', 'w'};
|
||||
|
||||
#define INIT_U2F_VERSION 0x02
|
||||
#define INIT_DEVICE_VERSION_MAJOR 0
|
||||
#define INIT_DEVICE_VERSION_MINOR 1
|
||||
#define INIT_BUILD_VERSION 0
|
||||
#define INIT_CAPABILITIES 0x00
|
||||
|
||||
#define FIDO_CLA 0x00
|
||||
#define FIDO_INS_ENROLL 0x01
|
||||
#define FIDO_INS_SIGN 0x02
|
||||
#define FIDO_INS_GET_VERSION 0x03
|
||||
|
||||
#define FIDO_INS_PROP_GET_COUNTER 0xC0 // U2F_VENDOR_FIRST
|
||||
|
||||
#define P1_SIGN_CHECK_ONLY 0x07
|
||||
#define P1_SIGN_SIGN 0x03
|
||||
|
||||
#define U2F_ENROLL_RESERVED 0x05
|
||||
#define SIGN_USER_PRESENCE_MASK 0x01
|
||||
|
||||
#define MAX_SEQ_TIMEOUT_MS 500
|
||||
#define MAX_KEEPALIVE_TIMEOUT_MS 500
|
||||
|
||||
static const uint8_t DUMMY_USER_PRESENCE[] = {SIGN_USER_PRESENCE_MASK};
|
||||
|
||||
|
||||
void u2f_handle_enroll(u2f_service_t *service, uint8_t p1, uint8_t p2,
|
||||
uint8_t *buffer, uint16_t length) {
|
||||
(void)p1;
|
||||
(void)p2;
|
||||
(void)buffer;
|
||||
if (length != 32 + 32) {
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_WRONG_LENGTH,
|
||||
sizeof(SW_WRONG_LENGTH), true);
|
||||
return;
|
||||
}
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG, (uint8_t *)SW_INTERNAL,
|
||||
sizeof(SW_INTERNAL), true);
|
||||
}
|
||||
|
||||
void u2f_handle_sign(u2f_service_t *service, uint8_t p1, uint8_t p2,
|
||||
uint8_t *buffer, uint16_t length) {
|
||||
(void)p1;
|
||||
(void)p2;
|
||||
(void)length;
|
||||
uint8_t keyHandleLength;
|
||||
uint8_t i;
|
||||
volatile unsigned int flags = 0;
|
||||
volatile unsigned int tx = 0;
|
||||
|
||||
if (length < 32 + 32 + 1) {
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_WRONG_LENGTH,
|
||||
sizeof(SW_WRONG_LENGTH), true);
|
||||
return;
|
||||
}
|
||||
if ((p1 != P1_SIGN_CHECK_ONLY) && (p1 != P1_SIGN_SIGN)) {
|
||||
u2f_response_error(service, ERROR_PROP_INVALID_PARAMETERS_APDU, true,
|
||||
service->channel);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
keyHandleLength = buffer[64];
|
||||
for (i = 0; i < keyHandleLength; i++) {
|
||||
buffer[65 + i] ^= PROXY_MAGIC[i % sizeof(PROXY_MAGIC)];
|
||||
}
|
||||
// Check magic
|
||||
if (length != (32 + 32 + 1 + 5 + buffer[65 + 4])) {
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_BAD_KEY_HANDLE,
|
||||
sizeof(SW_BAD_KEY_HANDLE), true);
|
||||
}
|
||||
// Check that it looks like an APDU
|
||||
os_memmove(G_io_apdu_buffer, buffer + 65, keyHandleLength);
|
||||
handleApdu(&flags, &tx);
|
||||
if ((flags & IO_ASYNCH_REPLY) == 0) {
|
||||
u2f_proxy_response(service, tx);
|
||||
}
|
||||
}
|
||||
|
||||
void u2f_handle_get_version(u2f_service_t *service, uint8_t p1, uint8_t p2,
|
||||
uint8_t *buffer, uint16_t length) {
|
||||
// screen_printf("U2F version\n");
|
||||
(void)p1;
|
||||
(void)p2;
|
||||
(void)buffer;
|
||||
if (length != 0) {
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_WRONG_LENGTH,
|
||||
sizeof(SW_WRONG_LENGTH), true);
|
||||
return;
|
||||
}
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG, (uint8_t *)VERSION,
|
||||
sizeof(VERSION), true);
|
||||
}
|
||||
|
||||
void u2f_handle_cmd_init(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t length, uint8_t *channelInit) {
|
||||
// screen_printf("U2F init\n");
|
||||
uint8_t channel[4];
|
||||
(void)length;
|
||||
uint16_t offset = 0;
|
||||
if (u2f_is_channel_forbidden(channelInit)) {
|
||||
u2f_response_error(service, ERROR_INVALID_CID, true, channelInit);
|
||||
return;
|
||||
}
|
||||
if (u2f_is_channel_broadcast(channelInit)) {
|
||||
cx_rng(channel, 4);
|
||||
} else {
|
||||
os_memmove(channel, channelInit, 4);
|
||||
}
|
||||
os_memmove(service->messageBuffer + offset, buffer, 8);
|
||||
offset += 8;
|
||||
os_memmove(service->messageBuffer + offset, channel, 4);
|
||||
offset += 4;
|
||||
service->messageBuffer[offset++] = INIT_U2F_VERSION;
|
||||
service->messageBuffer[offset++] = INIT_DEVICE_VERSION_MAJOR;
|
||||
service->messageBuffer[offset++] = INIT_DEVICE_VERSION_MINOR;
|
||||
service->messageBuffer[offset++] = INIT_BUILD_VERSION;
|
||||
service->messageBuffer[offset++] = INIT_CAPABILITIES;
|
||||
if (u2f_is_channel_broadcast(channelInit)) {
|
||||
os_memset(service->channel, 0xff, 4);
|
||||
} else {
|
||||
os_memmove(service->channel, channel, 4);
|
||||
}
|
||||
service->keepUserPresence = true;
|
||||
u2f_send_fragmented_response(service, U2F_CMD_INIT, service->messageBuffer,
|
||||
offset, true);
|
||||
// os_memmove(service->channel, channel, 4);
|
||||
}
|
||||
|
||||
void u2f_handle_cmd_ping(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t length) {
|
||||
// screen_printf("U2F ping\n");
|
||||
u2f_send_fragmented_response(service, U2F_CMD_PING, buffer, length, true);
|
||||
}
|
||||
|
||||
void u2f_handle_cmd_msg(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t length) {
|
||||
// screen_printf("U2F msg\n");
|
||||
uint8_t cla = buffer[0];
|
||||
uint8_t ins = buffer[1];
|
||||
uint8_t p1 = buffer[2];
|
||||
uint8_t p2 = buffer[3];
|
||||
uint32_t dataLength = (buffer[4] << 16) | (buffer[5] << 8) | (buffer[6]);
|
||||
if ((dataLength != (uint16_t)(length - 9)) &&
|
||||
(dataLength != (uint16_t)(length - 7))) { // Le is optional
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_WRONG_LENGTH,
|
||||
sizeof(SW_WRONG_LENGTH), true);
|
||||
return;
|
||||
}
|
||||
if (cla != FIDO_CLA) {
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_UNKNOWN_CLASS,
|
||||
sizeof(SW_UNKNOWN_CLASS), true);
|
||||
return;
|
||||
}
|
||||
switch (ins) {
|
||||
case FIDO_INS_ENROLL:
|
||||
// screen_printf("enroll\n");
|
||||
u2f_handle_enroll(service, p1, p2, buffer + 7, dataLength);
|
||||
break;
|
||||
case FIDO_INS_SIGN:
|
||||
// screen_printf("sign\n");
|
||||
u2f_handle_sign(service, p1, p2, buffer + 7, dataLength);
|
||||
break;
|
||||
case FIDO_INS_GET_VERSION:
|
||||
// screen_printf("version\n");
|
||||
u2f_handle_get_version(service, p1, p2, buffer + 7, dataLength);
|
||||
break;
|
||||
default:
|
||||
// screen_printf("unsupported\n");
|
||||
u2f_send_fragmented_response(service, U2F_CMD_MSG,
|
||||
(uint8_t *)SW_UNKNOWN_INSTRUCTION,
|
||||
sizeof(SW_UNKNOWN_INSTRUCTION), true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void u2f_process_message(u2f_service_t *service, uint8_t *buffer,
|
||||
uint8_t *channel) {
|
||||
uint8_t cmd = buffer[0];
|
||||
uint16_t length = (buffer[1] << 8) | (buffer[2]);
|
||||
switch (cmd) {
|
||||
case U2F_CMD_INIT:
|
||||
u2f_handle_cmd_init(service, buffer + 3, length, channel);
|
||||
break;
|
||||
case U2F_CMD_PING:
|
||||
service->pendingContinuation = false;
|
||||
u2f_handle_cmd_ping(service, buffer + 3, length);
|
||||
break;
|
||||
case U2F_CMD_MSG:
|
||||
service->pendingContinuation = false;
|
||||
if (!service->noReentry && service->runningCommand) {
|
||||
u2f_response_error(service, ERROR_CHANNEL_BUSY, false,
|
||||
service->channel);
|
||||
break;
|
||||
}
|
||||
service->runningCommand = true;
|
||||
u2f_handle_cmd_msg(service, buffer + 3, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void u2f_timeout(u2f_service_t *service) {
|
||||
service->timerNeedGeneralStatus = true;
|
||||
if ((service->transportMedia == U2F_MEDIA_USB) &&
|
||||
(service->pendingContinuation)) {
|
||||
service->seqTimeout += service->timerInterval;
|
||||
if (service->seqTimeout > MAX_SEQ_TIMEOUT_MS) {
|
||||
service->pendingContinuation = false;
|
||||
u2f_response_error(service, ERROR_MSG_TIMEOUT, true,
|
||||
service->lastContinuationChannel);
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_BLE
|
||||
if ((service->transportMedia == U2F_MEDIA_BLE) &&
|
||||
(service->requireKeepalive)) {
|
||||
service->keepaliveTimeout += service->timerInterval;
|
||||
if (service->keepaliveTimeout > MAX_KEEPALIVE_TIMEOUT_MS) {
|
||||
service->keepaliveTimeout = 0;
|
||||
u2f_send_fragmented_response(service, U2F_CMD_KEEPALIVE,
|
||||
(uint8_t *)NOTIFY_USER_PRESENCE_NEEDED,
|
||||
sizeof(NOTIFY_USER_PRESENCE_NEEDED),
|
||||
false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef __U2F_PROCESSING_H__
|
||||
|
||||
#define __U2F_PROCESSING_H__
|
||||
|
||||
void u2f_process_message(u2f_service_t *service, uint8_t *buffer,
|
||||
uint8_t *channel);
|
||||
void u2f_timeout(u2f_service_t *service);
|
||||
|
||||
void u2f_handle_ux_callback(u2f_service_t *service);
|
||||
|
||||
#endif
|
||||
@@ -1,146 +0,0 @@
|
||||
#ifdef HAVE_U2F
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "u2f_service.h"
|
||||
#include "u2f_transport.h"
|
||||
#include "u2f_processing.h"
|
||||
#include "u2f_timer.h"
|
||||
|
||||
// not too fast blinking
|
||||
#define DEFAULT_TIMER_INTERVAL_MS 500
|
||||
|
||||
void u2f_reset(u2f_service_t *service, bool keepUserPresence) {
|
||||
service->transportState = U2F_IDLE;
|
||||
service->runningCommand = false;
|
||||
// service->promptUserPresence = false;
|
||||
if (service->keepUserPresence) {
|
||||
keepUserPresence = true;
|
||||
service->keepUserPresence = false;
|
||||
}
|
||||
#ifdef HAVE_NO_USER_PRESENCE_CHECK
|
||||
service->keepUserPresence = true;
|
||||
service->userPresence = true;
|
||||
#endif // HAVE_NO_USER_PRESENCE_CHECK
|
||||
}
|
||||
|
||||
void u2f_initialize_service(u2f_service_t *service) {
|
||||
service->handleFunction = (u2fHandle_t)u2f_process_message;
|
||||
service->timeoutFunction = (u2fTimer_t)u2f_timeout;
|
||||
service->timerInterval = DEFAULT_TIMER_INTERVAL_MS;
|
||||
u2f_reset(service, false);
|
||||
service->promptUserPresence = false;
|
||||
service->userPresence = false;
|
||||
#ifdef HAVE_NO_USER_PRESENCE_CHECK
|
||||
service->keepUserPresence = true;
|
||||
service->userPresence = true;
|
||||
#endif // HAVE_NO_USER_PRESENCE_CHECK
|
||||
}
|
||||
|
||||
void u2f_send_direct_response_short(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t len) {
|
||||
(void)service;
|
||||
uint16_t maxSize = 0;
|
||||
switch (service->packetMedia) {
|
||||
case U2F_MEDIA_USB:
|
||||
maxSize = USB_SEGMENT_SIZE;
|
||||
break;
|
||||
#ifdef HAVE_BLE
|
||||
case U2F_MEDIA_BLE:
|
||||
maxSize = service->bleMtu;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
PRINTF("Request to send on unsupported media %d\n",
|
||||
service->packetMedia);
|
||||
break;
|
||||
}
|
||||
if (len > maxSize) {
|
||||
return;
|
||||
}
|
||||
u2f_io_send(buffer, len, service->packetMedia);
|
||||
u2f_io_close_session();
|
||||
}
|
||||
|
||||
void u2f_send_fragmented_response(u2f_service_t *service, uint8_t cmd,
|
||||
uint8_t *buffer, uint16_t len,
|
||||
bool resetAfterSend) {
|
||||
if (resetAfterSend) {
|
||||
service->transportState = U2F_SENDING_RESPONSE;
|
||||
}
|
||||
service->sending = true;
|
||||
service->sendPacketIndex = 0;
|
||||
service->sendBuffer = buffer;
|
||||
service->sendOffset = 0;
|
||||
service->sendLength = len;
|
||||
service->sendCmd = cmd;
|
||||
service->resetAfterSend = resetAfterSend;
|
||||
u2f_continue_sending_fragmented_response(service);
|
||||
}
|
||||
|
||||
void u2f_continue_sending_fragmented_response(u2f_service_t *service) {
|
||||
do {
|
||||
uint16_t channelHeader =
|
||||
(service->transportMedia == U2F_MEDIA_USB ? 4 : 0);
|
||||
uint8_t headerSize =
|
||||
(service->sendPacketIndex == 0 ? (channelHeader + 3)
|
||||
: (channelHeader + 1));
|
||||
uint16_t maxBlockSize =
|
||||
(service->transportMedia == U2F_MEDIA_USB ? USB_SEGMENT_SIZE
|
||||
: service->bleMtu);
|
||||
uint16_t blockSize = ((service->sendLength - service->sendOffset) >
|
||||
(maxBlockSize - headerSize)
|
||||
? (maxBlockSize - headerSize)
|
||||
: service->sendLength - service->sendOffset);
|
||||
uint16_t dataSize = blockSize + headerSize;
|
||||
uint16_t offset = 0;
|
||||
// Fragment
|
||||
if (service->transportMedia == U2F_MEDIA_USB) {
|
||||
os_memset(service->outputBuffer, 0, USB_SEGMENT_SIZE);
|
||||
os_memmove(service->outputBuffer + offset, service->channel, 4);
|
||||
offset += 4;
|
||||
}
|
||||
if (service->sendPacketIndex == 0) {
|
||||
service->outputBuffer[offset++] = service->sendCmd;
|
||||
service->outputBuffer[offset++] = (service->sendLength >> 8);
|
||||
service->outputBuffer[offset++] = (service->sendLength & 0xff);
|
||||
} else {
|
||||
service->outputBuffer[offset++] = (service->sendPacketIndex - 1);
|
||||
}
|
||||
if (service->sendBuffer != NULL) {
|
||||
os_memmove(service->outputBuffer + headerSize,
|
||||
service->sendBuffer + service->sendOffset, blockSize);
|
||||
}
|
||||
u2f_io_send(service->outputBuffer, dataSize, service->packetMedia);
|
||||
service->sendOffset += blockSize;
|
||||
service->sendPacketIndex++;
|
||||
} while (service->sendOffset != service->sendLength);
|
||||
if (service->sendOffset == service->sendLength) {
|
||||
u2f_io_close_session();
|
||||
service->sending = false;
|
||||
if (service->resetAfterSend) {
|
||||
u2f_reset(service, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef __U2F_SERVICE_H__
|
||||
|
||||
#define __U2F_SERVICE_H__
|
||||
|
||||
struct u2f_service_t;
|
||||
|
||||
typedef void (*u2fHandle_t)(struct u2f_service_t *service, uint8_t *inputBuffer,
|
||||
uint8_t *channel);
|
||||
typedef void (*u2fPromptUserPresence_t)(struct u2f_service_t *service,
|
||||
bool enroll,
|
||||
uint8_t *applicationParameter);
|
||||
typedef void (*u2fTimer_t)(struct u2f_service_t *service);
|
||||
|
||||
typedef enum {
|
||||
U2F_IDLE,
|
||||
U2F_HANDLE_SEGMENTED,
|
||||
U2F_PROCESSING_COMMAND,
|
||||
U2F_SENDING_RESPONSE
|
||||
} u2f_transport_state_t;
|
||||
|
||||
typedef enum {
|
||||
U2F_MEDIA_NONE,
|
||||
U2F_MEDIA_USB,
|
||||
U2F_MEDIA_NFC,
|
||||
U2F_MEDIA_BLE
|
||||
} u2f_transport_media_t;
|
||||
|
||||
typedef struct u2f_service_t {
|
||||
// Internal
|
||||
|
||||
uint8_t channel[4];
|
||||
uint8_t lastContinuationChannel[4];
|
||||
uint16_t transportOffset;
|
||||
u2f_transport_state_t transportState;
|
||||
u2f_transport_media_t transportMedia;
|
||||
u2f_transport_media_t packetMedia;
|
||||
uint8_t expectedContinuationPacket;
|
||||
uint16_t lastCommandLength;
|
||||
bool runningCommand;
|
||||
|
||||
u2fHandle_t handleFunction;
|
||||
|
||||
bool userPresence;
|
||||
bool promptUserPresence;
|
||||
bool reportUserPresence;
|
||||
bool keepUserPresence;
|
||||
u2fPromptUserPresence_t promptUserPresenceFunction;
|
||||
|
||||
u2fTimer_t timeoutFunction;
|
||||
uint32_t timerInterval;
|
||||
bool timerNeedGeneralStatus;
|
||||
uint32_t seqTimeout;
|
||||
bool pendingContinuation;
|
||||
bool requireKeepalive;
|
||||
uint32_t keepaliveTimeout;
|
||||
|
||||
bool sending;
|
||||
uint8_t sendPacketIndex;
|
||||
uint8_t *sendBuffer;
|
||||
uint16_t sendOffset;
|
||||
uint16_t sendLength;
|
||||
uint8_t sendCmd;
|
||||
bool resetAfterSend;
|
||||
|
||||
// External, to be filled
|
||||
|
||||
uint8_t *inputBuffer;
|
||||
uint8_t *outputBuffer;
|
||||
uint8_t *messageBuffer;
|
||||
uint16_t messageBufferSize;
|
||||
uint8_t *confirmedApplicationParameter;
|
||||
bool noReentry;
|
||||
uint16_t bleMtu;
|
||||
} u2f_service_t;
|
||||
|
||||
void u2f_initialize_service(u2f_service_t *service);
|
||||
void u2f_send_direct_response_short(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t len);
|
||||
void u2f_send_fragmented_response(u2f_service_t *service, uint8_t cmd,
|
||||
uint8_t *buffer, uint16_t len,
|
||||
bool resetAfterSend);
|
||||
void u2f_confirm_user_presence(u2f_service_t *service, bool userPresence,
|
||||
bool resume);
|
||||
void u2f_continue_sending_fragmented_response(u2f_service_t *service);
|
||||
void u2f_reset(u2f_service_t *service, bool keepUserPresence);
|
||||
|
||||
// export global
|
||||
extern volatile u2f_service_t u2fService;
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef __U2F_TIMER_H__
|
||||
|
||||
#define __U2F_TIMER_H__
|
||||
|
||||
typedef void (*u2fTimer_t)(struct u2f_service_t *service);
|
||||
|
||||
void u2f_timer_init(void);
|
||||
void u2f_timer_register(uint32_t timerMs, u2fTimer_t timerCallback);
|
||||
void u2f_timer_cancel(void);
|
||||
|
||||
#endif
|
||||
@@ -1,227 +0,0 @@
|
||||
#ifdef HAVE_U2F
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "u2f_service.h"
|
||||
#include "u2f_transport.h"
|
||||
|
||||
#define U2F_MASK_COMMAND 0x80
|
||||
#define U2F_COMMAND_HEADER_SIZE 3
|
||||
|
||||
static const uint8_t const BROADCAST_CHANNEL[] = {0xff, 0xff, 0xff, 0xff};
|
||||
static const uint8_t const FORBIDDEN_CHANNEL[] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
void u2f_transport_handle(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t size, u2f_transport_media_t media) {
|
||||
uint16_t channelHeader = (media == U2F_MEDIA_USB ? 4 : 0);
|
||||
uint8_t channel[4] = {0};
|
||||
if (media == U2F_MEDIA_USB) {
|
||||
os_memmove(channel, buffer, 4);
|
||||
}
|
||||
// screen_printf("U2F transport\n");
|
||||
service->packetMedia = media;
|
||||
u2f_io_open_session();
|
||||
// If busy, answer immediately
|
||||
if (service->noReentry) {
|
||||
if ((service->transportState == U2F_PROCESSING_COMMAND) ||
|
||||
(service->transportState == U2F_SENDING_RESPONSE)) {
|
||||
u2f_response_error(service, ERROR_CHANNEL_BUSY, false, channel);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (size < (1 + channelHeader)) {
|
||||
// Message to short, abort
|
||||
u2f_response_error(service, ERROR_PROP_MESSAGE_TOO_SHORT, true,
|
||||
channel);
|
||||
goto error;
|
||||
}
|
||||
if ((buffer[channelHeader] & U2F_MASK_COMMAND) != 0) {
|
||||
if (size < (channelHeader + 3)) {
|
||||
// Message to short, abort
|
||||
u2f_response_error(service, ERROR_PROP_MESSAGE_TOO_SHORT, true,
|
||||
channel);
|
||||
goto error;
|
||||
}
|
||||
// If waiting for a continuation on a different channel, reply BUSY
|
||||
// immediately
|
||||
if (media == U2F_MEDIA_USB) {
|
||||
if ((service->pendingContinuation) &&
|
||||
(os_memcmp(channel, service->lastContinuationChannel, 4) !=
|
||||
0) &&
|
||||
(buffer[channelHeader] != U2F_CMD_INIT)) {
|
||||
u2f_response_error(service, ERROR_CHANNEL_BUSY, false, channel);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
// If a command was already sent, and we are not processing a INIT
|
||||
// command, abort
|
||||
if ((service->transportState == U2F_HANDLE_SEGMENTED) &&
|
||||
!((media == U2F_MEDIA_USB) &&
|
||||
(buffer[channelHeader] == U2F_CMD_INIT))) {
|
||||
// Unexpected continuation at this stage, abort
|
||||
u2f_response_error(service, ERROR_INVALID_SEQ, true, channel);
|
||||
goto error;
|
||||
}
|
||||
// Check the length
|
||||
uint16_t commandLength =
|
||||
(buffer[channelHeader + 1] << 8) | (buffer[channelHeader + 2]);
|
||||
if (commandLength > (service->messageBufferSize - 3)) {
|
||||
// Overflow in message size, abort
|
||||
u2f_response_error(service, ERROR_INVALID_LEN, true, channel);
|
||||
goto error;
|
||||
}
|
||||
// Check if the command is supported
|
||||
switch (buffer[channelHeader]) {
|
||||
case U2F_CMD_PING:
|
||||
case U2F_CMD_MSG:
|
||||
if (media == U2F_MEDIA_USB) {
|
||||
if (u2f_is_channel_broadcast(channel) ||
|
||||
u2f_is_channel_forbidden(channel)) {
|
||||
u2f_response_error(service, ERROR_INVALID_CID, true,
|
||||
channel);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case U2F_CMD_INIT:
|
||||
if (media != U2F_MEDIA_USB) {
|
||||
// Unknown command, abort
|
||||
u2f_response_error(service, ERROR_INVALID_CMD, true, channel);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unknown command, abort
|
||||
u2f_response_error(service, ERROR_INVALID_CMD, true, channel);
|
||||
goto error;
|
||||
}
|
||||
// Ok, initialize the buffer
|
||||
os_memmove(service->channel, channel, 4);
|
||||
service->lastCommandLength = commandLength;
|
||||
service->expectedContinuationPacket = 0;
|
||||
os_memmove(service->messageBuffer, buffer + channelHeader,
|
||||
size - channelHeader);
|
||||
service->transportOffset = size - channelHeader;
|
||||
service->transportMedia = media;
|
||||
} else {
|
||||
// Continuation
|
||||
if (size < (channelHeader + 2)) {
|
||||
// Message to short, abort
|
||||
u2f_response_error(service, ERROR_PROP_MESSAGE_TOO_SHORT, true,
|
||||
channel);
|
||||
goto error;
|
||||
}
|
||||
if (media != service->transportMedia) {
|
||||
// Mixed medias
|
||||
u2f_response_error(service, ERROR_PROP_MEDIA_MIXED, true, channel);
|
||||
goto error;
|
||||
}
|
||||
if (service->transportState != U2F_HANDLE_SEGMENTED) {
|
||||
// Unexpected continuation at this stage, abort
|
||||
// TODO : review the behavior is HID only
|
||||
if (media == U2F_MEDIA_USB) {
|
||||
u2f_reset(service, true);
|
||||
goto error;
|
||||
} else {
|
||||
u2f_response_error(service, ERROR_INVALID_SEQ, true, channel);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (media == U2F_MEDIA_USB) {
|
||||
// Check the channel
|
||||
if (os_memcmp(buffer, service->channel, 4) != 0) {
|
||||
u2f_response_error(service, ERROR_CHANNEL_BUSY, true, channel);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer[channelHeader] != service->expectedContinuationPacket) {
|
||||
// Bad continuation packet, abort
|
||||
u2f_response_error(service, ERROR_INVALID_SEQ, true, channel);
|
||||
goto error;
|
||||
}
|
||||
if ((service->transportOffset + (size - (channelHeader + 1))) >
|
||||
(service->messageBufferSize - 3)) {
|
||||
// Overflow, abort
|
||||
u2f_response_error(service, ERROR_INVALID_LEN, true, channel);
|
||||
goto error;
|
||||
}
|
||||
os_memmove(service->messageBuffer + service->transportOffset,
|
||||
buffer + channelHeader + 1, size - (channelHeader + 1));
|
||||
service->transportOffset += size - (channelHeader + 1);
|
||||
service->expectedContinuationPacket++;
|
||||
}
|
||||
// See if we can process the command
|
||||
if ((media != U2F_MEDIA_USB) &&
|
||||
(service->transportOffset >
|
||||
(service->lastCommandLength + U2F_COMMAND_HEADER_SIZE))) {
|
||||
// Overflow, abort
|
||||
u2f_response_error(service, ERROR_INVALID_LEN, true, channel);
|
||||
goto error;
|
||||
} else if (service->transportOffset >=
|
||||
(service->lastCommandLength + U2F_COMMAND_HEADER_SIZE)) {
|
||||
// screen_printf("Process command\n");
|
||||
service->transportState = U2F_PROCESSING_COMMAND;
|
||||
service->handleFunction(service, service->messageBuffer, channel);
|
||||
} else {
|
||||
// screen_printf("segmented\n");
|
||||
service->seqTimeout = 0;
|
||||
service->transportState = U2F_HANDLE_SEGMENTED;
|
||||
service->pendingContinuation = true;
|
||||
os_memmove(service->lastContinuationChannel, channel, 4);
|
||||
u2f_io_close_session();
|
||||
}
|
||||
return;
|
||||
error:
|
||||
if ((media == U2F_MEDIA_USB) && (service->pendingContinuation) &&
|
||||
(os_memcmp(channel, service->lastContinuationChannel, 4) == 0)) {
|
||||
service->pendingContinuation = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void u2f_response_error(u2f_service_t *service, char errorCode, bool reset,
|
||||
uint8_t *channel) {
|
||||
uint8_t offset = 0;
|
||||
os_memset(service->outputBuffer, 0, MAX_SEGMENT_SIZE);
|
||||
if (service->transportMedia == U2F_MEDIA_USB) {
|
||||
os_memmove(service->outputBuffer + offset, channel, 4);
|
||||
offset += 4;
|
||||
}
|
||||
service->outputBuffer[offset++] = U2F_STATUS_ERROR;
|
||||
service->outputBuffer[offset++] = 0x00;
|
||||
service->outputBuffer[offset++] = 0x01;
|
||||
service->outputBuffer[offset++] = errorCode;
|
||||
u2f_send_direct_response_short(service, service->outputBuffer, offset);
|
||||
if (reset) {
|
||||
u2f_reset(service, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool u2f_is_channel_broadcast(uint8_t *channel) {
|
||||
return (os_memcmp(channel, BROADCAST_CHANNEL, 4) == 0);
|
||||
}
|
||||
|
||||
bool u2f_is_channel_forbidden(uint8_t *channel) {
|
||||
return (os_memcmp(channel, FORBIDDEN_CHANNEL, 4) == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Portable FIDO U2F implementation
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef __U2F_TRANSPORT_H__
|
||||
|
||||
#define __U2F_TRANSPORT_H__
|
||||
|
||||
#include "u2f_service.h"
|
||||
|
||||
#define MAX_SEGMENT_SIZE \
|
||||
(USB_SEGMENT_SIZE > BLE_SEGMENT_SIZE ? USB_SEGMENT_SIZE : BLE_SEGMENT_SIZE)
|
||||
|
||||
// Shared commands
|
||||
#define U2F_CMD_PING 0x81
|
||||
#define U2F_CMD_MSG 0x83
|
||||
|
||||
// USB only commands
|
||||
#define U2F_CMD_INIT 0x86
|
||||
#define U2F_CMD_LOCK 0x84
|
||||
#define U2F_CMD_WINK 0x88
|
||||
|
||||
// BLE only commands
|
||||
#define U2F_CMD_KEEPALIVE 0x82
|
||||
#define KEEPALIVE_REASON_PROCESSING 0x01
|
||||
#define KEEPALIVE_REASON_TUP_NEEDED 0x02
|
||||
|
||||
#define U2F_STATUS_ERROR 0xBF
|
||||
|
||||
// Shared errors
|
||||
#define ERROR_NONE 0x00
|
||||
#define ERROR_INVALID_CMD 0x01
|
||||
#define ERROR_INVALID_PAR 0x02
|
||||
#define ERROR_INVALID_LEN 0x03
|
||||
#define ERROR_INVALID_SEQ 0x04
|
||||
#define ERROR_MSG_TIMEOUT 0x05
|
||||
#define ERROR_OTHER 0x7f
|
||||
// USB only errors
|
||||
#define ERROR_CHANNEL_BUSY 0x06
|
||||
#define ERROR_LOCK_REQUIRED 0x0a
|
||||
#define ERROR_INVALID_CID 0x0b
|
||||
#define ERROR_PROP_UNKNOWN_COMMAND 0x80
|
||||
#define ERROR_PROP_COMMAND_TOO_LONG 0x81
|
||||
#define ERROR_PROP_INVALID_CONTINUATION 0x82
|
||||
#define ERROR_PROP_UNEXPECTED_CONTINUATION 0x83
|
||||
#define ERROR_PROP_CONTINUATION_OVERFLOW 0x84
|
||||
#define ERROR_PROP_MESSAGE_TOO_SHORT 0x85
|
||||
#define ERROR_PROP_UNCONSISTENT_MSG_LENGTH 0x86
|
||||
#define ERROR_PROP_UNSUPPORTED_MSG_APDU 0x87
|
||||
#define ERROR_PROP_INVALID_DATA_LENGTH_APDU 0x88
|
||||
#define ERROR_PROP_INTERNAL_ERROR_APDU 0x89
|
||||
#define ERROR_PROP_INVALID_PARAMETERS_APDU 0x8A
|
||||
#define ERROR_PROP_INVALID_DATA_APDU 0x8B
|
||||
#define ERROR_PROP_DEVICE_NOT_SETUP 0x8C
|
||||
#define ERROR_PROP_MEDIA_MIXED 0x8D
|
||||
|
||||
void u2f_transport_handle(u2f_service_t *service, uint8_t *buffer,
|
||||
uint16_t size, u2f_transport_media_t media);
|
||||
void u2f_response_error(u2f_service_t *service, char errorCode, bool reset,
|
||||
uint8_t *channel);
|
||||
bool u2f_is_channel_broadcast(uint8_t *channel);
|
||||
bool u2f_is_channel_forbidden(uint8_t *channel);
|
||||
|
||||
#endif
|
||||
@@ -1,545 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file usbd_hid.c
|
||||
* @author MCD Application Team
|
||||
* @version V2.2.0
|
||||
* @date 13-June-2014
|
||||
* @brief This file provides the HID core functions.
|
||||
*
|
||||
* @verbatim
|
||||
*
|
||||
* ===================================================================
|
||||
* HID Class Description
|
||||
* ===================================================================
|
||||
* This module manages the HID class V1.11 following the "Device
|
||||
*Class Definition
|
||||
* for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
|
||||
* This driver implements the following aspects of the specification:
|
||||
* - The Boot Interface Subclass
|
||||
* - Usage Page : Generic Desktop
|
||||
* - Usage : Vendor
|
||||
* - Collection : Application
|
||||
*
|
||||
* @note In HS mode and when the DMA is used, all variables and data
|
||||
*structures
|
||||
* dealing with the DMA during the transaction process should be
|
||||
*32-bit aligned.
|
||||
*
|
||||
*
|
||||
* @endverbatim
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2014 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.st.com/software_license_agreement_liberty_v2
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#include "os.h"
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usbd_hid.h"
|
||||
#include "usbd_ctlreq.h"
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_conf.h"
|
||||
|
||||
#include "usbd_def.h"
|
||||
#include "os_io_seproxyhal.h"
|
||||
|
||||
#include "u2f_service.h"
|
||||
#include "u2f_transport.h"
|
||||
|
||||
/** @togroup STM32_USB_DEVICE_LIBRARY
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_HID
|
||||
* @brief usbd core module
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_HID_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_HID_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_HID_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/** @defgroup USBD_HID_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_HID_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define HID_EPIN_ADDR 0x82
|
||||
#define HID_EPIN_SIZE 0x40
|
||||
|
||||
#define HID_EPOUT_ADDR 0x02
|
||||
#define HID_EPOUT_SIZE 0x40
|
||||
|
||||
#define USBD_LANGID_STRING 0x409
|
||||
|
||||
#ifdef HAVE_VID_PID_PROBER
|
||||
#define USBD_VID 0x2581
|
||||
#define USBD_PID 0xf1d1
|
||||
#else
|
||||
#define USBD_VID 0x2C97
|
||||
#if defined(TARGET_BLUE) // blue
|
||||
#define USBD_PID 0x0000
|
||||
const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
||||
4 * 2 + 2, USB_DESC_TYPE_STRING, 'B', 0, 'l', 0, 'u', 0, 'e', 0,
|
||||
};
|
||||
|
||||
#elif defined(TARGET_NANOS) // nano s
|
||||
#define USBD_PID 0x0001
|
||||
const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
||||
6 * 2 + 2, USB_DESC_TYPE_STRING,
|
||||
'N', 0,
|
||||
'a', 0,
|
||||
'n', 0,
|
||||
'o', 0,
|
||||
' ', 0,
|
||||
'S', 0,
|
||||
};
|
||||
#elif defined(TARGET_ARAMIS) // aramis
|
||||
#define USBD_PID 0x0002
|
||||
const uint8_t const USBD_PRODUCT_FS_STRING[] = {
|
||||
6 * 2 + 2, USB_DESC_TYPE_STRING,
|
||||
'A', 0,
|
||||
'r', 0,
|
||||
'a', 0,
|
||||
'm', 0,
|
||||
'i', 0,
|
||||
's', 0,
|
||||
};
|
||||
#else
|
||||
#error unknown TARGET_ID
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* USB Standard Device Descriptor */
|
||||
const uint8_t const USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] = {
|
||||
USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING, LOBYTE(USBD_LANGID_STRING),
|
||||
HIBYTE(USBD_LANGID_STRING),
|
||||
};
|
||||
|
||||
const uint8_t const USB_SERIAL_STRING[] = {
|
||||
4 * 2 + 2, USB_DESC_TYPE_STRING, '0', 0, '0', 0, '0', 0, '1', 0,
|
||||
};
|
||||
|
||||
const uint8_t const USBD_MANUFACTURER_STRING[] = {
|
||||
6 * 2 + 2, USB_DESC_TYPE_STRING,
|
||||
'L', 0,
|
||||
'e', 0,
|
||||
'd', 0,
|
||||
'g', 0,
|
||||
'e', 0,
|
||||
'r', 0,
|
||||
};
|
||||
|
||||
#define USBD_INTERFACE_FS_STRING USBD_PRODUCT_FS_STRING
|
||||
#define USBD_CONFIGURATION_FS_STRING USBD_PRODUCT_FS_STRING
|
||||
|
||||
const uint8_t const HID_ReportDesc[] = {
|
||||
0x06, 0xD0, 0xF1, // Usage page (vendor defined)
|
||||
0x09, 0x01, // Usage ID (vendor defined)
|
||||
0xA1, 0x01, // Collection (application)
|
||||
|
||||
// The Input report
|
||||
0x09, 0x03, // Usage ID - vendor defined
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8 bits)
|
||||
0x95, HID_EPIN_SIZE, // Report Count (64 fields)
|
||||
0x81, 0x08, // Input (Data, Variable, Absolute)
|
||||
|
||||
// The Output report
|
||||
0x09, 0x04, // Usage ID - vendor defined
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8 bits)
|
||||
0x95, HID_EPOUT_SIZE, // Report Count (64 fields)
|
||||
0x91, 0x08, // Output (Data, Variable, Absolute)
|
||||
0xC0};
|
||||
|
||||
#define PAGE_FIDO 0xF1D0
|
||||
#define PAGE_GENERIC 0xFFA0
|
||||
|
||||
uint8_t HID_DynReportDesc[sizeof(HID_ReportDesc)];
|
||||
bool fidoActivated;
|
||||
|
||||
/* USB HID device Configuration Descriptor */
|
||||
__ALIGN_BEGIN const uint8_t const USBD_HID_CfgDesc[] __ALIGN_END = {
|
||||
0x09, /* bLength: Configuration Descriptor size */
|
||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
||||
0x29,
|
||||
/* wTotalLength: Bytes returned */
|
||||
0x00, 0x01, /*bNumInterfaces: 1 interface*/
|
||||
0x01, /*bConfigurationValue: Configuration value*/
|
||||
USBD_IDX_PRODUCT_STR, /*iConfiguration: Index of string descriptor
|
||||
describing
|
||||
the configuration*/
|
||||
0xC0, /*bmAttributes: bus powered */
|
||||
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
|
||||
|
||||
/************** Descriptor of CUSTOM HID interface ****************/
|
||||
/* 09 */
|
||||
0x09, /*bLength: Interface Descriptor size*/
|
||||
USB_DESC_TYPE_INTERFACE, /*bDescriptorType: Interface descriptor type*/
|
||||
0x00, /*bInterfaceNumber: Number of Interface*/
|
||||
0x00, /*bAlternateSetting: Alternate setting*/
|
||||
0x02, /*bNumEndpoints*/
|
||||
0x03, /*bInterfaceClass: HID*/
|
||||
0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
||||
0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
||||
USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/
|
||||
/******************** Descriptor of HID *************************/
|
||||
/* 18 */
|
||||
0x09, /*bLength: HID Descriptor size*/
|
||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
||||
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
|
||||
0x01,
|
||||
0x00, /*bCountryCode: Hardware target country*/
|
||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
||||
0x22, /*bDescriptorType*/
|
||||
sizeof(
|
||||
HID_DynReportDesc), /*wItemLength: Total length of Report descriptor*/
|
||||
0x00,
|
||||
/******************** Descriptor of Custom HID endpoints
|
||||
********************/
|
||||
/* 27 */
|
||||
0x07, /*bLength: Endpoint Descriptor size*/
|
||||
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
||||
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
|
||||
0x03, /*bmAttributes: Interrupt endpoint*/
|
||||
HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
|
||||
0x00,
|
||||
0x01, /*bInterval: Polling Interval (20 ms)*/
|
||||
/* 34 */
|
||||
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||
HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/
|
||||
0x03, /* bmAttributes: Interrupt endpoint */
|
||||
HID_EPOUT_SIZE, /* wMaxPacketSize: 2 Bytes max */
|
||||
0x00, 0x01, /* bInterval: Polling Interval (20 ms) */
|
||||
/* 41 */
|
||||
};
|
||||
|
||||
/* USB HID device Configuration Descriptor */
|
||||
__ALIGN_BEGIN const uint8_t const USBD_HID_Desc[] __ALIGN_END = {
|
||||
/* 18 */
|
||||
0x09, /*bLength: HID Descriptor size*/
|
||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
||||
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
|
||||
0x01, 0x00, /*bCountryCode: Hardware target country*/
|
||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
||||
0x22, /*bDescriptorType*/
|
||||
sizeof(
|
||||
HID_DynReportDesc), /*wItemLength: Total length of Report descriptor*/
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* USB Standard Device Descriptor */
|
||||
__ALIGN_BEGIN const uint8_t const USBD_HID_DeviceQualifierDesc[] __ALIGN_END = {
|
||||
USB_LEN_DEV_QUALIFIER_DESC,
|
||||
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x01,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* USB Standard Device Descriptor */
|
||||
const uint8_t const USBD_DeviceDesc[USB_LEN_DEV_DESC] = {
|
||||
0x12, /* bLength */
|
||||
USB_DESC_TYPE_DEVICE, /* bDescriptorType */
|
||||
0x00, /* bcdUSB */
|
||||
0x02,
|
||||
0x00, /* bDeviceClass */
|
||||
0x00, /* bDeviceSubClass */
|
||||
0x00, /* bDeviceProtocol */
|
||||
USB_MAX_EP0_SIZE, /* bMaxPacketSize */
|
||||
LOBYTE(USBD_VID), /* idVendor */
|
||||
HIBYTE(USBD_VID), /* idVendor */
|
||||
LOBYTE(USBD_PID), /* idVendor */
|
||||
HIBYTE(USBD_PID), /* idVendor */
|
||||
0x00, /* bcdDevice rel. 2.00 */
|
||||
0x02,
|
||||
USBD_IDX_MFC_STR, /* Index of manufacturer string */
|
||||
USBD_IDX_PRODUCT_STR, /* Index of product string */
|
||||
USBD_IDX_SERIAL_STR, /* Index of serial number string */
|
||||
USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */
|
||||
}; /* USB_DeviceDescriptor */
|
||||
|
||||
/**
|
||||
* @brief Returns the device descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USBD_DeviceDesc);
|
||||
return (uint8_t *)USBD_DeviceDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the LangID string descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_LangIDStrDescriptor(USBD_SpeedTypeDef speed,
|
||||
uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USBD_LangIDDesc);
|
||||
return (uint8_t *)USBD_LangIDDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the product string descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed,
|
||||
uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USBD_PRODUCT_FS_STRING);
|
||||
return (uint8_t *)USBD_PRODUCT_FS_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the manufacturer string descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed,
|
||||
uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USBD_MANUFACTURER_STRING);
|
||||
return (uint8_t *)USBD_MANUFACTURER_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the serial number string descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_SerialStrDescriptor(USBD_SpeedTypeDef speed,
|
||||
uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USB_SERIAL_STRING);
|
||||
return (uint8_t *)USB_SERIAL_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the configuration string descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_ConfigStrDescriptor(USBD_SpeedTypeDef speed,
|
||||
uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USBD_CONFIGURATION_FS_STRING);
|
||||
return (uint8_t *)USBD_CONFIGURATION_FS_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the interface string descriptor.
|
||||
* @param speed: Current device speed
|
||||
* @param length: Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_InterfaceStrDescriptor(USBD_SpeedTypeDef speed,
|
||||
uint16_t *length) {
|
||||
UNUSED(speed);
|
||||
*length = sizeof(USBD_INTERFACE_FS_STRING);
|
||||
return (uint8_t *)USBD_INTERFACE_FS_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DeviceQualifierDescriptor
|
||||
* return Device Qualifier descriptor
|
||||
* @param length : pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_GetDeviceQualifierDesc_impl(uint16_t *length) {
|
||||
*length = sizeof(USBD_HID_DeviceQualifierDesc);
|
||||
return (uint8_t *)USBD_HID_DeviceQualifierDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD_CUSTOM_HID_GetCfgDesc
|
||||
* return configuration descriptor
|
||||
* @param speed : current device speed
|
||||
* @param length : pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t *USBD_HID_GetCfgDesc_impl(uint16_t *length) {
|
||||
*length = sizeof(USBD_HID_CfgDesc);
|
||||
return (uint8_t *)USBD_HID_CfgDesc;
|
||||
}
|
||||
|
||||
uint8_t *USBD_HID_GetHidDescriptor_impl(uint16_t *len) {
|
||||
*len = sizeof(USBD_HID_Desc);
|
||||
return (uint8_t *)USBD_HID_Desc;
|
||||
}
|
||||
|
||||
uint8_t *USBD_HID_GetReportDescriptor_impl(uint16_t *len) {
|
||||
*len = sizeof(HID_DynReportDesc);
|
||||
return (uint8_t *)HID_DynReportDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief USBD_HID_DataOut
|
||||
* handle data OUT Stage
|
||||
* @param pdev: device instance
|
||||
* @param epnum: endpoint index
|
||||
* @retval status
|
||||
*
|
||||
* This function is the default behavior for our implementation when data are
|
||||
* sent over the out hid endpoint
|
||||
*/
|
||||
extern volatile unsigned short G_io_apdu_length;
|
||||
|
||||
uint8_t USBD_HID_DataOut_impl(USBD_HandleTypeDef *pdev, uint8_t epnum,
|
||||
uint8_t *buffer) {
|
||||
UNUSED(epnum);
|
||||
|
||||
// prepare receiving the next chunk (masked time)
|
||||
USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR, HID_EPOUT_SIZE);
|
||||
|
||||
if (fidoActivated) {
|
||||
#ifdef HAVE_U2F
|
||||
u2f_transport_handle(&u2fService, buffer,
|
||||
io_seproxyhal_get_ep_rx_size(HID_EPOUT_ADDR),
|
||||
U2F_MEDIA_USB);
|
||||
#endif
|
||||
} else {
|
||||
// avoid troubles when an apdu has not been replied yet
|
||||
if (G_io_apdu_media == IO_APDU_MEDIA_NONE) {
|
||||
// add to the hid transport
|
||||
switch (io_usb_hid_receive(
|
||||
io_usb_send_apdu_data, buffer,
|
||||
io_seproxyhal_get_ep_rx_size(HID_EPOUT_ADDR))) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case IO_USB_APDU_RECEIVED:
|
||||
G_io_apdu_media = IO_APDU_MEDIA_USB_HID; // for application code
|
||||
G_io_apdu_state = APDU_USB_HID; // for next call to io_exchange
|
||||
G_io_apdu_length = G_io_usb_hid_total_length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/** @defgroup USBD_HID_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
// note: how core lib usb calls the hid class
|
||||
static const USBD_DescriptorsTypeDef const HID_Desc = {
|
||||
USBD_HID_DeviceDescriptor, USBD_HID_LangIDStrDescriptor,
|
||||
USBD_HID_ManufacturerStrDescriptor, USBD_HID_ProductStrDescriptor,
|
||||
USBD_HID_SerialStrDescriptor, USBD_HID_ConfigStrDescriptor,
|
||||
USBD_HID_InterfaceStrDescriptor, NULL,
|
||||
};
|
||||
|
||||
static const USBD_ClassTypeDef const USBD_HID = {
|
||||
USBD_HID_Init, USBD_HID_DeInit, USBD_HID_Setup, NULL, /*EP0_TxSent*/
|
||||
NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */
|
||||
NULL, /*DataIn*/
|
||||
USBD_HID_DataOut_impl, /*DataOut*/
|
||||
NULL, /*SOF */
|
||||
NULL, NULL, USBD_HID_GetCfgDesc_impl, USBD_HID_GetCfgDesc_impl,
|
||||
USBD_HID_GetCfgDesc_impl, USBD_HID_GetDeviceQualifierDesc_impl,
|
||||
};
|
||||
|
||||
void USB_power_U2F(unsigned char enabled, unsigned char fido) {
|
||||
uint16_t page = (fido ? PAGE_FIDO : PAGE_GENERIC);
|
||||
os_memmove(HID_DynReportDesc, HID_ReportDesc, sizeof(HID_ReportDesc));
|
||||
HID_DynReportDesc[1] = (page & 0xff);
|
||||
HID_DynReportDesc[2] = ((page >> 8) & 0xff);
|
||||
fidoActivated = (fido ? true : false);
|
||||
|
||||
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
|
||||
|
||||
if (enabled) {
|
||||
os_memset(&USBD_Device, 0, sizeof(USBD_Device));
|
||||
/* Init Device Library */
|
||||
USBD_Init(&USBD_Device, (USBD_DescriptorsTypeDef *)&HID_Desc, 0);
|
||||
|
||||
/* Register the HID class */
|
||||
USBD_RegisterClass(&USBD_Device, (USBD_ClassTypeDef *)&USBD_HID);
|
||||
|
||||
/* Start Device Process */
|
||||
USBD_Start(&USBD_Device);
|
||||
} else {
|
||||
USBD_DeInit(&USBD_Device);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef USBD_HID_IMPL_H
|
||||
#define USBD_HID_IMPL_H
|
||||
|
||||
#define HID_EPIN_ADDR 0x82
|
||||
#define HID_EPIN_SIZE 0x40
|
||||
|
||||
#define HID_EPOUT_ADDR 0x02
|
||||
#define HID_EPOUT_SIZE 0x40
|
||||
|
||||
#endif // USBD_HID_IMPL_H
|
||||
|
||||