mirror of
https://github.com/polhenarejos/pico-keys-sdk
synced 2026-05-31 18:41:22 +02:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
657913d29a | ||
|
|
18fa1d7f37 | ||
|
|
f123108c3e | ||
|
|
f8590ba8c7 | ||
|
|
4d7101b802 | ||
|
|
7fded7234b | ||
|
|
988d4e23c2 | ||
|
|
c23f17107a | ||
|
|
91e2b7f643 | ||
|
|
3092da23ed | ||
|
|
e29521fcf6 | ||
|
|
d2e54b04db | ||
|
|
4ab68cc822 | ||
|
|
e1914556ec | ||
|
|
287be74921 | ||
|
|
5a4aff7008 | ||
|
|
8b97791d8f | ||
|
|
847005d94f | ||
|
|
68f43f3cb2 | ||
|
|
4c49e59edc | ||
|
|
633593aae3 | ||
|
|
42f3c67c61 | ||
|
|
493a88538a | ||
|
|
607f7c50d4 | ||
|
|
2cb59d57d2 | ||
|
|
a8e1fe5842 | ||
|
|
d1530733a2 | ||
|
|
4538d6ef14 | ||
|
|
4a1bddb3d5 | ||
|
|
c6a129b6ad | ||
|
|
abd52c34ba | ||
|
|
7aeac46eef | ||
|
|
867d4637ee | ||
|
|
7491021102 | ||
|
|
9b137f6f08 | ||
|
|
3f492b9272 | ||
|
|
799733203b | ||
|
|
0be497e713 | ||
|
|
e23dead31d | ||
|
|
4d9faccedb | ||
|
|
f47df94dfb | ||
|
|
c0123aa669 | ||
|
|
43dfb0cde5 | ||
|
|
f14e029094 | ||
|
|
f14cc8dba5 | ||
|
|
16a1981dc3 | ||
|
|
9ccd10fcea | ||
|
|
a6506e6c95 | ||
|
|
3e73d6569b | ||
|
|
214ec2b9ae |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "mbedtls"]
|
||||
path = mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls
|
||||
[submodule "tinycbor"]
|
||||
path = tinycbor
|
||||
url = https://github.com/intel/tinycbor.git
|
||||
|
||||
@@ -1004,7 +1004,7 @@
|
||||
*
|
||||
* Enable functions that use the filesystem.
|
||||
*/
|
||||
#define MBEDTLS_FS_IO
|
||||
//#define MBEDTLS_FS_IO
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
|
||||
@@ -2112,7 +2112,7 @@
|
||||
*
|
||||
* Module: library/chacha20.c
|
||||
*/
|
||||
//#define MBEDTLS_CHACHA20_C
|
||||
#define MBEDTLS_CHACHA20_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_CHACHAPOLY_C
|
||||
@@ -2123,7 +2123,7 @@
|
||||
*
|
||||
* This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C
|
||||
*/
|
||||
//#define MBEDTLS_CHACHAPOLY_C
|
||||
#define MBEDTLS_CHACHAPOLY_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_CIPHER_C
|
||||
@@ -2657,7 +2657,7 @@
|
||||
* either MBEDTLS_PSA_ITS_FILE_C or a native implementation of
|
||||
* the PSA ITS interface
|
||||
*/
|
||||
#define MBEDTLS_PSA_CRYPTO_STORAGE_C
|
||||
//#define MBEDTLS_PSA_CRYPTO_STORAGE_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_PSA_ITS_FILE_C
|
||||
@@ -2669,7 +2669,7 @@
|
||||
*
|
||||
* Requires: MBEDTLS_FS_IO
|
||||
*/
|
||||
#define MBEDTLS_PSA_ITS_FILE_C
|
||||
//#define MBEDTLS_PSA_ITS_FILE_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_RIPEMD160_C
|
||||
|
||||
@@ -91,9 +91,22 @@ if (NOT TARGET pico_hsm_sdk)
|
||||
target_sources(pico_hsm_sdk INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/usb_descriptors.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborencoder.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser_dup_string.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
|
||||
)
|
||||
target_include_directories(pico_hsm_sdk INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
35
src/apdu.c
35
src/apdu.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -125,6 +125,39 @@ uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) {
|
||||
return make_uint16_t(sw1, sw2);
|
||||
}
|
||||
|
||||
void apdu_thread() {
|
||||
|
||||
card_init_core1();
|
||||
while (1) {
|
||||
uint32_t m;
|
||||
queue_remove_blocking(&usb_to_card_q, &m);
|
||||
|
||||
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE)
|
||||
{
|
||||
set_res_sw (0x6f, 0x00);
|
||||
goto done;
|
||||
}
|
||||
else if (m == EV_EXIT) {
|
||||
if (current_app && current_app->unload) {
|
||||
current_app->unload();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
process_apdu();
|
||||
|
||||
done:;
|
||||
|
||||
apdu_finish();
|
||||
finished_data_size = apdu_next();
|
||||
uint32_t flag = EV_EXEC_FINISHED;
|
||||
queue_add_blocking(&card_to_usb_q, &flag);
|
||||
}
|
||||
//printf("EXIT !!!!!!\r\n");
|
||||
if (current_app && current_app->unload)
|
||||
current_app->unload();
|
||||
}
|
||||
|
||||
void apdu_finish() {
|
||||
apdu.rdata[apdu.rlen] = apdu.sw >> 8;
|
||||
apdu.rdata[apdu.rlen+1] = apdu.sw & 0xff;
|
||||
|
||||
15
src/apdu.h
15
src/apdu.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct app {
|
||||
const uint8_t *aid;
|
||||
@@ -47,8 +48,19 @@ extern int register_app(app_t * (*)());
|
||||
printf("\r\n");\
|
||||
} printf("\r\n"); \
|
||||
}
|
||||
#define DEBUG_DATA(_p, _s) \
|
||||
{ \
|
||||
printf("Data %s (%d bytes):\r\n", #_p, _s); \
|
||||
for (int _i = 0; _i < _s; _i++) \
|
||||
{ \
|
||||
printf("%02X", (_p)[_i]); \
|
||||
} \
|
||||
printf("\n"); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define DEBUG_PAYLOAD(_p,_s)
|
||||
#define DEBUG_DATA(_p,_s)
|
||||
#endif
|
||||
|
||||
extern uint8_t num_apps;
|
||||
@@ -80,5 +92,6 @@ extern int process_apdu();
|
||||
extern size_t apdu_process(const uint8_t *buffer, size_t buffer_size);
|
||||
extern void apdu_finish();
|
||||
extern size_t apdu_next();
|
||||
extern void apdu_thread();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -235,10 +235,10 @@ void scan_region(bool persistent) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wait_flash_finish();
|
||||
void scan_flash() {
|
||||
initialize_flash(false); //soft initialization
|
||||
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
|
||||
if (*(uintptr_t *)flash_read(end_rom_pool) == 0xffffffff && *(uintptr_t *)flash_read(end_rom_pool+sizeof(uintptr_t)) == 0xffffffff)
|
||||
{
|
||||
printf("First initialization (or corrupted!)\r\n");
|
||||
uint8_t empty[sizeof(uintptr_t)*2+sizeof(uint32_t)];
|
||||
@@ -427,3 +427,6 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
bool file_has_data(file_t *f) {
|
||||
return (f != NULL && f->data != NULL && file_get_size(f) > 0);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ typedef struct file
|
||||
const uint8_t acl[7];
|
||||
} __attribute__((packed)) file_t;
|
||||
|
||||
extern bool file_has_data(file_t *);
|
||||
|
||||
extern file_t *currentEF;
|
||||
extern file_t *currentDF;
|
||||
extern const file_t *selected_applet;
|
||||
|
||||
@@ -61,6 +61,9 @@ enum {
|
||||
};
|
||||
extern void led_set_blink(uint32_t mode);
|
||||
|
||||
extern bool is_req_button_pending();
|
||||
extern uint32_t button_timeout;
|
||||
|
||||
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
|
||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
|
||||
#define SW_WARNING_CORRUPTED() set_res_sw (0x62, 0x81)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define HSM_SDK_VERSION 0x0300
|
||||
#define HSM_SDK_VERSION 0x0304
|
||||
|
||||
#define HSM_SDK_VERSION_MAJOR ((HSM_SDK_VERSION >> 8) & 0xff)
|
||||
#define HSM_SDK_VERSION_MINOR (HSM_SDK_VERSION & 0xff)
|
||||
|
||||
21
src/main.c
21
src/main.c
@@ -67,21 +67,31 @@ void led_set_blink(uint32_t mode) {
|
||||
|
||||
void execute_tasks();
|
||||
|
||||
static bool req_button_pending = false;
|
||||
|
||||
bool is_req_button_pending() {
|
||||
return req_button_pending;
|
||||
}
|
||||
|
||||
uint32_t button_timeout = 15000;
|
||||
bool cancel_button = false;
|
||||
|
||||
bool wait_button() {
|
||||
uint32_t start_button = board_millis();
|
||||
bool timeout = false;
|
||||
cancel_button = false;
|
||||
led_set_blink((1000 << 16) | 100);
|
||||
|
||||
while (board_button_read() == false) {
|
||||
req_button_pending = true;
|
||||
while (board_button_read() == false && cancel_button == false) {
|
||||
execute_tasks();
|
||||
//sleep_ms(10);
|
||||
if (start_button + 15000 < board_millis()) { /* timeout */
|
||||
if (start_button + button_timeout < board_millis()) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!timeout) {
|
||||
while (board_button_read() == true) {
|
||||
while (board_button_read() == true && cancel_button == false) {
|
||||
execute_tasks();
|
||||
//sleep_ms(10);
|
||||
if (start_button + 15000 < board_millis()) { /* timeout */
|
||||
@@ -91,7 +101,8 @@ bool wait_button() {
|
||||
}
|
||||
}
|
||||
led_set_blink(BLINK_PROCESSING);
|
||||
return timeout;
|
||||
req_button_pending = false;
|
||||
return timeout || cancel_button;
|
||||
}
|
||||
|
||||
struct apdu apdu;
|
||||
|
||||
@@ -176,6 +176,17 @@ void neug_wait_full(void) { //should be called only on core1
|
||||
}
|
||||
}
|
||||
|
||||
void neug_wait_full_ext(bool blocking) {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
while (!rb->full) {
|
||||
if (blocking == true)
|
||||
sleep_ms(1);
|
||||
else
|
||||
neug_task();
|
||||
}
|
||||
}
|
||||
|
||||
void neug_fini(void) {
|
||||
neug_get();
|
||||
}
|
||||
|
||||
@@ -20,10 +20,14 @@
|
||||
|
||||
#define NEUG_PRE_LOOP 32
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
void neug_init(uint32_t *buf, uint8_t size);
|
||||
uint32_t neug_get();
|
||||
void neug_flush(void);
|
||||
void neug_wait_full(void);
|
||||
void neug_wait_full_ext(bool);
|
||||
void neug_fini(void);
|
||||
|
||||
#endif
|
||||
@@ -79,13 +79,13 @@ void random_get_salt(uint8_t *p) {
|
||||
/*
|
||||
* Random byte iterator
|
||||
*/
|
||||
int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||
int random_gen_ext(void *arg, unsigned char *out, size_t out_len, bool blocking) {
|
||||
uint8_t *index_p = (uint8_t *)arg;
|
||||
uint8_t index = index_p ? *index_p : 0;
|
||||
size_t n;
|
||||
|
||||
while (out_len) {
|
||||
neug_wait_full();
|
||||
neug_wait_full_ext(blocking);
|
||||
|
||||
n = RANDOM_BYTES_LENGTH - index;
|
||||
if (n > out_len)
|
||||
@@ -107,3 +107,11 @@ int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||
return random_gen_ext(arg, out, out_len, true);
|
||||
}
|
||||
|
||||
int random_gen_core0(void *arg, unsigned char *out, size_t out_len) {
|
||||
return random_gen_ext(arg, out, out_len, false);
|
||||
}
|
||||
|
||||
@@ -34,5 +34,6 @@ void random_get_salt (uint8_t *p);
|
||||
|
||||
/* iterator returning a byta at a time */
|
||||
extern int random_gen (void *arg, unsigned char *output, size_t output_len);
|
||||
extern int random_gen_core0(void *arg, unsigned char *out, size_t out_len);
|
||||
|
||||
#endif
|
||||
@@ -124,6 +124,8 @@ int driver_init() {
|
||||
ccid_response = (struct ccid_header *)usb_get_tx();
|
||||
apdu.rdata = &ccid_response->apdu;
|
||||
|
||||
usb_set_timeout_counter(1500);
|
||||
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
@@ -174,7 +176,7 @@ int driver_process_usb_packet(uint16_t rx_read) {
|
||||
ccid_response->abRFU1 = 0;
|
||||
//printf("1 %x %x %x || %x %x %x\r\n",ccid_response->apdu,apdu.rdata,ccid_response,ccid_header,ccid_header->apdu,apdu.data);
|
||||
memcpy(apdu.rdata, ccid_atr+1, size_atr);
|
||||
card_start();
|
||||
card_start(apdu_thread);
|
||||
ccid_status = 0;
|
||||
ccid_write(size_atr);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"Pol Henarejos", // 1: Manufacturer
|
||||
"Pico HSM", // 2: Product
|
||||
"Pico HSM CCID", // 2: Product
|
||||
"11223344", // 3: Serials, should use chip ID
|
||||
"Pico HSM Config", // 4: Vendor Interface
|
||||
"Pico HSM Interface"
|
||||
|
||||
159
src/usb/hid/ctap_hid.h
Normal file
159
src/usb/hid/ctap_hid.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CTAP_HID_H_
|
||||
#define _CTAP_HID_H_
|
||||
|
||||
#ifdef _MSC_VER // Windows
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long int uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Size of HID reports
|
||||
|
||||
#define HID_RPT_SIZE 64 // Default size of raw HID report
|
||||
|
||||
// Frame layout - command- and continuation frames
|
||||
|
||||
#define CID_BROADCAST 0xffffffff // Broadcast channel id
|
||||
|
||||
#define TYPE_MASK 0x80 // Frame type mask
|
||||
#define TYPE_INIT 0x80 // Initial frame identifier
|
||||
#define TYPE_CONT 0x00 // Continuation frame identifier
|
||||
|
||||
typedef struct {
|
||||
uint32_t cid; // Channel identifier
|
||||
union {
|
||||
uint8_t type; // Frame type - b7 defines type
|
||||
struct {
|
||||
uint8_t cmd; // Command - b7 set
|
||||
uint8_t bcnth; // Message byte count - high part
|
||||
uint8_t bcntl; // Message byte count - low part
|
||||
uint8_t data[HID_RPT_SIZE - 7]; // Data payload
|
||||
} init;
|
||||
struct {
|
||||
uint8_t seq; // Sequence number - b7 cleared
|
||||
uint8_t data[HID_RPT_SIZE - 5]; // Data payload
|
||||
} cont;
|
||||
};
|
||||
}__packed CTAPHID_FRAME;
|
||||
|
||||
#define FRAME_TYPE(f) ((f)->type & TYPE_MASK)
|
||||
#define FRAME_CMD(f) ((f)->init.cmd & ~TYPE_MASK)
|
||||
#define MSG_LEN(f) ((f)->init.bcnth*256 + (f)->init.bcntl)
|
||||
#define FRAME_SEQ(f) ((f)->cont.seq & ~TYPE_MASK)
|
||||
|
||||
// HID usage- and usage-page definitions
|
||||
|
||||
#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
|
||||
#define FIDO_USAGE_CTAPHID 0x01 // CTAPHID usage for top-level collection
|
||||
#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
|
||||
#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
|
||||
|
||||
// General constants
|
||||
|
||||
#define CTAPHID_IF_VERSION 2 // Current interface implementation version
|
||||
#define CTAPHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
|
||||
|
||||
// CTAPHID native commands
|
||||
|
||||
#define CTAPHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
|
||||
#define CTAPHID_MSG (TYPE_INIT | 0x03) // Send CTAP message frame
|
||||
#define CTAPHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
|
||||
#define CTAPHID_INIT (TYPE_INIT | 0x06) // Channel initialization
|
||||
#define CTAPHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
|
||||
#define CTAPHID_CBOR (TYPE_INIT | 0x10) // CBOR
|
||||
#define CTAPHID_CANCEL (TYPE_INIT | 0x11) // Cancel any request
|
||||
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3B) // Keepalive command
|
||||
#define CTAPHID_SYNC (TYPE_INIT | 0x3C) // Protocol resync command
|
||||
#define CTAPHID_ERROR (TYPE_INIT | 0x3F) // Error response
|
||||
|
||||
#define CTAPHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
|
||||
#define CTAPHID_VENDOR_LAST (TYPE_INIT | 0x7F) // Last vendor defined command
|
||||
|
||||
// CTAP CBOR commands
|
||||
|
||||
#define CTAP_MAKE_CREDENTIAL 0x01
|
||||
#define CTAP_GET_ASSERTION 0x02
|
||||
#define CTAP_GET_INFO 0x04
|
||||
#define CTAP_CLIENT_PIN 0x06
|
||||
#define CTAP_RESET 0x07
|
||||
#define CTAP_GET_NEXT_ASSERTION 0x08
|
||||
|
||||
// CTAP_KEEPALIVE command defines
|
||||
|
||||
#define KEEPALIVE_STATUS_PROCESSING 0x1
|
||||
#define KEEPALIVE_STATUS_UPNEEDED 0x2
|
||||
|
||||
// CTAPHID_INIT command defines
|
||||
|
||||
#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
|
||||
#define CAPFLAG_WINK 0x01 // Device supports WINK command
|
||||
#define CAPFLAG_CBOR 0x04 // Device supports CBOR command
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
|
||||
}__packed CTAPHID_INIT_REQ;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
|
||||
uint32_t cid; // Channel identifier
|
||||
uint8_t versionInterface; // Interface version
|
||||
uint8_t versionMajor; // Major version number
|
||||
uint8_t versionMinor; // Minor version number
|
||||
uint8_t versionBuild; // Build version number
|
||||
uint8_t capFlags; // Capabilities flags
|
||||
}__packed CTAPHID_INIT_RESP;
|
||||
|
||||
// CTAPHID_SYNC command defines
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce; // Client application nonce
|
||||
} CTAPHID_SYNC_REQ;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce; // Client application nonce
|
||||
} CTAPHID_SYNC_RESP;
|
||||
|
||||
// Low-level error codes. Return as negatives.
|
||||
|
||||
#define CTAP_MAX_PACKET_SIZE (64 - 7 + 128 * (64 - 5))
|
||||
|
||||
#define CTAP1_ERR_NONE 0x00 // No error
|
||||
#define CTAP1_ERR_INVALID_CMD 0x01 // Invalid command
|
||||
#define CTAP1_ERR_INVALID_PARAMETER 0x02 // Invalid parameter
|
||||
#define CTAP1_ERR_INVALID_LEN 0x03 // Invalid message length
|
||||
#define CTAP1_ERR_INVALID_SEQ 0x04 // Invalid message sequencing
|
||||
#define CTAP1_ERR_MSG_TIMEOUT 0x05 // Message has timed out
|
||||
#define CTAP1_ERR_CHANNEL_BUSY 0x06 // Channel busy
|
||||
#define CTAP1_ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
|
||||
#define CTAP1_ERR_INVALID_CHANNEL 0x0b // CID not valid
|
||||
#define CTAP1_ERR_OTHER 0x7f // Other unspecified error
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CTAP_HID_H_
|
||||
@@ -16,13 +16,24 @@
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
#include "u2f_hid.h"
|
||||
#include "ctap_hid.h"
|
||||
#include "hsm.h"
|
||||
#include "hsm_version.h"
|
||||
#include "apdu.h"
|
||||
#include "usb.h"
|
||||
#include "bsp/board.h"
|
||||
|
||||
static bool mounted = false;
|
||||
extern int cbor_process(const uint8_t *, size_t);
|
||||
extern void init_fido(bool);
|
||||
|
||||
typedef struct msg_packet {
|
||||
uint16_t len;
|
||||
uint16_t current_len;
|
||||
uint8_t data[CTAP_MAX_PACKET_SIZE];
|
||||
} __packed msg_packet_t;
|
||||
|
||||
msg_packet_t msg_packet = { 0 };
|
||||
|
||||
void tud_mount_cb()
|
||||
{
|
||||
@@ -33,15 +44,17 @@ bool driver_mounted() {
|
||||
return mounted;
|
||||
}
|
||||
|
||||
U2FHID_FRAME *u2f_req, *u2f_resp;
|
||||
CTAPHID_FRAME *ctap_req = NULL, *ctap_resp = NULL;
|
||||
|
||||
int driver_init() {
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
u2f_req = (U2FHID_FRAME *)usb_get_rx();
|
||||
apdu.header = u2f_req->init.data;
|
||||
ctap_req = (CTAPHID_FRAME *)usb_get_rx();
|
||||
apdu.header = ctap_req->init.data;
|
||||
|
||||
u2f_resp = (U2FHID_FRAME *)usb_get_tx();
|
||||
apdu.rdata = u2f_resp->init.data;
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
apdu.rdata = ctap_resp->init.data;
|
||||
|
||||
usb_set_timeout_counter(200);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -69,8 +82,32 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hid_write_offset(uint16_t size, uint16_t offset) {
|
||||
if (*usb_get_tx() != 0x81)
|
||||
DEBUG_PAYLOAD(usb_get_tx()+offset, size);
|
||||
usb_write_offset(size, offset);
|
||||
}
|
||||
|
||||
void hid_write(uint16_t size) {
|
||||
hid_write_offset(size, 0);
|
||||
}
|
||||
|
||||
uint16_t send_buffer_size = 0;
|
||||
|
||||
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len) {
|
||||
uint8_t seq = report[4] & TYPE_MASK ? 0 : report[4]+1;
|
||||
if (send_buffer_size > 0) {
|
||||
ctap_resp->cid = ctap_req->cid;
|
||||
ctap_resp->cont.seq = seq;
|
||||
hid_write_offset(64, (uint8_t *)ctap_resp - (usb_get_tx()));
|
||||
send_buffer_size -= MIN(64 - 5, send_buffer_size);
|
||||
ctap_resp = (CTAPHID_FRAME *)((uint8_t *)ctap_resp + 64 - 5);
|
||||
}
|
||||
}
|
||||
|
||||
int driver_write(const uint8_t *buffer, size_t buffer_size) {
|
||||
return tud_hid_report(0, buffer, buffer_size);
|
||||
int ret = tud_hid_report(0, buffer, buffer_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t driver_read(uint8_t *buffer, size_t buffer_size) {
|
||||
@@ -85,57 +122,239 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
|
||||
(void) itf;
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
printf("set report\n");
|
||||
usb_rx(buffer, bufsize);
|
||||
}
|
||||
|
||||
void hid_write_offset(uint16_t size, uint16_t offset) {
|
||||
if (*usb_get_tx() != 0x81)
|
||||
DEBUG_PAYLOAD(usb_get_tx()+offset,size+10);
|
||||
usb_write_offset(size, offset);
|
||||
}
|
||||
|
||||
void hid_write(uint16_t size) {
|
||||
hid_write_offset(size, 0);
|
||||
}
|
||||
|
||||
int driver_process_usb_packet(uint16_t read) {
|
||||
if (read >= 10)
|
||||
{
|
||||
if (FRAME_TYPE(u2f_req) == TYPE_INIT) {
|
||||
printf("command %x\n", FRAME_CMD(u2f_req));
|
||||
printf("len %d\n", MSG_LEN(u2f_req));
|
||||
DEBUG_PAYLOAD(u2f_req->init.data, MSG_LEN(u2f_req));
|
||||
}
|
||||
if (u2f_req->init.cmd == U2FHID_INIT) {
|
||||
U2FHID_INIT_REQ *req = (U2FHID_INIT_REQ *)u2f_req->init.data;
|
||||
U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)u2f_resp->init.data;
|
||||
memcpy(resp->nonce, req->nonce, sizeof(resp->nonce));
|
||||
resp->cid = 0x01000000;
|
||||
resp->versionInterface = U2FHID_IF_VERSION;
|
||||
resp->versionMajor = HSM_SDK_VERSION_MAJOR;
|
||||
resp->versionMinor = HSM_SDK_VERSION_MINOR;
|
||||
resp->capFlags = CAPFLAG_WINK;
|
||||
|
||||
u2f_resp->cid = CID_BROADCAST;
|
||||
u2f_resp->init.cmd = U2FHID_INIT;
|
||||
u2f_resp->init.bcntl = 17;
|
||||
u2f_resp->init.bcnth = 0;
|
||||
uint32_t last_cmd_time = 0, last_packet_time = 0;
|
||||
int ctap_error(uint8_t error) {
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
|
||||
ctap_resp->cid = ctap_req->cid;
|
||||
ctap_resp->init.cmd = CTAPHID_ERROR;
|
||||
ctap_resp->init.bcntl = 1;
|
||||
ctap_resp->init.data[0] = error;
|
||||
hid_write(64);
|
||||
DEBUG_PAYLOAD((uint8_t *)u2f_resp, u2f_resp->init.bcntl+7);
|
||||
}
|
||||
// echo back anything we received from host
|
||||
//tud_hid_report(0, buffer, bufsize);
|
||||
printf("END\n");
|
||||
usb_clear_rx();
|
||||
last_packet_time = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t last_cmd = 0;
|
||||
uint8_t last_seq = 0;
|
||||
CTAPHID_FRAME last_req = { 0 };
|
||||
uint32_t lock = 0;
|
||||
|
||||
uint8_t thread_type = 0; //1 is APDU, 2 is CBOR
|
||||
extern void cbor_thread();
|
||||
extern bool cancel_button;
|
||||
|
||||
int driver_process_usb_nopacket() {
|
||||
if (last_packet_time > 0 && last_packet_time+500 < board_millis()) {
|
||||
ctap_error(CTAP1_ERR_MSG_TIMEOUT);
|
||||
last_packet_time = 0;
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void driver_exec_timeout() {
|
||||
int driver_process_usb_packet(uint16_t read) {
|
||||
int apdu_sent = 0;
|
||||
if (read >= 5)
|
||||
{
|
||||
last_packet_time = board_millis();
|
||||
DEBUG_PAYLOAD(usb_get_rx(),64);
|
||||
memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
|
||||
if (ctap_req->cid == 0x0 || (ctap_req->cid == CID_BROADCAST && ctap_req->init.cmd != CTAPHID_INIT))
|
||||
return ctap_error(CTAP1_ERR_INVALID_CHANNEL);
|
||||
if (board_millis() < lock && ctap_req->cid != last_req.cid && last_cmd_time+100 > board_millis())
|
||||
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
|
||||
if (FRAME_TYPE(ctap_req) == TYPE_INIT)
|
||||
{
|
||||
if (MSG_LEN(ctap_req) > CTAP_MAX_PACKET_SIZE)
|
||||
return ctap_error(CTAP1_ERR_INVALID_LEN);
|
||||
if (msg_packet.len > 0 && last_cmd_time+100 > board_millis() && ctap_req->init.cmd != CTAPHID_INIT) {
|
||||
if (last_req.cid != ctap_req->cid) //We are in a transaction
|
||||
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
|
||||
else
|
||||
return ctap_error(CTAP1_ERR_INVALID_SEQ);
|
||||
}
|
||||
printf("command %x\n", FRAME_CMD(ctap_req));
|
||||
printf("len %d\n", MSG_LEN(ctap_req));
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
if (MSG_LEN(ctap_req) > 64 - 7)
|
||||
{
|
||||
msg_packet.len = MSG_LEN(ctap_req);
|
||||
memcpy(msg_packet.data + msg_packet.current_len, ctap_req->init.data, 64-7);
|
||||
msg_packet.current_len += 64 - 7;
|
||||
}
|
||||
memcpy(&last_req, ctap_req, sizeof(CTAPHID_FRAME));
|
||||
last_cmd = ctap_req->init.cmd;
|
||||
last_seq = 0;
|
||||
last_cmd_time = board_millis();
|
||||
}
|
||||
else {
|
||||
if (msg_packet.len == 0) //Received a cont with a prior init pkt
|
||||
return 0;
|
||||
if (last_seq != ctap_req->cont.seq)
|
||||
return ctap_error(CTAP1_ERR_INVALID_SEQ);
|
||||
if (last_req.cid == ctap_req->cid) {
|
||||
memcpy(msg_packet.data + msg_packet.current_len, ctap_req->cont.data, MIN(64 - 5, msg_packet.len - msg_packet.current_len));
|
||||
msg_packet.current_len += MIN(64 - 5, msg_packet.len - msg_packet.current_len);
|
||||
memcpy(&last_req, ctap_req, sizeof(CTAPHID_FRAME));
|
||||
last_seq++;
|
||||
}
|
||||
else if (last_cmd_time+100 > board_millis())
|
||||
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
|
||||
|
||||
}
|
||||
|
||||
if (ctap_req->init.cmd == CTAPHID_INIT) {
|
||||
init_fido(false);
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
memset(ctap_resp, 0, 64);
|
||||
CTAPHID_INIT_REQ *req = (CTAPHID_INIT_REQ *)ctap_req->init.data;
|
||||
CTAPHID_INIT_RESP *resp = (CTAPHID_INIT_RESP *)ctap_resp->init.data;
|
||||
memcpy(resp->nonce, req->nonce, sizeof(resp->nonce));
|
||||
resp->cid = 0x01000000;
|
||||
resp->versionInterface = CTAPHID_IF_VERSION;
|
||||
resp->versionMajor = HSM_SDK_VERSION_MAJOR;
|
||||
resp->versionMinor = HSM_SDK_VERSION_MINOR;
|
||||
resp->capFlags = CAPFLAG_WINK | CAPFLAG_CBOR;
|
||||
|
||||
ctap_resp->cid = CID_BROADCAST;
|
||||
ctap_resp->init.cmd = CTAPHID_INIT;
|
||||
ctap_resp->init.bcntl = 17;
|
||||
ctap_resp->init.bcnth = 0;
|
||||
driver_exec_finished(17);
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
}
|
||||
else if (ctap_req->init.cmd == CTAPHID_WINK) {
|
||||
if (MSG_LEN(ctap_req) != 0) {
|
||||
return ctap_error(CTAP1_ERR_INVALID_LEN);
|
||||
}
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
memcpy(ctap_resp, ctap_req, sizeof(CTAPHID_FRAME));
|
||||
sleep_ms(1000); //For blinking the device during 1 seg
|
||||
hid_write(64);
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
}
|
||||
else if ((last_cmd == CTAPHID_PING || last_cmd == CTAPHID_SYNC) && (msg_packet.len == 0 || (msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
|
||||
memcpy(ctap_resp->init.data, msg_packet.data, msg_packet.len);
|
||||
driver_exec_finished(msg_packet.len);
|
||||
}
|
||||
else {
|
||||
memcpy(ctap_resp->init.data, ctap_req->init.data, MSG_LEN(ctap_req));
|
||||
driver_exec_finished(MSG_LEN(ctap_req));
|
||||
}
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
}
|
||||
else if (ctap_req->init.cmd == CTAPHID_LOCK) {
|
||||
if (MSG_LEN(ctap_req) != 1)
|
||||
return ctap_error(CTAP1_ERR_INVALID_LEN);
|
||||
if (ctap_req->init.data[0] > 10)
|
||||
return ctap_error(CTAP1_ERR_INVALID_PARAMETER);
|
||||
lock = board_millis() + ctap_req->init.data[0] * 1000;
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
memset(ctap_resp, 0, 64);
|
||||
ctap_resp->cid = ctap_req->cid;
|
||||
ctap_resp->init.cmd = ctap_req->init.cmd;
|
||||
hid_write(64);
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
}
|
||||
else if (last_cmd == CTAPHID_MSG && (msg_packet.len == 0 || (msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
|
||||
|
||||
current_app = apps[0].select_aid(&apps[0]);
|
||||
if (thread_type != 1)
|
||||
card_start(apdu_thread);
|
||||
thread_type = 1;
|
||||
|
||||
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0)
|
||||
apdu_sent = apdu_process(msg_packet.data, msg_packet.len);
|
||||
else
|
||||
apdu_sent = apdu_process(ctap_req->init.data, MSG_LEN(ctap_req));
|
||||
DEBUG_PAYLOAD(apdu.data, (int)apdu.nc);
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
}
|
||||
else if (last_cmd == CTAPHID_CBOR && (msg_packet.len == 0 || (msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
|
||||
|
||||
if (thread_type != 2)
|
||||
card_start(cbor_thread);
|
||||
thread_type = 2;
|
||||
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0)
|
||||
apdu_sent = cbor_process(msg_packet.data, msg_packet.len);
|
||||
else
|
||||
apdu_sent = cbor_process(ctap_req->init.data, MSG_LEN(ctap_req));
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
if (apdu_sent < 0)
|
||||
return ctap_error(-apdu_sent);
|
||||
}
|
||||
else if (ctap_req->init.cmd == CTAPHID_CANCEL) {
|
||||
ctap_error(0x2D);
|
||||
msg_packet.len = msg_packet.current_len = 0;
|
||||
last_packet_time = 0;
|
||||
cancel_button = true;
|
||||
}
|
||||
else {
|
||||
if (msg_packet.len == 0)
|
||||
return ctap_error(CTAP1_ERR_INVALID_CMD);
|
||||
}
|
||||
// echo back anything we received from host
|
||||
//tud_hid_report(0, buffer, bufsize);
|
||||
//printf("END\n");
|
||||
usb_clear_rx();
|
||||
}
|
||||
return apdu_sent;
|
||||
}
|
||||
|
||||
void send_keepalive() {
|
||||
CTAPHID_FRAME *resp = (CTAPHID_FRAME *)(usb_get_tx() + 4096);
|
||||
//memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
|
||||
resp->cid = ctap_req->cid;
|
||||
resp->init.cmd = CTAPHID_KEEPALIVE;
|
||||
resp->init.bcntl = 1;
|
||||
resp->init.data[0] = is_req_button_pending() ? 2 : 1;
|
||||
send_buffer_size = 0;
|
||||
hid_write_offset(64, 4096);
|
||||
}
|
||||
|
||||
void driver_exec_timeout() {
|
||||
send_keepalive();
|
||||
}
|
||||
|
||||
uint8_t *driver_prepare_response() {
|
||||
ctap_resp = (CTAPHID_FRAME *)usb_get_tx();
|
||||
apdu.rdata = ctap_resp->init.data;
|
||||
send_buffer_size = 0;
|
||||
memset(usb_get_tx(), 0, 4096);
|
||||
return ctap_resp->init.data;
|
||||
}
|
||||
|
||||
void driver_exec_finished(size_t size_next) {
|
||||
|
||||
if (thread_type == 2 && apdu.sw != 0)
|
||||
ctap_error(apdu.sw & 0xff);
|
||||
else
|
||||
driver_exec_finished_cont(size_next, 7);
|
||||
apdu.sw = 0;
|
||||
}
|
||||
|
||||
void driver_exec_finished_cont(size_t size_next, size_t offset) {
|
||||
offset -= 7;
|
||||
ctap_resp = (CTAPHID_FRAME *)(usb_get_tx() + offset);
|
||||
ctap_resp->cid = ctap_req->cid;
|
||||
ctap_resp->init.cmd = last_cmd;
|
||||
ctap_resp->init.bcnth = size_next >> 8;
|
||||
ctap_resp->init.bcntl = size_next & 0xff;
|
||||
hid_write_offset(64, offset);
|
||||
ctap_resp = (CTAPHID_FRAME *)((uint8_t *)ctap_resp + 64 - 5);
|
||||
|
||||
send_buffer_size = size_next;
|
||||
send_buffer_size -= MIN(64-7, send_buffer_size);
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
// Common U2F raw message format header - Review Draft
|
||||
// 2014-10-08
|
||||
// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com
|
||||
|
||||
#ifndef __U2F_H_INCLUDED__
|
||||
#define __U2F_H_INCLUDED__
|
||||
|
||||
#ifdef _MSC_VER // Windows
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long int uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// General constants
|
||||
|
||||
#define U2F_EC_KEY_SIZE 32 // EC key size in bytes
|
||||
#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point
|
||||
#define U2F_MAX_KH_SIZE 128 // Max size of key handle
|
||||
#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate
|
||||
#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature
|
||||
#define U2F_CTR_SIZE 4 // Size of counter field
|
||||
#define U2F_APPID_SIZE 32 // Size of application id
|
||||
#define U2F_CHAL_SIZE 32 // Size of challenge
|
||||
|
||||
#define ENC_SIZE(x) ((x + 7) & 0xfff8)
|
||||
|
||||
// EC (uncompressed) point
|
||||
|
||||
#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format
|
||||
|
||||
typedef struct {
|
||||
uint8_t pointFormat; // Point type
|
||||
uint8_t x[U2F_EC_KEY_SIZE]; // X-value
|
||||
uint8_t y[U2F_EC_KEY_SIZE]; // Y-value
|
||||
} U2F_EC_POINT;
|
||||
|
||||
// U2F native commands
|
||||
|
||||
#define U2F_REGISTER 0x01 // Registration command
|
||||
#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command
|
||||
#define U2F_VERSION 0x03 // Read version string command
|
||||
|
||||
#define U2F_VENDOR_FIRST 0x40 // First vendor defined command
|
||||
#define U2F_VENDOR_LAST 0xbf // Last vendor defined command
|
||||
|
||||
// U2F_CMD_REGISTER command defines
|
||||
|
||||
#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier
|
||||
#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier
|
||||
|
||||
typedef struct {
|
||||
uint8_t chal[U2F_CHAL_SIZE]; // Challenge
|
||||
uint8_t appId[U2F_APPID_SIZE]; // Application id
|
||||
} U2F_REGISTER_REQ;
|
||||
|
||||
typedef struct {
|
||||
uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2)
|
||||
U2F_EC_POINT pubKey; // Generated public key
|
||||
uint8_t keyHandleLen; // Length of key handle
|
||||
uint8_t keyHandleCertSig[
|
||||
U2F_MAX_KH_SIZE + // Key handle
|
||||
U2F_MAX_ATT_CERT_SIZE + // Attestation certificate
|
||||
U2F_MAX_EC_SIG_SIZE]; // Registration signature
|
||||
} U2F_REGISTER_RESP;
|
||||
|
||||
// U2F_CMD_AUTHENTICATE command defines
|
||||
|
||||
// Authentication control byte
|
||||
|
||||
#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign
|
||||
#define U2F_AUTH_CHECK_ONLY 0x07 // Check only
|
||||
#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set
|
||||
|
||||
typedef struct {
|
||||
uint8_t chal[U2F_CHAL_SIZE]; // Challenge
|
||||
uint8_t appId[U2F_APPID_SIZE]; // Application id
|
||||
uint8_t keyHandleLen; // Length of key handle
|
||||
uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle
|
||||
} U2F_AUTHENTICATE_REQ;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags; // U2F_AUTH_FLAG_ values
|
||||
uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian)
|
||||
uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature
|
||||
} U2F_AUTHENTICATE_RESP;
|
||||
|
||||
// Command status responses
|
||||
|
||||
#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR
|
||||
#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA
|
||||
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED
|
||||
#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED
|
||||
#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __U2F_H_INCLUDED__
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
// Common U2F HID transport header - Review Draft
|
||||
// 2014-10-08
|
||||
// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com
|
||||
|
||||
#ifndef __U2FHID_H_INCLUDED__
|
||||
#define __U2FHID_H_INCLUDED__
|
||||
|
||||
#ifdef _MSC_VER // Windows
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long int uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Size of HID reports
|
||||
|
||||
#define HID_RPT_SIZE 64 // Default size of raw HID report
|
||||
|
||||
// Frame layout - command- and continuation frames
|
||||
|
||||
#define CID_BROADCAST 0xffffffff // Broadcast channel id
|
||||
|
||||
#define TYPE_MASK 0x80 // Frame type mask
|
||||
#define TYPE_INIT 0x80 // Initial frame identifier
|
||||
#define TYPE_CONT 0x00 // Continuation frame identifier
|
||||
|
||||
typedef struct {
|
||||
uint32_t cid; // Channel identifier
|
||||
union {
|
||||
uint8_t type; // Frame type - b7 defines type
|
||||
struct {
|
||||
uint8_t cmd; // Command - b7 set
|
||||
uint8_t bcnth; // Message byte count - high part
|
||||
uint8_t bcntl; // Message byte count - low part
|
||||
uint8_t data[HID_RPT_SIZE - 7]; // Data payload
|
||||
} init;
|
||||
struct {
|
||||
uint8_t seq; // Sequence number - b7 cleared
|
||||
uint8_t data[HID_RPT_SIZE - 5]; // Data payload
|
||||
} cont;
|
||||
};
|
||||
}__packed U2FHID_FRAME;
|
||||
|
||||
#define FRAME_TYPE(f) ((f)->type & TYPE_MASK)
|
||||
#define FRAME_CMD(f) ((f)->init.cmd & ~TYPE_MASK)
|
||||
#define MSG_LEN(f) ((f)->init.bcnth*256 + (f)->init.bcntl)
|
||||
#define FRAME_SEQ(f) ((f)->cont.seq & ~TYPE_MASK)
|
||||
|
||||
// HID usage- and usage-page definitions
|
||||
|
||||
#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
|
||||
#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection
|
||||
#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
|
||||
#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
|
||||
|
||||
// General constants
|
||||
|
||||
#define U2FHID_IF_VERSION 2 // Current interface implementation version
|
||||
#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
|
||||
|
||||
// U2FHID native commands
|
||||
|
||||
#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
|
||||
#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame
|
||||
#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
|
||||
#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization
|
||||
#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
|
||||
#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command
|
||||
#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response
|
||||
|
||||
#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
|
||||
#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command
|
||||
|
||||
// U2FHID_INIT command defines
|
||||
|
||||
#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
|
||||
#define CAPFLAG_WINK 0x01 // Device supports WINK command
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
|
||||
}__packed U2FHID_INIT_REQ;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
|
||||
uint32_t cid; // Channel identifier
|
||||
uint8_t versionInterface; // Interface version
|
||||
uint8_t versionMajor; // Major version number
|
||||
uint8_t versionMinor; // Minor version number
|
||||
uint8_t versionBuild; // Build version number
|
||||
uint8_t capFlags; // Capabilities flags
|
||||
}__packed U2FHID_INIT_RESP;
|
||||
|
||||
// U2FHID_SYNC command defines
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce; // Client application nonce
|
||||
} U2FHID_SYNC_REQ;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce; // Client application nonce
|
||||
} U2FHID_SYNC_RESP;
|
||||
|
||||
// Low-level error codes. Return as negatives.
|
||||
|
||||
#define ERR_NONE 0x00 // No error
|
||||
#define ERR_INVALID_CMD 0x01 // Invalid command
|
||||
#define ERR_INVALID_PAR 0x02 // Invalid parameter
|
||||
#define ERR_INVALID_LEN 0x03 // Invalid message length
|
||||
#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing
|
||||
#define ERR_MSG_TIMEOUT 0x05 // Message has timed out
|
||||
#define ERR_CHANNEL_BUSY 0x06 // Channel busy
|
||||
#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
|
||||
#define ERR_SYNC_FAIL 0x0b // SYNC command failed
|
||||
#define ERR_OTHER 0x7f // Other unspecified error
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __U2FHID_H_INCLUDED__
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
#include "u2f_hid.h"
|
||||
#include "ctap_hid.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "hsm_version.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||
@@ -49,7 +51,7 @@ tusb_desc_device_t const desc_device =
|
||||
|
||||
.idVendor = 0xCafe,
|
||||
.idProduct = 0x4231,
|
||||
.bcdDevice = 0x0100,
|
||||
.bcdDevice = HSM_SDK_VERSION,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
@@ -69,9 +71,9 @@ uint8_t const * tud_descriptor_device_cb(void)
|
||||
// HID Report Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define TUD_HID_REPORT_DESC_U2F(report_size, ...) \
|
||||
#define TUD_HID_REPORT_DESC_CTAP(report_size, ...) \
|
||||
HID_USAGE_PAGE_N ( FIDO_USAGE_PAGE, 2 ),\
|
||||
HID_USAGE ( FIDO_USAGE_U2FHID ),\
|
||||
HID_USAGE ( FIDO_USAGE_CTAPHID ),\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
@@ -93,7 +95,7 @@ uint8_t const * tud_descriptor_device_cb(void)
|
||||
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_U2F(CFG_TUD_HID_EP_BUFSIZE)
|
||||
TUD_HID_REPORT_DESC_CTAP(CFG_TUD_HID_EP_BUFSIZE)
|
||||
};
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
@@ -145,8 +147,8 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||
char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"Pol Henarejos", // 1: Manufacturer
|
||||
"Pico HSM HID", // 2: Product
|
||||
"123456", // 3: Serials, should use chip ID
|
||||
};
|
||||
|
||||
@@ -160,33 +162,37 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if ( index == 0)
|
||||
{
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
}else
|
||||
{
|
||||
}
|
||||
else {
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
|
||||
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) )
|
||||
return NULL;
|
||||
|
||||
const char* str = string_desc_arr[index];
|
||||
char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
if (index == 3) {
|
||||
pico_unique_board_id_t unique_id;
|
||||
pico_get_unique_board_id(&unique_id);
|
||||
pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1);
|
||||
str = unique_id_str;
|
||||
}
|
||||
|
||||
// Cap at max char
|
||||
chr_count = (uint8_t) strlen(str);
|
||||
if ( chr_count > 31 ) chr_count = 31;
|
||||
chr_count = strlen(str);
|
||||
if ( chr_count > 31 )
|
||||
chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for(uint8_t i=0; i<chr_count; i++)
|
||||
{
|
||||
for(uint8_t i=0; i<chr_count; i++) {
|
||||
_desc_str[1+i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,14 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
// Device specific functions
|
||||
static uint8_t rx_buffer[4096], tx_buffer[4096];
|
||||
static uint8_t rx_buffer[4096], tx_buffer[4096+64];
|
||||
static uint16_t w_offset = 0, r_offset = 0;
|
||||
static uint16_t w_len = 0, tx_r_offset = 0;
|
||||
static uint32_t timeout_counter = 0;
|
||||
|
||||
void usb_set_timeout_counter(uint32_t v) {
|
||||
timeout_counter = v;
|
||||
}
|
||||
|
||||
uint32_t usb_write_offset(uint16_t len, uint16_t offset) {
|
||||
uint8_t pkt_max = 64;
|
||||
@@ -129,6 +134,8 @@ void usb_init() {
|
||||
driver_init();
|
||||
}
|
||||
|
||||
extern int driver_process_usb_nopacket();
|
||||
|
||||
static int usb_event_handle() {
|
||||
uint16_t rx_read = usb_read_available();
|
||||
if (driver_process_usb_packet(rx_read) > 0) {
|
||||
@@ -136,50 +143,22 @@ static int usb_event_handle() {
|
||||
queue_add_blocking(&usb_to_card_q, &flag);
|
||||
timeout_start();
|
||||
}
|
||||
else
|
||||
driver_process_usb_nopacket();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void card_init_core1(void) {
|
||||
//gpg_data_scan (flash_do_start, flash_do_end);
|
||||
extern void low_flash_init();
|
||||
void card_init_core1() {
|
||||
low_flash_init_core1();
|
||||
}
|
||||
|
||||
void card_thread() {
|
||||
card_init_core1();
|
||||
size_t finished_data_size = 0;
|
||||
|
||||
while (1) {
|
||||
uint32_t m;
|
||||
queue_remove_blocking(&usb_to_card_q, &m);
|
||||
|
||||
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE)
|
||||
{
|
||||
set_res_sw (0x6f, 0x00);
|
||||
goto done;
|
||||
}
|
||||
else if (m == EV_EXIT) {
|
||||
if (current_app && current_app->unload) {
|
||||
current_app->unload();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
process_apdu();
|
||||
|
||||
done:;
|
||||
uint32_t flag = EV_EXEC_FINISHED;
|
||||
queue_add_blocking(&card_to_usb_q, &flag);
|
||||
}
|
||||
//printf("EXIT !!!!!!\r\n");
|
||||
if (current_app && current_app->unload)
|
||||
current_app->unload();
|
||||
}
|
||||
|
||||
void card_thread();
|
||||
void card_start()
|
||||
{
|
||||
void card_start(void (*func)(void)) {
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(card_thread);
|
||||
multicore_launch_core1(func);
|
||||
led_set_blink(BLINK_MOUNTED);
|
||||
}
|
||||
|
||||
@@ -201,10 +180,9 @@ void usb_task() {
|
||||
// printf("\r\n ------ M = %lu\r\n",m);
|
||||
if (has_m) {
|
||||
if (m == EV_EXEC_FINISHED) {
|
||||
apdu_finish();
|
||||
size_t size_next = apdu_next();
|
||||
driver_exec_finished(size_next);
|
||||
driver_exec_finished(finished_data_size);
|
||||
led_set_blink(BLINK_MOUNTED);
|
||||
timeout_stop();
|
||||
}
|
||||
else if (m == EV_PRESS_BUTTON) {
|
||||
uint32_t flag = wait_button() ? EV_BUTTON_TIMEOUT : EV_BUTTON_PRESSED;
|
||||
@@ -262,7 +240,7 @@ void usb_task() {
|
||||
}
|
||||
else {
|
||||
if (timeout > 0) {
|
||||
if (timeout + 1500 < board_millis()) {
|
||||
if (timeout + timeout_counter < board_millis()) {
|
||||
driver_exec_timeout();
|
||||
timeout = board_millis();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ extern void driver_exec_timeout();
|
||||
extern bool driver_mounted();
|
||||
extern uint8_t *driver_prepare_response();
|
||||
|
||||
extern void card_start();
|
||||
extern void card_start(void (*func)(void));
|
||||
extern void card_exit();
|
||||
extern void usb_init();
|
||||
extern uint8_t *usb_prepare_response();
|
||||
@@ -56,4 +56,8 @@ extern uint8_t *usb_get_rx();
|
||||
extern uint8_t *usb_get_tx();
|
||||
extern uint32_t usb_write_offset(uint16_t len, uint16_t offset);
|
||||
extern void usb_clear_rx();
|
||||
extern size_t finished_data_size;
|
||||
extern void usb_set_timeout_counter(uint32_t v);
|
||||
extern void card_init_core1();
|
||||
|
||||
#endif
|
||||
|
||||
1
tinycbor
Submodule
1
tinycbor
Submodule
Submodule tinycbor added at e27261ed5e
Reference in New Issue
Block a user