Display fee as startgas * gaslimit, allow conditional signing of raw data, add U2F tunnel

This commit is contained in:
BTChip 2016-10-17 23:40:31 +02:00
parent 533c14adc2
commit 3617bb2eee
14 changed files with 2524 additions and 287 deletions

3
.gitignore vendored
View File

@ -2,6 +2,7 @@ bin
debug
dep
obj
src/u2f_crypto_data.h
src/glyph.c

View File

@ -45,8 +45,14 @@ PROG := token-genericwallet
CONFIG_PRODUCTIONS := bin/$(PROG)
GLYPH_FILES := $(addprefix glyphs/,$(sort $(notdir $(shell find glyphs/))))
GLYPH_DEST := src_common/glyphs.c
$(GLYPH_DEST): $(GLYPH_FILES) $(BOLOS_SDK)/icon.py
-rm $@
if [ ! -z "$(GLYPH_FILES)" ] ; then for gif in $(GLYPH_FILES) ; do python $(BOLOS_SDK)/icon.py $$gif | grep -v "bitmap}," ; done > $(GLYPH_DEST) ; fi
SOURCE_PATH := src_genericwallet $(BOLOS_SDK)/src $(dir $(shell find $(BOLOS_SDK)/lib_stusb* | grep "\.c$$")) src_common
SOURCE_FILES := $(foreach path, $(SOURCE_PATH),$(shell find $(path) | grep "\.c$$") )
SOURCE_FILES := $(foreach path, $(SOURCE_PATH),$(shell find $(path) | grep "\.c$$") ) $(GLYPH_DEST)
INCLUDES_PATH := $(dir $(shell find $(BOLOS_SDK)/lib_stusb* | grep "\.h$$")) include src_genericwallet $(BOLOS_SDK)/include $(BOLOS_SDK)/include/arm src_common
### platform definitions
@ -55,6 +61,16 @@ DEFINES := ST31 gcc __IO=volatile
DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=128
DEFINES += HAVE_BAGL HAVE_PRINTF
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
DEFINES += LEDGER_MAJOR_VERSION=1 LEDGER_MINOR_VERSION=0 LEDGER_PATCH_VERSION=2
# U2F
DEFINES += HAVE_U2F
DEFINES += USB_SEGMENT_SIZE=64
DEFINES += BLE_SEGMENT_SIZE=32 #max MTU, min 20
DEFINES += U2F_MAX_MESSAGE_SIZE=264 #257+5+2
DEFINES += UNUSED\(x\)=\(void\)x
DEFINES += PRINTF\(...\)=
DEFINES += TARGET_ID=$(TARGET_ID)
##############
# Compiler #
@ -113,9 +129,9 @@ ifeq ($(filter clean,$(MAKECMDGOALS)),)
endif
clean:
rm -fr obj bin debug dep
rm -fr obj bin debug dep $(GLYPH_DEST)
prepare:
prepare: $(GLYPH_DEST)
@mkdir -p bin obj debug dep
.SECONDEXPANSION:
@ -126,10 +142,10 @@ log = $(if $(strip $(VERBOSE)),$1,@$1)
default: prepare bin/$(PROG)
load:
python -m ledgerblue.loadApp --targetId $(TARGET_ID) --fileName bin/$(PROG).hex --appName $(APPNAME) --icon `python $(BOLOS_SDK)/icon.py 16 16 icon.gif hexbitmaponly` $(APP_LOAD_PARAMS)
python -m ledgerblue.loadApp --targetId $(TARGET_ID) --fileName bin/$(PROG).hex --appName $(APPNAME) --icon `python $(BOLOS_SDK)/icon.py 16 16 icon.gif hexbitmaponly` --apdu $(APP_LOAD_PARAMS)
load_release:
python -m ledgerblue.loadApp --targetId $(TARGET_ID) --fileName bin/$(PROG).hex --appName $(APPNAME) --icon `python $(BOLOS_SDK)/icon.py 16 16 icon.gif hexbitmaponly` $(APP_LOAD_PARAMS) --signature 3044022065e5bcf6519ea12ff991e429cc85bf7ecc789bd1a7a141d5e2dc358e5544c6170220726801803361b3296b83a3d14be8afc3374bda215b4dadd3d67bc3518e1f78bc
python -m ledgerblue.loadApp --targetId $(TARGET_ID) --fileName bin/$(PROG).hex --appName $(APPNAME) --icon `python $(BOLOS_SDK)/icon.py 16 16 icon.gif hexbitmaponly` $(APP_LOAD_PARAMS) --signature 304402205385091595d285e0b06b8f968457d70415140497a0edea385a63b9f526ebd2630220524c832f5f0d5e7ecce56db5839a70e52dc1b79bdda37c3aa08282f28b410082
delete:
python -m ledgerblue.deleteApp --targetId $(TARGET_ID) --appName $(APPNAME)

BIN
glyphs/icon_back.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
#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

View File

@ -0,0 +1,35 @@
/*
*******************************************************************************
* 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

View File

@ -0,0 +1,281 @@
#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

View File

@ -0,0 +1,29 @@
/*
*******************************************************************************
* 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

View File

@ -0,0 +1,146 @@
#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

View File

@ -0,0 +1,112 @@
/*
*******************************************************************************
* 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

View File

@ -0,0 +1,33 @@
/*
*******************************************************************************
* 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

View File

@ -0,0 +1,227 @@
#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

View File

@ -0,0 +1,78 @@
/*
*******************************************************************************
* 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

View File

@ -0,0 +1,531 @@
/**
******************************************************************************
* @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>&copy; 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
#ifdef HAVE_VID_PID_PROBER
#define USBD_VID 0x2581
#define USBD_PID 0xf1d1
#define USBD_LANGID_STRING 0x409
#else
#define USBD_VID 0x2C97
#if TARGET_ID == 0x31000002 // 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 TARGET_ID == 0x31100002 // 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 TARGET_ID == 0x31200002 // 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
#define USBD_LANGID_STRING 0x409
#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[] = {
0x2, USB_DESC_TYPE_STRING,
};
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 {
// 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_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
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,
};
// the USB device
USBD_HandleTypeDef USBD_Device;
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****/