diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a5ae58..46af1c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,14 +17,20 @@ cmake_minimum_required(VERSION 3.13) +if(ENABLE_EMULATION) +else() include(pico_sdk_import.cmake) +endif() project(pico_fido C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) +if(ENABLE_EMULATION) +else() pico_sdk_init() +endif() add_executable(pico_fido) @@ -70,7 +76,7 @@ else() set(USB_ITF_CCID 0) endif() -target_sources(pico_fido PUBLIC +set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c @@ -91,12 +97,12 @@ target_sources(pico_fido PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_large_blobs.c ) if (${ENABLE_OATH_APP}) -target_sources(pico_fido PUBLIC +set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/fido/oath.c ) endif() if (${ENABLE_OTP_APP}) -target_sources(pico_fido PUBLIC +set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/fido/otp.c ) endif() @@ -104,10 +110,13 @@ endif() set(USB_ITF_HID 1) include(pico-hsm-sdk/pico_hsm_sdk_import.cmake) -target_include_directories(pico_fido PUBLIC +set(INCLUDES ${INCLUDES} ${CMAKE_CURRENT_LIST_DIR}/src/fido ) +target_sources(pico_fido PUBLIC ${SOURCES}) +target_include_directories(pico_fido PUBLIC ${INCLUDES}) + target_compile_options(pico_fido PUBLIC -Wall -Werror @@ -119,6 +128,16 @@ if (${COMPILER_COLON} GREATER_EQUAL 0) ) endif() -pico_add_extra_outputs(pico_fido) +if(ENABLE_EMULATION) +target_compile_options(pico_fido PUBLIC + -fdata-sections + -ffunction-sections + ) + target_link_options(pico_fido PUBLIC + -Wl,-dead_strip + ) +else() +pico_add_extra_outputs(pico_fido) target_link_libraries(pico_fido PRIVATE pico_hsm_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board) +endif() diff --git a/pico-hsm-sdk b/pico-hsm-sdk index 88b2978..4919eb9 160000 --- a/pico-hsm-sdk +++ b/pico-hsm-sdk @@ -1 +1 @@ -Subproject commit 88b2978ae5cf3f1de95ebaec0aec0acd3a24878e +Subproject commit 4919eb980f22652aeb5ad91fbdeaeb510ffb7ca3 diff --git a/src/fido/cbor.c b/src/fido/cbor.c index aebc662..717d0cf 100644 --- a/src/fido/cbor.c +++ b/src/fido/cbor.c @@ -15,7 +15,10 @@ * along with this program. If not, see . */ +#ifndef ENABLE_EMULATION #include "pico/stdlib.h" +#endif +#include "hid/ctap_hid.h" #include "ctap.h" #include "fido.h" #include "usb.h" @@ -45,7 +48,9 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) { if (len == 0) return CTAP1_ERR_INVALID_LEN; DEBUG_DATA(data+1,len-1); +#ifndef ENABLE_EMULATION driver_prepare_response_hid(); +#endif if (cmd == CTAPHID_CBOR) { if (data[0] == CTAP_MAKE_CREDENTIAL) return cbor_make_credential(data + 1, len - 1); @@ -74,6 +79,7 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) { return CTAP2_ERR_INVALID_CBOR; } +#ifndef ENABLE_EMULATION void cbor_thread() { card_init_core1(); @@ -90,10 +96,12 @@ void cbor_thread() { DEBUG_DATA(res_APDU + 1, res_APDU_size); finished_data_size = res_APDU_size+1; + uint32_t flag = EV_EXEC_FINISHED; queue_add_blocking(&card_to_usb_q, &flag); } } +#endif int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len) { cbor_data = data; diff --git a/src/fido/cbor_client_pin.c b/src/fido/cbor_client_pin.c index 5b4dadc..0765e1b 100644 --- a/src/fido/cbor_client_pin.c +++ b/src/fido/cbor_client_pin.c @@ -23,7 +23,10 @@ #include "cbor.h" #include "ctap.h" #include "ctap2_cbor.h" +#ifndef ENABLE_EMULATION #include "bsp/board.h" +#endif +#include "hid/ctap_hid.h" #include "fido.h" #include "files.h" #include "random.h" diff --git a/src/fido/cbor_config.c b/src/fido/cbor_config.c index 2029748..dff4014 100644 --- a/src/fido/cbor_config.c +++ b/src/fido/cbor_config.c @@ -18,6 +18,7 @@ #include "ctap2_cbor.h" #include "fido.h" #include "ctap.h" +#include "hid/ctap_hid.h" #include "files.h" #include "apdu.h" #include "credential.h" diff --git a/src/fido/cbor_cred_mgmt.c b/src/fido/cbor_cred_mgmt.c index e43a749..c4994d1 100644 --- a/src/fido/cbor_cred_mgmt.c +++ b/src/fido/cbor_cred_mgmt.c @@ -17,6 +17,7 @@ #include "fido.h" #include "ctap.h" +#include "hid/ctap_hid.h" #include "cbor_make_credential.h" #include "files.h" #include "apdu.h" diff --git a/src/fido/cbor_get_assertion.c b/src/fido/cbor_get_assertion.c index b7b589a..2ed9b14 100644 --- a/src/fido/cbor_get_assertion.c +++ b/src/fido/cbor_get_assertion.c @@ -17,7 +17,10 @@ #include "cbor.h" #include "ctap.h" +#ifndef ENABLE_EMULATION #include "bsp/board.h" +#endif +#include "hid/ctap_hid.h" #include "fido.h" #include "files.h" #include "crypto_utils.h" diff --git a/src/fido/cbor_get_info.c b/src/fido/cbor_get_info.c index 689ddca..15cfcc1 100644 --- a/src/fido/cbor_get_info.c +++ b/src/fido/cbor_get_info.c @@ -16,6 +16,7 @@ */ #include "ctap2_cbor.h" +#include "hid/ctap_hid.h" #include "fido.h" #include "ctap.h" #include "files.h" diff --git a/src/fido/cbor_large_blobs.c b/src/fido/cbor_large_blobs.c index 24b685b..2f7876e 100644 --- a/src/fido/cbor_large_blobs.c +++ b/src/fido/cbor_large_blobs.c @@ -18,6 +18,7 @@ #include "ctap2_cbor.h" #include "fido.h" #include "ctap.h" +#include "hid/ctap_hid.h" #include "files.h" #include "apdu.h" #include "hsm.h" diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index d2ffa40..80da1f0 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -17,6 +17,7 @@ #include "cbor_make_credential.h" #include "ctap2_cbor.h" +#include "hid/ctap_hid.h" #include "fido.h" #include "ctap.h" #include "files.h" diff --git a/src/fido/cbor_reset.c b/src/fido/cbor_reset.c index 586d0a8..47b5486 100644 --- a/src/fido/cbor_reset.c +++ b/src/fido/cbor_reset.c @@ -19,17 +19,21 @@ #include "file.h" #include "fido.h" #include "ctap.h" +#ifndef ENABLE_EMULATION #include "bsp/board.h" +#endif extern void scan_all(); int cbor_reset() { +#ifndef ENABLE_EMULATION #if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET==1 if (board_millis() > 10000) return CTAP2_ERR_NOT_ALLOWED; #endif if (wait_button_pressed() == true) return CTAP2_ERR_USER_ACTION_TIMEOUT; +#endif initialize_flash(true); init_fido(); return 0; diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c index 5039caf..8e65252 100644 --- a/src/fido/cbor_vendor.c +++ b/src/fido/cbor_vendor.c @@ -18,6 +18,7 @@ #include "ctap2_cbor.h" #include "fido.h" #include "ctap.h" +#include "hid/ctap_hid.h" #include "files.h" #include "apdu.h" #include "hsm.h" @@ -241,8 +242,14 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { mbedtls_ecdsa_free(&ekey); CBOR_ERROR(CTAP2_ERR_PROCESSING); } +#ifndef ENABLE_EMULATION pico_unique_board_id_t rpiid; pico_get_unique_board_id(&rpiid); +#else + struct { + uint8_t id[8]; + } rpiid = {0}; +#endif mbedtls_x509write_csr ctx; mbedtls_x509write_csr_init(&ctx); snprintf((char *)buffer, sizeof(buffer), "C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %llu", ((uint64_t)rpiid.id[0] << 56) | ((uint64_t)rpiid.id[1] << 48) | ((uint64_t)rpiid.id[2] << 40) | ((uint64_t)rpiid.id[3] << 32) | (rpiid.id[4] << 24) | (rpiid.id[5] << 16) | (rpiid.id[6] << 8) | rpiid.id[7]); diff --git a/src/fido/cmd_register.c b/src/fido/cmd_register.c index 432132c..4890135 100644 --- a/src/fido/cmd_register.c +++ b/src/fido/cmd_register.c @@ -21,6 +21,7 @@ #include "ctap.h" #include "random.h" #include "files.h" +#include "hid/ctap_hid.h" const uint8_t *bogus_firefox = (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const uint8_t *bogus_chrome = (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; @@ -38,7 +39,11 @@ int cmd_register() { if (wait_button_pressed() == true) return SW_CONDITIONS_NOT_SATISFIED(); if (memcmp(req->appId, bogus_firefox, CTAP_APPID_SIZE) == 0 || memcmp(req->appId, bogus_chrome, CTAP_APPID_SIZE) == 0) +#ifndef ENABLE_EMULATION return ctap_error(CTAP1_ERR_CHANNEL_BUSY); +#else + return SW_DATA_INVALID(); +#endif mbedtls_ecdsa_context key; mbedtls_ecdsa_init(&key); int ret = derive_key(req->appId, true, resp->keyHandleCertSig, MBEDTLS_ECP_DP_SECP256R1, &key); diff --git a/src/fido/credential.c b/src/fido/credential.c index bfe7a30..c6a928b 100644 --- a/src/fido/credential.c +++ b/src/fido/credential.c @@ -18,7 +18,10 @@ #include "mbedtls/chachapoly.h" #include "mbedtls/sha256.h" #include "credential.h" +#ifndef ENABLE_EMULATION #include "bsp/board.h" +#endif +#include "hid/ctap_hid.h" #include "fido.h" #include "ctap.h" #include "random.h" diff --git a/src/fido/ctap.h b/src/fido/ctap.h index ad012f9..a82c608 100644 --- a/src/fido/ctap.h +++ b/src/fido/ctap.h @@ -24,7 +24,9 @@ typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long int uint64_t; #else +#include #include +#include #endif #ifdef __cplusplus diff --git a/src/fido/fido.c b/src/fido/fido.c index c9e42f5..a1295fb 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -24,8 +24,11 @@ #include "random.h" #include "mbedtls/x509_crt.h" #include "mbedtls/hkdf.h" -#ifdef USB_ITF_CCID -#include "ccid.h" +#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) +#include "ccid/ccid.h" +#endif +#ifndef ENABLE_EMULATION +#include "bsp/board.h" #endif #include @@ -58,7 +61,7 @@ app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { } void __attribute__ ((constructor)) fido_ctor() { -#ifdef USB_ITF_CCID +#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) ccid_atr = atr_fido; #endif register_app(fido_select); @@ -308,11 +311,13 @@ void init_fido() { bool wait_button_pressed() { uint32_t val = EV_PRESS_BUTTON; +#ifndef ENABLE_EMULATION #if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON==1 queue_try_add(&card_to_usb_q, &val); do { queue_remove_blocking(&usb_to_card_q, &val); } while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT); +#endif #endif return (val == EV_BUTTON_TIMEOUT); } diff --git a/src/fido/fido.h b/src/fido/fido.h index 8230cb9..72f363a 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -18,10 +18,16 @@ #ifndef _FIDO_H_ #define _FIDO_H_ +#ifndef ENABLE_EMULATION #include "pico/stdlib.h" +#endif #include "common.h" #include "mbedtls/ecdsa.h" +#ifndef ENABLE_EMULATION #include "ctap_hid.h" +#else +#include +#endif #define CTAP_PUBKEY_LEN (65) #define KEY_PATH_LEN (32) @@ -33,7 +39,6 @@ extern int scan_files(); extern int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int, mbedtls_ecdsa_context *key); extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *); extern bool wait_button_pressed(); -extern CTAPHID_FRAME *ctap_req, *ctap_resp; extern void init_fido(); extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key); diff --git a/src/fido/oath.c b/src/fido/oath.c index 67ea75e..812b3b5 100644 --- a/src/fido/oath.c +++ b/src/fido/oath.c @@ -75,12 +75,17 @@ app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = 8; +#ifndef ENABLE_EMULATION pico_get_unique_board_id((pico_unique_board_id_t *)(res_APDU+res_APDU_size)); res_APDU_size += 8; +#else + memset(res_APDU+res_APDU_size,0,8); res_APDU_size += 8; +#endif if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) { res_APDU[res_APDU_size++] = TAG_CHALLENGE; res_APDU[res_APDU_size++] = sizeof(challenge); memcpy(res_APDU+res_APDU_size, challenge, sizeof(challenge)); res_APDU_size += sizeof(challenge); } + apdu.ne = res_APDU_size; return a; } return NULL; @@ -248,6 +253,7 @@ int cmd_list() { } } } + apdu.ne = res_APDU_size; return SW_OK(); } @@ -281,6 +287,7 @@ int cmd_validate() { res_APDU[res_APDU_size++] = TAG_RESPONSE; res_APDU[res_APDU_size++] = mbedtls_md_get_size(md_info); memcpy(res_APDU+res_APDU_size, hmac, mbedtls_md_get_size(md_info)); res_APDU_size += mbedtls_md_get_size(md_info); + apdu.ne = res_APDU_size; return SW_OK(); } @@ -307,6 +314,7 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u res_APDU[res_APDU_size++] = key[1]; memcpy(res_APDU+res_APDU_size, hmac, hmac_size); res_APDU_size += hmac_size; } + apdu.ne = res_APDU_size; return CCID_OK; } @@ -357,6 +365,7 @@ int cmd_calculate() { low_flash_available(); free(tmp); } + apdu.ne = res_APDU_size; return SW_OK(); } @@ -399,6 +408,11 @@ int cmd_calculate_all() { } } } + apdu.ne = res_APDU_size; + return SW_OK(); +} + +int cmd_send_remaining() { return SW_OK(); } @@ -421,6 +435,7 @@ static const cmd_t cmds[] = { { INS_VALIDATE, cmd_validate }, { INS_CALCULATE, cmd_calculate }, { INS_CALC_ALL, cmd_calculate_all }, + { INS_SEND_REMAINING, cmd_send_remaining }, { 0x00, 0x0} }; diff --git a/src/fido/otp.c b/src/fido/otp.c index 1cf6c21..7e41258 100644 --- a/src/fido/otp.c +++ b/src/fido/otp.c @@ -36,7 +36,7 @@ #define CONFIG_LED_INV 0x10 #define CONFIG_STATUS_MASK 0x1f -static uint8_t config_seq[2] = {1}; +static uint8_t config_seq = {1}; typedef struct otp_config { uint8_t fixed_data[FIXED_SIZE]; @@ -52,13 +52,14 @@ typedef struct otp_config { } __attribute__((packed)) otp_config_t; static const size_t otp_config_size = sizeof(otp_config_t); +uint16_t otp_status(); int otp_process_apdu(); int otp_unload(); const uint8_t otp_aid[] = { 7, - 0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01 + 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 }; app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { @@ -66,6 +67,12 @@ app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { a->aid = otp_aid; a->process_apdu = otp_process_apdu; a->unload = otp_unload; + if (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) || file_has_data(search_dynamic_file(EF_OTP_SLOT2))) + config_seq = 1; + else + config_seq = 0; + otp_status(); + apdu.ne = res_APDU_size; return a; } return NULL; @@ -79,13 +86,13 @@ int otp_unload() { return CCID_OK; } -uint16_t otp_status(uint8_t slot) { +uint16_t otp_status() { res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[res_APDU_size++] = 0; - res_APDU[res_APDU_size++] = config_seq[slot]; + res_APDU[res_APDU_size++] = config_seq; res_APDU[res_APDU_size++] = 0; - res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) | (config_seq[0] > 0 ? CONFIG1_VALID : 0x00) | (config_seq[1] > 0 ? CONFIG2_VALID : 0x00); + res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) | (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID : 0x00) | (file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID : 0x00); return SW_OK(); } @@ -99,7 +106,6 @@ int cmd_otp() { return SW_WRONG_LENGTH(); if (apdu.data[48] != 0 || apdu.data[49] != 0) return SW_WRONG_DATA(); - uint8_t slot = p1 == 0x01 ? 0 : 1; file_t *ef = file_new(p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); if (file_has_data(ef)) { otp_config_t *otpc = (otp_config_t *)file_get_data(ef); @@ -110,14 +116,21 @@ int cmd_otp() { if (apdu.data[c] != 0) { flash_write_data_to_file(ef, apdu.data, otp_config_size); low_flash_available(); - config_seq[slot]++; - return otp_status(slot); + config_seq++; + return otp_status(); } } // Delete slot delete_file(ef); - config_seq[slot] = 0; - return otp_status(slot); + if (!file_has_data(search_dynamic_file(EF_OTP_SLOT1)) && !file_has_data(search_dynamic_file(EF_OTP_SLOT2))) + config_seq = 0; + return otp_status(); + } + else if (p1 == 0x10) { +#ifndef ENABLE_EMULATION + pico_get_unique_board_id_string((char *)res_APDU, 4); +#endif + res_APDU_size = 4; } return SW_OK(); }