13 Commits

Author SHA1 Message Date
Pol Henarejos
ab6cc09c08 Merge branch 'main' into development 2026-01-26 23:39:33 +01:00
Pol Henarejos
cba1db783f Upgrade to v7.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 23:39:18 +01:00
Pol Henarejos
9788029e8a Upgrade to Pico Keys SDK 8.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 23:24:29 +01:00
Pol Henarejos
dfd7927413 Merge branch 'main' into development 2026-01-15 00:51:05 +01:00
Pol Henarejos
cfc23a1f0e Merge branch 'main' into development 2026-01-07 23:39:08 +01:00
Pol Henarejos
a7630dca5c Merge branch 'main' into development 2025-12-11 20:01:15 +01:00
Pol Henarejos
7f31e6a00f Merge branch 'main' into development 2025-12-09 18:52:23 +01:00
Pol Henarejos
a1cb2fa3bf Merge branch 'main' into development 2025-12-02 14:40:25 +01:00
Pol Henarejos
faceaf8fc6 Merge branch 'main' into development
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-02 10:22:07 +01:00
Pol Henarejos
c33b133c6b Add support for RP2354.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-15 19:57:43 +01:00
Pol Henarejos
8036a5dda4 Merge branch 'main' into development 2025-11-15 19:57:19 +01:00
Pol Henarejos
f3866c4a93 Merge pull request #189 from sylvainpelissier/autobuild
Bump autobuild bump to esp-idf 5.5.1 and add pico parallel build
2025-11-10 00:58:19 +01:00
Sylvain
105cf61866 Bump autobuild to esp-idf 5.5.1 and add pico parallel build 2025-09-27 10:42:13 +02:00
36 changed files with 834 additions and 773 deletions

View File

@@ -1,19 +1,19 @@
# #
# This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido). # This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
# Copyright (c) 2022 Pol Henarejos. # Copyright (c) 2022 Pol Henarejos.
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3. # the Free Software Foundation, version 3.
# #
# This program is distributed in the hope that it will be useful, but # This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of # WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. # General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
@@ -21,64 +21,51 @@ set(USB_VID 0x2E8A)
set(USB_PID 0x10FE) set(USB_PID 0x10FE)
if(ESP_PLATFORM) if(ESP_PLATFORM)
if(NOT DEFINED ENABLE_POWER_ON_RESET) set(DENABLE_POWER_ON_RESET 0)
set(ENABLE_POWER_ON_RESET 0) set(EXTRA_COMPONENT_DIRS pico-keys-sdk/config/esp32/components src/fido)
endif() include($ENV{IDF_PATH}/tools/cmake/project.cmake)
if(NOT DEFINED ENABLE_PQC)
set(ENABLE_PQC 0)
endif()
set(EXTRA_COMPONENT_DIRS
src/fido
pico-keys-sdk/config/esp32/components/pico-keys-sdk
pico-keys-sdk/config/esp32/components/tinycbor
)
if(ENABLE_PQC)
list(APPEND EXTRA_COMPONENT_DIRS
pico-keys-sdk/config/esp32/components/mlkem512
pico-keys-sdk/config/esp32/components/mlkem768
pico-keys-sdk/config/esp32/components/mlkem1024
)
endif()
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else() else()
if(NOT ENABLE_EMULATION)
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
include(pico_sdk_import.cmake)
endif()
project(pico_fido C CXX ASM) if(ENABLE_EMULATION)
else()
set(CMAKE_C_STANDARD 11) set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
set(CMAKE_CXX_STANDARD 17) include(pico_sdk_import.cmake)
add_executable(pico_fido)
endif() endif()
include(pico-keys-sdk/cmake/options.cmake) project(pico_fido C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
add_executable(pico_fido)
endif()
option(ENABLE_POWER_ON_RESET "Enable/disable power cycle on reset" ON) option(ENABLE_POWER_ON_RESET "Enable/disable power cycle on reset" ON)
configure_bool_option( if(ENABLE_POWER_ON_RESET)
ENABLE_POWER_ON_RESET add_definitions(-DENABLE_POWER_ON_RESET=1)
ENABLE_POWER_ON_RESET message(STATUS "Power cycle on reset: \t enabled")
"Power cycle on reset: \t enabled" else()
"Power cycle on reset: \t disabled" add_definitions(-DENABLE_POWER_ON_RESET=0)
) message(STATUS "Power cycle on reset: \t disabled")
endif(ENABLE_POWER_ON_RESET)
option(ENABLE_OATH_APP "Enable/disable OATH application" ON) option(ENABLE_OATH_APP "Enable/disable OATH application" ON)
configure_bool_option( if(ENABLE_OATH_APP)
ENABLE_OATH_APP add_definitions(-DENABLE_OATH_APP=1)
ENABLE_OATH_APP message(STATUS "OATH Application: \t\t enabled")
"OATH Application: \t\t enabled" else()
"OATH Application: \t\t disabled" add_definitions(-DENABLE_OATH_APP=0)
) message(STATUS "OATH Application: \t\t disabled")
endif(ENABLE_OATH_APP)
option(ENABLE_OTP_APP "Enable/disable OTP application" ON) option(ENABLE_OTP_APP "Enable/disable OTP application" ON)
configure_bool_option( if(ENABLE_OTP_APP)
ENABLE_OTP_APP add_definitions(-DENABLE_OTP_APP=1)
ENABLE_OTP_APP message(STATUS "OTP Application: \t\t enabled")
"OTP Application: \t\t enabled" else()
"OTP Application: \t\t disabled" add_definitions(-DENABLE_OTP_APP=0)
) message(STATUS "OTP Application: \t\t disabled")
endif(ENABLE_OTP_APP)
if(ENABLE_OTP_APP OR ENABLE_OATH_APP) if(ENABLE_OTP_APP OR ENABLE_OATH_APP)
set(USB_ITF_CCID 1) set(USB_ITF_CCID 1)
@@ -88,127 +75,98 @@ else()
endif() endif()
set(USB_ITF_HID 1) set(USB_ITF_HID 1)
include(pico-keys-sdk/picokeys_sdk_import.cmake) include(pico-keys-sdk/pico_keys_sdk_import.cmake)
if(NOT ESP_PLATFORM) if(NOT ESP_PLATFORM)
set(SOURCES ${PICOKEYS_SOURCES}) set(SOURCES ${PICO_KEYS_SOURCES})
endif() endif()
list(APPEND SOURCES set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/kek.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_reset.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_get_info.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_reset.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_make_credential.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_get_info.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/known_apps.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_make_credential.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_client_pin.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/known_apps.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/credential.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_client_pin.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_get_assertion.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/credential.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_selection.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_get_assertion.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_cred_mgmt.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_selection.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_config.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_cred_mgmt.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_vendor.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_config.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_large_blobs.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_vendor.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/management.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cbor_large_blobs.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/defs.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/management.c
) ${CMAKE_CURRENT_LIST_DIR}/src/fido/defs.c
)
if(ENABLE_OATH_APP) if (${ENABLE_OATH_APP})
list(APPEND SOURCES set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fido/oath.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/oath.c
) )
endif() endif()
if (${ENABLE_OTP_APP})
if(ENABLE_OTP_APP) set(SOURCES ${SOURCES}
list(APPEND SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/fido/otp.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/otp.c
) )
endif() endif()
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/fido/version.h") SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/fido/version.h" 3)
if(ESP_PLATFORM) if(ESP_PLATFORM)
project(pico_fido) project(pico_fido)
endif() endif()
set(INCLUDES ${INCLUDES} set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/fido ${CMAKE_CURRENT_LIST_DIR}/src/fido
) )
if(NOT ESP_PLATFORM)
if(NOT ESP_PLATFORM) target_sources(pico_fido PUBLIC ${SOURCES})
target_sources(pico_fido PUBLIC ${SOURCES}) target_include_directories(pico_fido PUBLIC ${INCLUDES})
target_include_directories(pico_fido PUBLIC ${INCLUDES})
target_compile_options(pico_fido PUBLIC
set(COMMON_COMPILE_OPTIONS -Wall
-Wall )
) if (NOT MSVC)
target_compile_options(pico_fido PRIVATE ${COMMON_COMPILE_OPTIONS}) target_compile_options(pico_fido PUBLIC
-Werror
picokeys_apply_strict_flags( )
SOURCES ${SOURCES}
FILTER_REGEX "/src/fido/|/pico-keys-sdk/src/|/pico-keys-sdk/config/" string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
) if (${COMPILER_COLON} GREATER_EQUAL 0)
target_compile_options(pico_fido PUBLIC
if(NOT MSVC) -Wno-error=use-after-free
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
if(${COMPILER_COLON} GREATER_EQUAL 0)
target_compile_options(pico_fido PRIVATE
-Wno-error=use-after-free
)
endif()
endif()
if(ENABLE_EMULATION)
if(NOT MSVC)
set(EMULATION_NON_MSVC_COMPILE_OPTIONS
-fdata-sections
-ffunction-sections
)
target_compile_options(pico_fido PRIVATE ${EMULATION_NON_MSVC_COMPILE_OPTIONS})
endif()
if(APPLE)
set(EMULATION_APPLE_LINK_OPTIONS
-Wl,-dead_strip
)
target_link_options(pico_fido PRIVATE ${EMULATION_APPLE_LINK_OPTIONS})
if(DEBUG_APDU)
set(DEBUG_APDU_SANITIZER_OPTIONS
-fsanitize=address
-g
-O1
-fno-omit-frame-pointer
)
target_compile_options(pico_fido PRIVATE ${DEBUG_APDU_SANITIZER_OPTIONS})
target_link_options(pico_fido PRIVATE ${DEBUG_APDU_SANITIZER_OPTIONS})
endif()
else()
set(EMULATION_NON_APPLE_LINK_OPTIONS
-Wl,--gc-sections
)
target_link_options(pico_fido PRIVATE ${EMULATION_NON_APPLE_LINK_OPTIONS})
endif()
target_link_libraries(pico_fido PRIVATE picokeys_sdk mbedtls pthread m)
else()
target_link_libraries(
pico_fido
PRIVATE
picokeys_sdk
pico_stdlib
pico_multicore
hardware_flash
hardware_sync
hardware_adc
pico_unique_id
pico_aon_timer
tinyusb_device
tinyusb_board
) )
pico_add_extra_outputs(${CMAKE_PROJECT_NAME}) endif()
endif() endif(NOT MSVC)
if(ENABLE_EMULATION)
if(NOT MSVC)
target_compile_options(pico_fido PUBLIC
-fdata-sections
-ffunction-sections
)
endif(NOT MSVC)
if(APPLE)
target_link_options(pico_fido PUBLIC
-Wl,-dead_strip
)
if(DEBUG_APDU)
target_compile_options(pico_fido PUBLIC
-fsanitize=address -g -O1 -fno-omit-frame-pointer)
target_link_options(pico_fido PUBLIC
-fsanitize=address -g -O1 -fno-omit-frame-pointer)
endif()
else()
target_link_options(pico_fido PUBLIC
-Wl,--gc-sections
)
endif (APPLE)
target_link_libraries(pico_fido PRIVATE pico_keys_sdk mbedtls pthread m)
else()
target_link_libraries(pico_fido PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id pico_aon_timer tinyusb_device tinyusb_board)
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif()
endif() endif()

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="7" VERSION_MAJOR="7"
VERSION_MINOR="6" VERSION_MINOR="4"
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}" SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then #if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}" # SUFFIX="${SUFFIX}.${GITHUB_SHA}"

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#if defined(PICO_PLATFORM) #if defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#endif #endif
@@ -30,13 +30,26 @@
const bool _btrue = true, _bfalse = false; const bool _btrue = true, _bfalse = false;
int cbor_reset();
int cbor_get_info();
int cbor_make_credential(const uint8_t *data, size_t len);
int cbor_client_pin(const uint8_t *data, size_t len);
int cbor_get_assertion(const uint8_t *data, size_t len, bool next); int cbor_get_assertion(const uint8_t *data, size_t len, bool next);
int cbor_get_next_assertion(const uint8_t *data, size_t len);
int cbor_selection();
int cbor_cred_mgmt(const uint8_t *data, size_t len);
int cbor_config(const uint8_t *data, size_t len);
int cbor_vendor(const uint8_t *data, size_t len);
int cbor_large_blobs(const uint8_t *data, size_t len);
extern void reset_gna_state();
extern int cmd_read_config();
const uint8_t aaguid[16] = { 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2") const uint8_t aaguid[16] = { 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2")
static const uint8_t *volatile cbor_data = NULL; const uint8_t *cbor_data = NULL;
static volatile size_t cbor_len = 0; size_t cbor_len = 0;
static volatile uint8_t cbor_cmd = 0; uint8_t cbor_cmd = 0;
int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) { int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
if (len == 0 && cmd == CTAPHID_CBOR) { if (len == 0 && cmd == CTAPHID_CBOR) {
@@ -85,7 +98,7 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
return cbor_vendor(data, len); return cbor_vendor(data, len);
} }
else if (cmd == 0xC2) { else if (cmd == 0xC2) {
if (man_get_config() == 0) { if (cmd_read_config() == 0x9000) {
memmove(res_APDU-1, res_APDU, res_APDU_size); memmove(res_APDU-1, res_APDU, res_APDU_size);
res_APDU_size -= 1; res_APDU_size -= 1;
return 0; return 0;
@@ -95,7 +108,6 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
return CTAP1_ERR_INVALID_CMD; return CTAP1_ERR_INVALID_CMD;
} }
void *cbor_thread(void *arg) __attribute__((unused));
void *cbor_thread(void *arg) { void *cbor_thread(void *arg) {
(void)arg; (void)arg;
card_init_core1(); card_init_core1();
@@ -108,10 +120,7 @@ void *cbor_thread(void *arg) {
if (m == EV_EXIT) { if (m == EV_EXIT) {
break; break;
} }
const uint8_t *data = (const uint8_t *)cbor_data; apdu.sw = (uint16_t)cbor_parse(cbor_cmd, cbor_data, cbor_len);
size_t len = cbor_len;
uint8_t cmd = cbor_cmd;
apdu.sw = (uint16_t)cbor_parse(cmd, data, len);
if (apdu.sw == 0) { if (apdu.sw == 0) {
DEBUG_DATA(res_APDU, res_APDU_size); DEBUG_DATA(res_APDU, res_APDU_size);
} }
@@ -143,7 +152,7 @@ int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len) {
return 2; // CBOR processing return 2; // CBOR processing
} }
static CborError COSE_key_params(int crv, int alg, mbedtls_ecp_group *grp, mbedtls_ecp_point *Q, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) { CborError COSE_key_params(int crv, int alg, mbedtls_ecp_group *grp, mbedtls_ecp_point *Q, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) {
CborError error = CborNoError; CborError error = CborNoError;
int kty = 1; int kty = 1;
if (crv == FIDO2_CURVE_P256 || crv == FIDO2_CURVE_P384 || crv == FIDO2_CURVE_P521 || if (crv == FIDO2_CURVE_P256 || crv == FIDO2_CURVE_P384 || crv == FIDO2_CURVE_P521 ||

View File

@@ -15,12 +15,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#ifndef ESP_PLATFORM
#include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecp.h" #include "mbedtls/ecp.h"
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "mbedtls/hkdf.h" #include "mbedtls/hkdf.h"
#include "mbedtls/constant_time.h"
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
@@ -33,14 +37,16 @@
#include "random.h" #include "random.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "apdu.h" #include "apdu.h"
#include "kek.h"
uint32_t usage_timer = 0, initial_usage_time_limit = 0; uint32_t usage_timer = 0, initial_usage_time_limit = 0;
uint32_t max_usage_time_period = 600 * 1000; uint32_t max_usage_time_period = 600 * 1000;
bool needs_power_cycle = false; bool needs_power_cycle = false;
static mbedtls_ecdh_context hkey; static mbedtls_ecdh_context hkey;
static bool hkey_init = false; static bool hkey_init = false;
extern int encrypt_keydev_f1(const uint8_t keydev[32]);
static int beginUsingPinUvAuthToken(bool userIsPresent) { int beginUsingPinUvAuthToken(bool userIsPresent) {
paut.user_present = userIsPresent; paut.user_present = userIsPresent;
paut.user_verified = true; paut.user_verified = true;
initial_usage_time_limit = board_millis(); initial_usage_time_limit = board_millis();
@@ -49,25 +55,25 @@ static int beginUsingPinUvAuthToken(bool userIsPresent) {
return 0; return 0;
} }
void clearUserPresentFlag(void) { void clearUserPresentFlag() {
if (paut.in_use == true) { if (paut.in_use == true) {
paut.user_present = false; paut.user_present = false;
} }
} }
void clearUserVerifiedFlag(void) { void clearUserVerifiedFlag() {
if (paut.in_use == true) { if (paut.in_use == true) {
paut.user_verified = false; paut.user_verified = false;
} }
} }
void clearPinUvAuthTokenPermissionsExceptLbw(void) { void clearPinUvAuthTokenPermissionsExceptLbw() {
if (paut.in_use == true) { if (paut.in_use == true) {
paut.permissions = CTAP_PERMISSION_LBW; paut.permissions = CTAP_PERMISSION_LBW;
} }
} }
static void stopUsingPinUvAuthToken(void) { void stopUsingPinUvAuthToken() {
paut.permissions = 0; paut.permissions = 0;
usage_timer = 0; usage_timer = 0;
paut.in_use = false; paut.in_use = false;
@@ -78,21 +84,21 @@ static void stopUsingPinUvAuthToken(void) {
user_present_time_limit = 0; user_present_time_limit = 0;
} }
bool getUserPresentFlagValue(void) { bool getUserPresentFlagValue() {
if (paut.in_use != true) { if (paut.in_use != true) {
paut.user_present = false; paut.user_present = false;
} }
return paut.user_present; return paut.user_present;
} }
bool getUserVerifiedFlagValue(void) { bool getUserVerifiedFlagValue() {
if (paut.in_use != true) { if (paut.in_use != true) {
paut.user_verified = false; paut.user_verified = false;
} }
return paut.user_verified; return paut.user_verified;
} }
static int regenerate(void) { int regenerate() {
if (hkey_init == true) { if (hkey_init == true) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
} }
@@ -100,7 +106,7 @@ static int regenerate(void) {
mbedtls_ecdh_init(&hkey); mbedtls_ecdh_init(&hkey);
hkey_init = true; hkey_init = true;
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1); mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_fill_iterator, NULL); int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1); mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) { if (ret != 0) {
return ret; return ret;
@@ -108,7 +114,7 @@ static int regenerate(void) {
return 0; return 0;
} }
static int kdf(uint8_t protocol, const mbedtls_mpi *z, uint8_t *sharedSecret) { int kdf(uint8_t protocol, const mbedtls_mpi *z, uint8_t *sharedSecret) {
int ret = 0; int ret = 0;
uint8_t buf[32]; uint8_t buf[32];
ret = mbedtls_mpi_write_binary(z, buf, sizeof(buf)); ret = mbedtls_mpi_write_binary(z, buf, sizeof(buf));
@@ -132,25 +138,25 @@ static int kdf(uint8_t protocol, const mbedtls_mpi *z, uint8_t *sharedSecret) {
int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret) { int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret) {
mbedtls_mpi z; mbedtls_mpi z;
mbedtls_mpi_init(&z); mbedtls_mpi_init(&z);
int ret = mbedtls_ecdh_compute_shared(&hkey.ctx.mbed_ecdh.grp, &z, Q, &hkey.ctx.mbed_ecdh.d, random_fill_iterator, NULL); int ret = mbedtls_ecdh_compute_shared(&hkey.ctx.mbed_ecdh.grp, &z, Q, &hkey.ctx.mbed_ecdh.d, random_gen, NULL);
ret = kdf(protocol, &z, sharedSecret); ret = kdf(protocol, &z, sharedSecret);
mbedtls_mpi_free(&z); mbedtls_mpi_free(&z);
return ret; return ret;
} }
static void resetAuthToken(bool persistent) { void resetAuthToken(bool persistent) {
uint16_t fid = EF_AUTHTOKEN; uint16_t fid = EF_AUTHTOKEN;
if (persistent) { if (persistent) {
fid = EF_PAUTHTOKEN; fid = EF_PAUTHTOKEN;
} }
file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF); file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
uint8_t t[32]; uint8_t t[32];
random_fill_buffer(t, sizeof(t)); random_gen(NULL, t, sizeof(t));
file_put_data(ef, t, sizeof(t)); file_put_data(ef, t, sizeof(t));
flash_commit(); low_flash_available();
} }
int resetPinUvAuthToken(void) { int resetPinUvAuthToken() {
resetAuthToken(false); resetAuthToken(false);
paut.permissions = 0; paut.permissions = 0;
paut.data = file_get_data(ef_authtoken); paut.data = file_get_data(ef_authtoken);
@@ -158,9 +164,9 @@ int resetPinUvAuthToken(void) {
return 0; return 0;
} }
int resetPersistentPinUvAuthToken(void) { int resetPersistentPinUvAuthToken() {
resetAuthToken(true); resetAuthToken(true);
file_t *ef_pauthtoken = file_search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF); file_t *ef_pauthtoken = search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF);
ppaut.permissions = 0; ppaut.permissions = 0;
ppaut.data = file_get_data(ef_pauthtoken); ppaut.data = file_get_data(ef_pauthtoken);
ppaut.len = file_get_size(ef_pauthtoken); ppaut.len = file_get_size(ef_pauthtoken);
@@ -170,12 +176,12 @@ int resetPersistentPinUvAuthToken(void) {
int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) { int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) {
if (protocol == 1) { if (protocol == 1) {
memcpy(out, in, in_len); memcpy(out, in, in_len);
return aes_encrypt(key, NULL, 32 * 8, PICOKEYS_AES_MODE_CBC, out, in_len); return aes_encrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
} }
else if (protocol == 2) { else if (protocol == 2) {
random_fill_buffer(out, IV_SIZE); random_gen(NULL, out, IV_SIZE);
memcpy(out + IV_SIZE, in, in_len); memcpy(out + IV_SIZE, in, in_len);
return aes_encrypt(key + 32, out, 32 * 8, PICOKEYS_AES_MODE_CBC, out + IV_SIZE, in_len); return aes_encrypt(key + 32, out, 32 * 8, PICO_KEYS_AES_MODE_CBC, out + IV_SIZE, in_len);
} }
return -1; return -1;
@@ -184,17 +190,17 @@ int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in
int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) { int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) {
if (protocol == 1) { if (protocol == 1) {
memcpy(out, in, in_len); memcpy(out, in, in_len);
return aes_decrypt(key, NULL, 32 * 8, PICOKEYS_AES_MODE_CBC, out, in_len); return aes_decrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
} }
else if (protocol == 2) { else if (protocol == 2) {
memcpy(out, in + IV_SIZE, in_len - IV_SIZE); memcpy(out, in + IV_SIZE, in_len - IV_SIZE);
return aes_decrypt(key + 32, in, 32 * 8, PICOKEYS_AES_MODE_CBC, out, in_len - IV_SIZE); return aes_decrypt(key + 32, in, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len - IV_SIZE);
} }
return -1; return -1;
} }
static int __attribute__((unused)) authenticate(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len, uint8_t *sign) { int authenticate(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len, uint8_t *sign) {
uint8_t hmac[32]; uint8_t hmac[32];
int ret = int ret =
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac); mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac);
@@ -222,24 +228,24 @@ int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t l
return ret; return ret;
} }
if (protocol == 1) { if (protocol == 1) {
return mbedtls_ct_memcmp(sign, hmac, 16); return ct_memcmp(sign, hmac, 16);
} }
else if (protocol == 2) { else if (protocol == 2) {
return mbedtls_ct_memcmp(sign, hmac, 32); return ct_memcmp(sign, hmac, 32);
} }
return -1; return -1;
} }
static int initialize(void) { int initialize() {
regenerate(); regenerate();
return resetPinUvAuthToken(); return resetPinUvAuthToken();
} }
static int __attribute__((unused)) getPublicKey(void) { int getPublicKey() {
return 0; return 0;
} }
static int __attribute__((unused)) pinUvAuthTokenUsageTimerObserver(void) { int pinUvAuthTokenUsageTimerObserver() {
if (usage_timer == 0) { if (usage_timer == 0) {
return -1; return -1;
} }
@@ -260,16 +266,16 @@ static int __attribute__((unused)) pinUvAuthTokenUsageTimerObserver(void) {
return 0; return 0;
} }
static int check_keydev_encrypted(const uint8_t pin_token[32]) { int check_keydev_encrypted(const uint8_t pin_token[32]) {
if (file_get_data(ef_keydev) && *file_get_data(ef_keydev) == 0x01) { if (file_get_data(ef_keydev) && *file_get_data(ef_keydev) == 0x01) {
uint8_t tmp_keydev[61]; uint8_t tmp_keydev[61];
tmp_keydev[0] = 0x03; // Change format to encrypted tmp_keydev[0] = 0x02; // Change format to encrypted
encrypt_with_aad(pin_token, file_get_data(ef_keydev) + 1, 32, 2, tmp_keydev + 1); encrypt_with_aad(pin_token, file_get_data(ef_keydev) + 1, 32, tmp_keydev + 1);
file_put_data(ef_keydev, tmp_keydev, sizeof(tmp_keydev)); file_put_data(ef_keydev, tmp_keydev, sizeof(tmp_keydev));
mbedtls_platform_zeroize(tmp_keydev, sizeof(tmp_keydev)); mbedtls_platform_zeroize(tmp_keydev, sizeof(tmp_keydev));
flash_commit(); low_flash_available();
} }
return PICOKEYS_OK; return PICOKEY_OK;
} }
uint8_t new_pin_mismatches = 0; uint8_t new_pin_mismatches = 0;
@@ -401,7 +407,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_len++; pin_len++;
} }
uint8_t minPin = 4; uint8_t minPin = 4;
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) { if (file_has_data(ef_minpin)) {
minPin = *file_get_data(ef_minpin); minPin = *file_get_data(ef_minpin);
} }
@@ -416,11 +422,11 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(paddedNewPin, sizeof(paddedNewPin)); mbedtls_platform_zeroize(paddedNewPin, sizeof(paddedNewPin));
pin_derive_verifier(dhash, 16, hsh + 3); pin_derive_verifier(dhash, 16, hsh + 3);
file_put_data(ef_pin, hsh, sizeof(hsh)); file_put_data(ef_pin, hsh, sizeof(hsh));
flash_commit(); low_flash_available();
pin_derive_session(dhash, 16, session_pin); pin_derive_session(dhash, 16, session_pin);
ret = check_keydev_encrypted(session_pin); ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(ret); CBOR_ERROR(ret);
} }
mbedtls_platform_zeroize(hsh, sizeof(hsh)); mbedtls_platform_zeroize(hsh, sizeof(hsh));
@@ -475,7 +481,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
memcpy(pin_data, file_get_data(ef_pin), file_get_size(ef_pin)); memcpy(pin_data, file_get_data(ef_pin), file_get_size(ef_pin));
pin_data[0] -= 1; pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, file_get_size(ef_pin)); file_put_data(ef_pin, pin_data, file_get_size(ef_pin));
flash_commit(); low_flash_available();
uint8_t retries = pin_data[0]; uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64]; uint8_t paddedNewPin[64];
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin); ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin);
@@ -492,7 +498,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_verifier(paddedNewPin, 16, dhash); pin_derive_verifier(paddedNewPin, 16, dhash);
} }
if (mbedtls_ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) { if (ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
@@ -513,7 +519,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
hash_multi(paddedNewPin, 16, session_pin); hash_multi(paddedNewPin, 16, session_pin);
ret = load_keydev(keydev); ret = load_keydev(keydev);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
encrypt_keydev_f1(keydev); encrypt_keydev_f1(keydev);
@@ -521,10 +527,10 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_session(paddedNewPin, 16, session_pin); pin_derive_session(paddedNewPin, 16, session_pin);
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
flash_commit(); low_flash_available();
ret = check_keydev_encrypted(session_pin); ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(ret); CBOR_ERROR(ret);
} }
@@ -542,7 +548,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_len++; pin_len++;
} }
uint8_t minPin = 4; uint8_t minPin = 4;
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) { if (file_has_data(ef_minpin)) {
minPin = *file_get_data(ef_minpin); minPin = *file_get_data(ef_minpin);
} }
@@ -552,7 +558,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
// New PIN is valid and verified // New PIN is valid and verified
ret = load_keydev(keydev); ret = load_keydev(keydev);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
encrypt_keydev_f1(keydev); encrypt_keydev_f1(keydev);
@@ -560,17 +566,17 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash);
pin_derive_session(dhash, 16, session_pin); pin_derive_session(dhash, 16, session_pin);
ret = check_keydev_encrypted(session_pin); ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(ret); CBOR_ERROR(ret);
} }
flash_commit(); low_flash_available();
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
pin_data[1] = pin_len; pin_data[1] = pin_len;
pin_data[2] = 1; // New format indicator pin_data[2] = 1; // New format indicator
pin_derive_verifier(dhash, 16, pin_data + 3); pin_derive_verifier(dhash, 16, pin_data + 3);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && mbedtls_ct_memcmp(pin_data + 3, file_get_data(ef_pin) + 3, 32) == 0) { if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && ct_memcmp(pin_data + 3, file_get_data(ef_pin) + 3, 32) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
} }
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
@@ -584,7 +590,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
file_put_data(ef_minpin, tmpf, file_get_size(ef_minpin)); file_put_data(ef_minpin, tmpf, file_get_size(ef_minpin));
free(tmpf); free(tmpf);
} }
flash_commit(); low_flash_available();
resetPinUvAuthToken(); resetPinUvAuthToken();
resetPersistentPinUvAuthToken(); resetPersistentPinUvAuthToken();
needs_power_cycle = false; needs_power_cycle = false;
@@ -637,7 +643,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
memcpy(pin_data, file_get_data(ef_pin), file_get_size(ef_pin)); memcpy(pin_data, file_get_data(ef_pin), file_get_size(ef_pin));
pin_data[0] -= 1; pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, file_get_size(ef_pin)); file_put_data(ef_pin, pin_data, file_get_size(ef_pin));
flash_commit(); low_flash_available();
uint8_t retries = pin_data[0]; uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64], poff = ((uint8_t)pinUvAuthProtocol - 1) * IV_SIZE; uint8_t paddedNewPin[64], poff = ((uint8_t)pinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin); ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin);
@@ -653,7 +659,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
else { else {
pin_derive_verifier(paddedNewPin, 16, dhash); pin_derive_verifier(paddedNewPin, 16, dhash);
} }
if (mbedtls_ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) { if (ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
mbedtls_platform_zeroize(dhash, sizeof(dhash)); mbedtls_platform_zeroize(dhash, sizeof(dhash));
@@ -676,7 +682,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_verifier(paddedNewPin, 16, pin_data + 3); pin_derive_verifier(paddedNewPin, 16, pin_data + 3);
hash_multi(paddedNewPin, 16, session_pin); hash_multi(paddedNewPin, 16, session_pin);
ret = load_keydev(keydev); ret = load_keydev(keydev);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
encrypt_keydev_f1(keydev); encrypt_keydev_f1(keydev);
@@ -684,7 +690,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_session(paddedNewPin, 16, session_pin); pin_derive_session(paddedNewPin, 16, session_pin);
ret = check_keydev_encrypted(session_pin); ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
CBOR_ERROR(ret); CBOR_ERROR(ret);
} }
@@ -694,8 +700,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
mbedtls_platform_zeroize(pin_data, sizeof(pin_data)); mbedtls_platform_zeroize(pin_data, sizeof(pin_data));
flash_commit(); low_flash_available();
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) { if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "fido.h" #include "fido.h"
#include "ctap.h" #include "ctap.h"
@@ -31,6 +31,9 @@
extern uint8_t keydev_dec[32]; extern uint8_t keydev_dec[32];
extern bool has_keydev_dec; extern bool has_keydev_dec;
extern void resetPersistentPinUvAuthToken();
extern void resetPinUvAuthToken();
int cbor_config(const uint8_t *data, size_t len) { int cbor_config(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
@@ -151,7 +154,7 @@ int cbor_config(const uint8_t *data, size_t len) {
file_put_data(ef_keydev, keydev_dec, sizeof(keydev_dec)); file_put_data(ef_keydev, keydev_dec, sizeof(keydev_dec));
mbedtls_platform_zeroize(keydev_dec, sizeof(keydev_dec)); mbedtls_platform_zeroize(keydev_dec, sizeof(keydev_dec));
file_put_data(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes file_put_data(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes
flash_commit(); low_flash_available();
} }
else if (vendorCommandId == CTAP_CONFIG_AUT_ENABLE) { else if (vendorCommandId == CTAP_CONFIG_AUT_ENABLE) {
if (!file_has_data(ef_keydev)) { if (!file_has_data(ef_keydev)) {
@@ -168,7 +171,7 @@ int cbor_config(const uint8_t *data, size_t len) {
} }
uint8_t key_dev_enc[12 + 32 + 16]; uint8_t key_dev_enc[12 + 32 + 16];
random_fill_buffer(key_dev_enc, 12); random_gen(NULL, key_dev_enc, 12);
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorParamByteString.data); mbedtls_chachapoly_setkey(&chatx, vendorParamByteString.data);
ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, file_get_size(ef_keydev), key_dev_enc, NULL, 0, file_get_data(ef_keydev), key_dev_enc + 12, key_dev_enc + 12 + file_get_size(ef_keydev)); ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, file_get_size(ef_keydev), key_dev_enc, NULL, 0, file_get_data(ef_keydev), key_dev_enc + 12, key_dev_enc + 12 + file_get_size(ef_keydev));
@@ -181,17 +184,17 @@ int cbor_config(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(key_dev_enc, sizeof(key_dev_enc)); mbedtls_platform_zeroize(key_dev_enc, sizeof(key_dev_enc));
file_put_data(ef_keydev, key_dev_enc, file_get_size(ef_keydev)); // Overwrite ef with 0 file_put_data(ef_keydev, key_dev_enc, file_get_size(ef_keydev)); // Overwrite ef with 0
file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
flash_commit(); low_flash_available();
} }
else if (vendorCommandId == CTAP_CONFIG_EA_UPLOAD) { else if (vendorCommandId == CTAP_CONFIG_EA_UPLOAD) {
if (vendorParamByteString.present == false) { if (vendorParamByteString.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
} }
file_t *ef_ee_ea = file_search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF); file_t *ef_ee_ea = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
if (ef_ee_ea) { if (ef_ee_ea) {
file_put_data(ef_ee_ea, vendorParamByteString.data, (uint16_t)vendorParamByteString.len); file_put_data(ef_ee_ea, vendorParamByteString.data, (uint16_t)vendorParamByteString.len);
} }
flash_commit(); low_flash_available();
} }
else if (vendorCommandId == CTAP_CONFIG_PIN_POLICY) { else if (vendorCommandId == CTAP_CONFIG_PIN_POLICY) {
file_t *ef_pin_policy = file_new(EF_PIN_COMPLEXITY_POLICY); file_t *ef_pin_policy = file_new(EF_PIN_COMPLEXITY_POLICY);
@@ -206,7 +209,7 @@ int cbor_config(const uint8_t *data, size_t len) {
free(val); free(val);
} }
} }
flash_commit(); low_flash_available();
} }
else { else {
CBOR_ERROR(CTAP2_ERR_INVALID_SUBCOMMAND); CBOR_ERROR(CTAP2_ERR_INVALID_SUBCOMMAND);
@@ -215,7 +218,7 @@ int cbor_config(const uint8_t *data, size_t len) {
} }
else if (subcommand == 0x03) { else if (subcommand == 0x03) {
uint8_t currentMinPinLen = 4; uint8_t currentMinPinLen = 4;
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) { if (file_has_data(ef_minpin)) {
currentMinPinLen = *file_get_data(ef_minpin); currentMinPinLen = *file_get_data(ef_minpin);
} }
@@ -242,7 +245,7 @@ int cbor_config(const uint8_t *data, size_t len) {
mbedtls_sha256((uint8_t *) minPinLengthRPIDs[m].data, minPinLengthRPIDs[m].len, dataf + 2 + m * 32, 0); mbedtls_sha256((uint8_t *) minPinLengthRPIDs[m].data, minPinLengthRPIDs[m].len, dataf + 2 + m * 32, 0);
} }
file_put_data(ef_minpin, dataf, (uint16_t)(2 + minPinLengthRPIDs_len * 32)); file_put_data(ef_minpin, dataf, (uint16_t)(2 + minPinLengthRPIDs_len * 32));
flash_commit(); low_flash_available();
free(dataf); free(dataf);
goto err; //No return goto err; //No return
} }

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "ctap.h" #include "ctap.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
@@ -137,7 +137,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
} }
uint8_t existing = 0; uint8_t existing = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
if (file_has_data(file_search((uint16_t)(EF_CRED + i)))) { if (file_has_data(search_dynamic_file((uint16_t)(EF_CRED + i)))) {
existing++; existing++;
} }
} }
@@ -173,7 +173,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
} }
uint8_t skip = 0; uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = file_search((uint16_t)(EF_RP + i)); file_t *tef = search_dynamic_file((uint16_t)(EF_RP + i));
if (file_has_data(tef) && *file_get_data(tef) > 0) { if (file_has_data(tef) && *file_get_data(tef) > 0) {
if (++skip == rp_counter) { if (++skip == rp_counter) {
if (rp_ef == NULL) { if (rp_ef == NULL) {
@@ -239,7 +239,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
file_t *cred_ef = NULL; file_t *cred_ef = NULL;
uint8_t skip = 0; uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = file_search((uint16_t)(EF_CRED + i)); file_t *tef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (file_has_data(tef) && memcmp(file_get_data(tef), rpIdHash.data, 32) == 0) { if (file_has_data(tef) && memcmp(file_get_data(tef), rpIdHash.data, 32) == 0) {
if (++skip == cred_counter) { if (++skip == cred_counter) {
if (cred_ef == NULL) { if (cred_ef == NULL) {
@@ -373,20 +373,20 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = file_search((uint16_t)(EF_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, CRED_RESIDENT_LEN) == 0) { if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, CRED_RESIDENT_LEN) == 0) {
uint8_t *rp_id_hash = file_get_data(ef); uint8_t *rp_id_hash = file_get_data(ef);
if (file_delete(ef) != 0) { if (delete_file(ef) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
} }
for (int j = 0; j < MAX_RESIDENT_CREDENTIALS; j++) { for (int j = 0; j < MAX_RESIDENT_CREDENTIALS; j++) {
file_t *rp_ef = file_search((uint16_t)(EF_RP + j)); file_t *rp_ef = search_dynamic_file((uint16_t)(EF_RP + j));
if (file_has_data(rp_ef) && memcmp(file_get_data(rp_ef) + 1, rp_id_hash, 32) == 0) { if (file_has_data(rp_ef) && memcmp(file_get_data(rp_ef) + 1, rp_id_hash, 32) == 0) {
uint8_t *rp_data = (uint8_t *) calloc(1, file_get_size(rp_ef)); uint8_t *rp_data = (uint8_t *) calloc(1, file_get_size(rp_ef));
memcpy(rp_data, file_get_data(rp_ef), file_get_size(rp_ef)); memcpy(rp_data, file_get_data(rp_ef), file_get_size(rp_ef));
rp_data[0] -= 1; rp_data[0] -= 1;
if (rp_data[0] == 0) { if (rp_data[0] == 0) {
file_delete(rp_ef); delete_file(rp_ef);
} }
else { else {
file_put_data(rp_ef, rp_data, file_get_size(rp_ef)); file_put_data(rp_ef, rp_data, file_get_size(rp_ef));
@@ -395,7 +395,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
break; break;
} }
} }
flash_commit(); low_flash_available();
goto err; //no error goto err; //no error
} }
} }
@@ -415,7 +415,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = file_search((uint16_t)(EF_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, CRED_RESIDENT_LEN) == 0) { if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, CRED_RESIDENT_LEN) == 0) {
Credential cred = { 0 }; Credential cred = { 0 };
uint8_t *rp_id_hash = file_get_data(ef); uint8_t *rp_id_hash = file_get_data(ef);
@@ -439,7 +439,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
if (credential_store(newcred, newcred_len, rp_id_hash) != 0) { if (credential_store(newcred, newcred_len, rp_id_hash) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
} }
flash_commit(); low_flash_available();
goto err; //no error goto err; //no error
} }
} }

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#if defined(PICO_PLATFORM) #if defined(PICO_PLATFORM)
@@ -32,7 +32,6 @@
#include "random.h" #include "random.h"
int cbor_get_assertion(const uint8_t *data, size_t len, bool next); int cbor_get_assertion(const uint8_t *data, size_t len, bool next);
extern char *rp_id, *user_name, *display_name;
bool residentx = false; bool residentx = false;
Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 }; Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
@@ -43,7 +42,7 @@ uint32_t timerx = 0;
uint8_t *datax = NULL; uint8_t *datax = NULL;
size_t lenx = 0; size_t lenx = 0;
void reset_gna_state(void) { void reset_gna_state() {
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credential_free(&credsx[i]); credential_free(&credsx[i]);
} }
@@ -206,9 +205,6 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (rpId.present == false || clientDataHash.present == false) { if (rpId.present == false || clientDataHash.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
} }
rp_id = rpId.data;
user_name = NULL;
display_name = NULL;
uint8_t flags = 0; uint8_t flags = 0;
uint8_t rp_id_hash[32] = {0}; uint8_t rp_id_hash[32] = {0};
@@ -305,7 +301,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
if (credential_is_resident(allowList[e].id.data, allowList[e].id.len)) { if (credential_is_resident(allowList[e].id.data, allowList[e].id.len)) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = file_search((uint16_t)(EF_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) { if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue; continue;
} }
@@ -332,7 +328,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
// Even we provide allowList, we need to check if the credential is resident // Even we provide allowList, we need to check if the credential is resident
if (!resident) { if (!resident) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = file_search((uint16_t)(EF_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) { if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue; continue;
} }
@@ -351,7 +347,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
else { else {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = file_search((uint16_t)(EF_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) { if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue; continue;
} }
@@ -405,7 +401,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
if (credential_is_resident(allowList[e].id.data, allowList[e].id.len)) { if (credential_is_resident(allowList[e].id.data, allowList[e].id.len)) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = file_search((uint16_t)(EF_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) { if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue; continue;
} }
@@ -615,7 +611,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
uint8_t *pa = aut_data; uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32; memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags; *pa++ = flags;
pa += put_uint32_be(ctr, pa); pa += put_uint32_t_be(ctr, pa);
memcpy(pa, ext, ext_len); pa += ext_len; memcpy(pa, ext, ext_len); pa += ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) { if ((size_t)(pa - aut_data) != aut_data_len) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
@@ -648,11 +644,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
#endif #endif
if (md != NULL) { if (md != NULL) {
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash); ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_fill_iterator, NULL); ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
} }
#ifdef MBEDTLS_EDDSA_C #ifdef MBEDTLS_EDDSA_C
else { else {
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_fill_iterator, NULL); ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL);
} }
#endif #endif
} }
@@ -743,7 +739,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
ctr++; ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr)); file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
flash_commit(); low_flash_available();
err: err:
CBOR_FREE_BYTE_STRING(clientDataHash); CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "fido.h" #include "fido.h"
@@ -24,7 +24,7 @@
#include "apdu.h" #include "apdu.h"
#include "version.h" #include "version.h"
int cbor_get_info(void) { int cbor_get_info() {
CborEncoder encoder, mapEncoder, arrayEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, arrayEncoder, mapEncoder2;
CborError error = CborNoError; CborError error = CborNoError;
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
@@ -36,7 +36,7 @@ int cbor_get_info(void) {
#else #else
lfields++; lfields++;
#endif #endif
file_t *ef_pin_policy = file_search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF); file_t *ef_pin_policy = search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF);
if (file_has_data(ef_pin_policy)) { if (file_has_data(ef_pin_policy)) {
lfields += 2; lfields += 2;
} }
@@ -144,7 +144,7 @@ int cbor_get_info(void) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_LARGE_BLOB_SIZE)); // maxSerializedLargeBlobArray CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_LARGE_BLOB_SIZE)); // maxSerializedLargeBlobArray
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C));
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) { if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "fido.h" #include "fido.h"
#include "ctap.h" #include "ctap.h"
@@ -129,7 +129,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
uint8_t verify_data[70] = { 0 }; uint8_t verify_data[70] = { 0 };
memset(verify_data, 0xff, 32); memset(verify_data, 0xff, 32);
verify_data[32] = 0x0C; verify_data[32] = 0x0C;
put_uint32_le((uint32_t)offset, verify_data + 34); put_uint32_t_le((uint32_t)offset, verify_data + 34);
mbedtls_sha256(set.data, set.len, verify_data + 38, 0); mbedtls_sha256(set.data, set.len, verify_data + 38, 0);
if (verify((uint8_t)pinUvAuthProtocol, paut.data, verify_data, (uint16_t)sizeof(verify_data), pinUvAuthParam.data) != 0) { if (verify((uint8_t)pinUvAuthProtocol, paut.data, verify_data, (uint16_t)sizeof(verify_data), pinUvAuthParam.data) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -152,7 +152,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE); CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE);
} }
file_put_data(ef_largeblob, temp_lba, (uint16_t)expectedLength); file_put_data(ef_largeblob, temp_lba, (uint16_t)expectedLength);
flash_commit(); low_flash_available();
} }
goto err; goto err;
} }

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "cbor_make_credential.h" #include "cbor_make_credential.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
@@ -28,8 +28,6 @@
#include "random.h" #include "random.h"
#include "crypto_utils.h" #include "crypto_utils.h"
char *rp_id = NULL, *user_name = NULL, *display_name = NULL;
int cbor_make_credential(const uint8_t *data, size_t len) { int cbor_make_credential(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
@@ -194,9 +192,6 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
} }
CBOR_PARSE_MAP_END(map, 1); CBOR_PARSE_MAP_END(map, 1);
rp_id = rp.id.data;
user_name = user.parent.name.data;
display_name = user.displayName.data;
uint8_t flags = FIDO2_AUT_FLAG_AT; uint8_t flags = FIDO2_AUT_FLAG_AT;
uint8_t rp_id_hash[32] = {0}; uint8_t rp_id_hash[32] = {0};
@@ -357,7 +352,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
Credential ecred = {0}; Credential ecred = {0};
if (credential_is_resident(excludeList[e].id.data, excludeList[e].id.len)) { if (credential_is_resident(excludeList[e].id.data, excludeList[e].id.len)) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef_cred = file_search((uint16_t)(EF_CRED + i)); file_t *ef_cred = search_dynamic_file((uint16_t)(EF_CRED + i));
if (!file_has_data(ef_cred) || memcmp(file_get_data(ef_cred), rp_id_hash, 32) != 0) { if (!file_has_data(ef_cred) || memcmp(file_get_data(ef_cred), rp_id_hash, 32) != 0) {
continue; continue;
} }
@@ -428,7 +423,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
l++; l++;
} }
if (extensions.minPinLength == ptrue) { if (extensions.minPinLength == ptrue) {
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) { if (file_has_data(ef_minpin)) {
uint8_t *minpin_data = file_get_data(ef_minpin); uint8_t *minpin_data = file_get_data(ef_minpin);
for (int o = 2; o < file_get_size(ef_minpin); o += 32) { for (int o = 2; o < file_get_size(ef_minpin); o += 32) {
@@ -522,7 +517,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
if (pin_complexity_policy == ptrue) { if (pin_complexity_policy == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "pinComplexityPolicy")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "pinComplexityPolicy"));
file_t *ef_pin_complexity_policy = file_search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF); file_t *ef_pin_complexity_policy = search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF);
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, file_has_data(ef_pin_complexity_policy))); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, file_has_data(ef_pin_complexity_policy)));
} }
@@ -555,16 +550,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
uint8_t *pa = aut_data; uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32; memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags; *pa++ = flags;
pa += put_uint32_be(ctr, pa); pa += put_uint32_t_be(ctr, pa);
memcpy(pa, aaguid, 16); pa += 16; memcpy(pa, aaguid, 16); pa += 16;
if (options.rk == ptrue) { if (options.rk == ptrue) {
uint8_t cred_idr[CRED_RESIDENT_LEN] = {0}; uint8_t cred_idr[CRED_RESIDENT_LEN] = {0};
pa += put_uint16_be(sizeof(cred_idr), pa); pa += put_uint16_t_be(sizeof(cred_idr), pa);
credential_derive_resident(cred_id, cred_id_len, cred_idr); credential_derive_resident(cred_id, cred_id_len, cred_idr);
memcpy(pa, cred_idr, sizeof(cred_idr)); pa += sizeof(cred_idr); memcpy(pa, cred_idr, sizeof(cred_idr)); pa += sizeof(cred_idr);
} }
else { else {
pa += put_uint16_be(cred_id_len, pa); pa += put_uint16_t_be(cred_id_len, pa);
memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len; memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len;
} }
memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs; memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
@@ -606,11 +601,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
self_attestation = false; self_attestation = false;
} }
if (md != NULL) { if (md != NULL) {
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_fill_iterator, NULL); ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
} }
#ifdef MBEDTLS_EDDSA_C #ifdef MBEDTLS_EDDSA_C
else { else {
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_fill_iterator, NULL); ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL);
} }
#endif #endif
mbedtls_ecp_keypair_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
@@ -651,7 +646,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CborEncoder arrEncoder; CborEncoder arrEncoder;
file_t *ef_cert = NULL; file_t *ef_cert = NULL;
if (enterpriseAttestation == 2) { if (enterpriseAttestation == 2) {
ef_cert = file_search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF); ef_cert = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
} }
if (!file_has_data(ef_cert)) { if (!file_has_data(ef_cert)) {
ef_cert = ef_certdev; ef_cert = ef_certdev;
@@ -683,7 +678,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
ctr++; ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr)); file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
flash_commit(); low_flash_available();
err: err:
CBOR_FREE_BYTE_STRING(clientDataHash); CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);

View File

@@ -15,10 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "file.h" #include "file.h"
#include "fido.h" #include "fido.h"
#include "ctap2_cbor.h"
#include "ctap.h" #include "ctap.h"
#if defined(PICO_PLATFORM) #if defined(PICO_PLATFORM)
#include "bsp/board.h" #include "bsp/board.h"
@@ -28,18 +27,20 @@
#endif #endif
#include "fs/phy.h" #include "fs/phy.h"
int cbor_reset(void) { extern void scan_all();
int cbor_reset() {
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET == 1 #if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET == 1
if (!(phy_data.opts & PHY_OPT_DISABLE_POWER_RESET) && board_millis() > 10000) { if (!(phy_data.opts & PHY_OPT_DISABLE_POWER_RESET) && board_millis() > 10000) {
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
#endif #endif
if (wait_button_pressed() > 0) { if (wait_button_pressed() == true) {
return CTAP2_ERR_USER_ACTION_TIMEOUT; return CTAP2_ERR_USER_ACTION_TIMEOUT;
} }
#endif #endif
file_initialize_flash(true); initialize_flash(true);
init_fido(); init_fido();
return 0; return 0;
} }

View File

@@ -15,21 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "ctap2_cbor.h"
#include "ctap.h" #include "ctap.h"
extern char *rp_id, *user_name, *display_name; int cbor_selection() {
if (wait_button_pressed() == true) {
int cbor_selection(void) {
rp_id = user_name = display_name = NULL;
int ret = wait_button_pressed() ;
if (ret == 1) {
return CTAP2_ERR_USER_ACTION_TIMEOUT; return CTAP2_ERR_USER_ACTION_TIMEOUT;
} }
else if (ret == 2) {
return CTAP2_ERR_OPERATION_DENIED;
}
return CTAP2_OK; return CTAP2_OK;
} }

View File

@@ -15,8 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "serial.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "fido.h" #include "fido.h"
#include "ctap.h" #include "ctap.h"
@@ -43,7 +42,7 @@ int mse_decrypt_ct(uint8_t *data, size_t len) {
return ret; return ret;
} }
static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
@@ -117,7 +116,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
file_put_data(ef_keydev_enc, vendorParam.data, (uint16_t)vendorParam.len); file_put_data(ef_keydev_enc, vendorParam.data, (uint16_t)vendorParam.len);
file_put_data(ef_keydev, zeros, file_get_size(ef_keydev)); // Overwrite ef with 0 file_put_data(ef_keydev, zeros, file_get_size(ef_keydev)); // Overwrite ef with 0
file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
flash_commit(); low_flash_available();
goto err; goto err;
} }
else { else {
@@ -133,7 +132,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdh_context hkey; mbedtls_ecdh_context hkey;
mbedtls_ecdh_init(&hkey); mbedtls_ecdh_init(&hkey);
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1); mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_fill_iterator, NULL); int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1); mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -155,7 +154,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_fill_iterator, NULL); ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
mbedtls_platform_zeroize(buf, sizeof(buf)); mbedtls_platform_zeroize(buf, sizeof(buf));
@@ -217,7 +216,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
ret = mbedtls_ecp_keypair_calc_public(&ekey, random_fill_iterator, NULL); ret = mbedtls_ecp_mul(&ekey.grp, &ekey.Q, &ekey.d, &ekey.grp.G, random_gen, NULL);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
@@ -233,7 +232,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_x509write_csr_set_key(&ctx, &key); mbedtls_x509write_csr_set_key(&ctx, &key);
mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256); mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256);
mbedtls_x509write_csr_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04", 0xB, 0, aaguid, sizeof(aaguid)); mbedtls_x509write_csr_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04", 0xB, 0, aaguid, sizeof(aaguid));
ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_fill_iterator, NULL); ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_gen, NULL);
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
if (ret <= 0) { if (ret <= 0) {
mbedtls_x509write_csr_free(&ctx); mbedtls_x509write_csr_free(&ctx);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
@@ -23,10 +23,10 @@
#include "files.h" #include "files.h"
#include "credential.h" #include "credential.h"
int cmd_authenticate(void) { int cmd_authenticate() {
CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *) apdu.data; CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *) apdu.data;
CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *) res_APDU; CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *) res_APDU;
//if (scan_files_fido(true) != PICOKEYS_OK) //if (scan_files_fido(true) != PICOKEY_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
if (apdu.nc < CTAP_CHAL_SIZE + CTAP_APPID_SIZE + 1 + 1) { if (apdu.nc < CTAP_CHAL_SIZE + CTAP_APPID_SIZE + 1 + 1) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
@@ -34,7 +34,7 @@ int cmd_authenticate(void) {
if (req->keyHandleLen < KEY_HANDLE_LEN) { if (req->keyHandleLen < KEY_HANDLE_LEN) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (P1(apdu) == CTAP_AUTH_ENFORCE && wait_button_pressed() > 0) { if (P1(apdu) == CTAP_AUTH_ENFORCE && wait_button_pressed() == true) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
@@ -55,7 +55,7 @@ int cmd_authenticate(void) {
} }
} }
free(tmp_kh); free(tmp_kh);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
mbedtls_ecp_keypair_free(&key); mbedtls_ecp_keypair_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -66,7 +66,7 @@ int cmd_authenticate(void) {
resp->flags = 0; resp->flags = 0;
resp->flags |= P1(apdu) == CTAP_AUTH_ENFORCE ? CTAP_AUTH_FLAG_TUP : 0x0; resp->flags |= P1(apdu) == CTAP_AUTH_ENFORCE ? CTAP_AUTH_FLAG_TUP : 0x0;
uint32_t ctr = get_sign_counter(); uint32_t ctr = get_sign_counter();
put_uint32_be(ctr, resp->ctr); put_uint32_t_be(ctr, resp->ctr);
uint8_t hash[32], sig_base[CTAP_APPID_SIZE + 1 + 4 + CTAP_CHAL_SIZE]; uint8_t hash[32], sig_base[CTAP_APPID_SIZE + 1 + 4 + CTAP_CHAL_SIZE];
memcpy(sig_base, req->appId, CTAP_APPID_SIZE); memcpy(sig_base, req->appId, CTAP_APPID_SIZE);
memcpy(sig_base + CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t)); memcpy(sig_base + CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t));
@@ -78,7 +78,7 @@ int cmd_authenticate(void) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&key, MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->sig, CTAP_MAX_EC_SIG_SIZE, &olen, random_fill_iterator, NULL); ret = mbedtls_ecdsa_write_signature(&key, MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->sig, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
mbedtls_ecp_keypair_free(&key); mbedtls_ecp_keypair_free(&key);
if (ret != 0) { if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -87,6 +87,6 @@ int cmd_authenticate(void) {
ctr++; ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr)); file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
flash_commit(); low_flash_available();
return SW_OK(); return SW_OK();
} }

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
@@ -29,41 +29,42 @@ const uint8_t u2f_aid[] = {
0xA0, 0x00, 0x00, 0x05, 0x27, 0x10, 0x02 0xA0, 0x00, 0x00, 0x05, 0x27, 0x10, 0x02
}; };
static int u2f_unload(void); int u2f_unload();
static int u2f_process_apdu(void); int u2f_process_apdu();
static int u2f_select(app_t *a, uint8_t force) { int u2f_select(app_t *a, uint8_t force) {
(void) force; (void) force;
if (cap_supported(CAP_U2F)) { if (cap_supported(CAP_U2F)) {
a->process_apdu = u2f_process_apdu; a->process_apdu = u2f_process_apdu;
a->unload = u2f_unload; a->unload = u2f_unload;
return PICOKEYS_OK; return PICOKEY_OK;
} }
return PICOKEYS_ERR_FILE_NOT_FOUND; return PICOKEY_ERR_FILE_NOT_FOUND;
} }
INITIALIZER ( u2f_ctor ) { INITIALIZER ( u2f_ctor ) {
register_app(u2f_select, u2f_aid); register_app(u2f_select, u2f_aid);
} }
int u2f_unload(void) { int u2f_unload() {
return PICOKEYS_OK; return PICOKEY_OK;
} }
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_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"; const uint8_t *bogus_chrome = (const uint8_t *) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
int cmd_register(void) { extern int ctap_error(uint8_t error);
int cmd_register() {
CTAP_REGISTER_REQ *req = (CTAP_REGISTER_REQ *) apdu.data; CTAP_REGISTER_REQ *req = (CTAP_REGISTER_REQ *) apdu.data;
CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *) res_APDU; CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *) res_APDU;
resp->registerId = CTAP_REGISTER_ID; resp->registerId = CTAP_REGISTER_ID;
resp->keyHandleLen = KEY_HANDLE_LEN; resp->keyHandleLen = KEY_HANDLE_LEN;
//if (scan_files_fido(true) != PICOKEYS_OK) //if (scan_files_fido(true) != PICOKEY_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) { if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
if (wait_button_pressed() > 0) { if (wait_button_pressed() == true) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
if (memcmp(req->appId, bogus_firefox, if (memcmp(req->appId, bogus_firefox,
@@ -72,7 +73,7 @@ int cmd_register(void) {
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
int ret = derive_key(req->appId, true, resp->keyHandleCertSig, MBEDTLS_ECP_DP_SECP256R1, &key); int ret = derive_key(req->appId, true, resp->keyHandleCertSig, MBEDTLS_ECP_DP_SECP256R1, &key);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -97,16 +98,16 @@ int cmd_register(void) {
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
uint8_t key_dev[32] = {0}; uint8_t key_dev[32] = {0};
ret = load_keydev(key_dev); ret = load_keydev(key_dev);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, key_dev, 32); ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, key_dev, 32);
mbedtls_platform_zeroize(key_dev, sizeof(key_dev)); mbedtls_platform_zeroize(key_dev, sizeof(key_dev));
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
ret = mbedtls_ecdsa_write_signature(&key,MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->keyHandleCertSig + KEY_HANDLE_LEN + ef_certdev_size, CTAP_MAX_EC_SIG_SIZE, &olen, random_fill_iterator, NULL); ret = mbedtls_ecdsa_write_signature(&key,MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->keyHandleCertSig + KEY_HANDLE_LEN + ef_certdev_size, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
if (ret != 0) { if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -115,6 +116,10 @@ int cmd_register(void) {
return SW_OK(); return SW_OK();
} }
extern int cmd_register();
extern int cmd_authenticate();
extern int cmd_version();
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ CTAP_REGISTER, cmd_register }, { CTAP_REGISTER, cmd_register },
{ CTAP_AUTHENTICATE, cmd_authenticate }, { CTAP_AUTHENTICATE, cmd_authenticate },
@@ -122,7 +127,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int u2f_process_apdu(void) { int u2f_process_apdu() {
if (CLA(apdu) != 0x00) { if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -16,10 +16,9 @@
*/ */
#include "apdu.h" #include "apdu.h"
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h"
int cmd_version(void) { int cmd_version() {
memcpy(res_APDU, "U2F_V2", strlen("U2F_V2")); memcpy(res_APDU, "U2F_V2", strlen("U2F_V2"));
res_APDU_size = (uint16_t)strlen("U2F_V2"); res_APDU_size = (uint16_t)strlen("U2F_V2");
return SW_OK(); return SW_OK();

View File

@@ -15,9 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "serial.h"
#include "pico_time.h"
#include "mbedtls/chachapoly.h" #include "mbedtls/chachapoly.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "credential.h" #include "credential.h"
@@ -31,6 +29,7 @@
#include "files.h" #include "files.h"
#include "otp.h" #include "otp.h"
extern bool has_set_rtc();
int credential_derive_chacha_key(uint8_t *outk, const uint8_t *); int credential_derive_chacha_key(uint8_t *outk, const uint8_t *);
static int credential_silent_tag(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, uint8_t *outk) { static int credential_silent_tag(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, uint8_t *outk) {
@@ -160,7 +159,7 @@ int credential_create(CborCharString *rpId,
uint8_t key[32] = {0}; uint8_t key[32] = {0};
credential_derive_chacha_key(key, (const uint8_t *)CRED_PROTO); credential_derive_chacha_key(key, (const uint8_t *)CRED_PROTO);
uint8_t iv[CRED_IV_LEN] = {0}; uint8_t iv[CRED_IV_LEN] = {0};
random_fill_buffer(iv, sizeof(iv)); random_gen(NULL, iv, sizeof(iv));
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key); mbedtls_chachapoly_setkey(&chatx, key);
@@ -312,7 +311,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
return ret; return ret;
} }
for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = file_search(EF_CRED + i); file_t *ef = search_dynamic_file(EF_CRED + i);
Credential rcred = { 0 }; Credential rcred = { 0 };
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
if (sloti == -1) { if (sloti == -1) {
@@ -352,7 +351,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
if (new_record == true) { //increase rps if (new_record == true) { //increase rps
sloti = -1; sloti = -1;
for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
ef = file_search(EF_RP + i); ef = search_dynamic_file(EF_RP + i);
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
if (sloti == -1) { if (sloti == -1) {
sloti = i; sloti = i;
@@ -367,7 +366,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
if (sloti == -1) { if (sloti == -1) {
return -1; return -1;
} }
ef = file_search((uint16_t)(EF_RP + sloti)); ef = search_dynamic_file((uint16_t)(EF_RP + sloti));
if (file_has_data(ef)) { if (file_has_data(ef)) {
data = (uint8_t *) calloc(1, file_get_size(ef)); data = (uint8_t *) calloc(1, file_get_size(ef));
memcpy(data, file_get_data(ef), file_get_size(ef)); memcpy(data, file_get_data(ef), file_get_size(ef));
@@ -386,7 +385,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
} }
} }
credential_free(&cred); credential_free(&cred);
flash_commit(); low_flash_available();
return 0; return 0;
} }

View File

@@ -129,7 +129,8 @@ typedef struct {
#define CTAP_VENDOR_MSE 0x02 #define CTAP_VENDOR_MSE 0x02
#define CTAP_VENDOR_UNLOCK 0x03 #define CTAP_VENDOR_UNLOCK 0x03
#define CTAP_VENDOR_EA 0x04 #define CTAP_VENDOR_EA 0x04
#define CTAP_VENDOR_ADMIN_PIN 0x08 #define CTAP_VENDOR_PHY_OPTS 0x05
#define CTAP_VENDOR_MEMORY 0x06
#define CTAP_PERMISSION_MC 0x01 // MakeCredential #define CTAP_PERMISSION_MC 0x01 // MakeCredential
#define CTAP_PERMISSION_GA 0x02 // GetAssertion #define CTAP_PERMISSION_GA 0x02 // GetAssertion

View File

@@ -19,23 +19,16 @@
#define _CTAP2_CBOR_H_ #define _CTAP2_CBOR_H_
#include "cbor.h" #include "cbor.h"
#ifndef ESP_PLATFORM
#include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecp.h" #include "mbedtls/ecp.h"
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
extern uint8_t *driver_prepare_response(void); extern uint8_t *driver_prepare_response();
extern void driver_exec_finished(size_t size_next); extern void driver_exec_finished(size_t size_next);
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
extern int cbor_get_info(void);
extern int cbor_reset(void);
extern int cbor_make_credential(const uint8_t *data, size_t len);
extern int cbor_client_pin(const uint8_t *data, size_t len);
extern int cbor_selection(void);
extern int cbor_get_next_assertion(const uint8_t *data, size_t len);
extern int cbor_cred_mgmt(const uint8_t *data, size_t len);
extern int cbor_config(const uint8_t *data, size_t len);
extern int cbor_large_blobs(const uint8_t *data, size_t len);
extern int cbor_vendor(const uint8_t *data, size_t len);
extern void reset_gna_state(void);
extern int cbor_process(uint8_t, const uint8_t *data, size_t len); extern int cbor_process(uint8_t, const uint8_t *data, size_t len);
extern const uint8_t aaguid[16]; extern const uint8_t aaguid[16];

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "version.h" #include "version.h"

View File

@@ -15,9 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "serial.h" #include "kek.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
#include "files.h" #include "files.h"
@@ -34,12 +34,12 @@
#include <math.h> #include <math.h>
#include "management.h" #include "management.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "ctap2_cbor.h"
#include "version.h" #include "version.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "otp.h" #include "otp.h"
static int fido_unload(void); int fido_process_apdu();
int fido_unload();
pinUvAuthToken_t paut = { 0 }; pinUvAuthToken_t paut = { 0 };
persistentPinUvAuthToken_t ppaut = { 0 }; persistentPinUvAuthToken_t ppaut = { 0 };
@@ -64,25 +64,25 @@ const uint8_t atr_fido[] = {
0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40 0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40
}; };
static uint8_t fido_get_version_major(void) { uint8_t fido_get_version_major() {
return PICO_FIDO_VERSION_MAJOR; return PICO_FIDO_VERSION_MAJOR;
} }
static uint8_t fido_get_version_minor(void) { uint8_t fido_get_version_minor() {
return PICO_FIDO_VERSION_MINOR; return PICO_FIDO_VERSION_MINOR;
} }
static int fido_select(app_t *a, uint8_t force) { int fido_select(app_t *a, uint8_t force) {
(void) force; (void) force;
if (cap_supported(CAP_FIDO2)) { if (cap_supported(CAP_FIDO2)) {
a->process_apdu = fido_process_apdu; a->process_apdu = fido_process_apdu;
a->unload = fido_unload; a->unload = fido_unload;
return PICOKEYS_OK; return PICOKEY_OK;
} }
return PICOKEYS_ERR_FILE_NOT_FOUND; return PICOKEY_ERR_FILE_NOT_FOUND;
} }
extern uint8_t (*get_version_major)(void); extern uint8_t (*get_version_major)();
extern uint8_t (*get_version_minor)(void); extern uint8_t (*get_version_minor)();
INITIALIZER ( fido_ctor ) { INITIALIZER ( fido_ctor ) {
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) #if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
@@ -94,8 +94,8 @@ INITIALIZER ( fido_ctor ) {
register_app(fido_select, fido_aid_backup); register_app(fido_select, fido_aid_backup);
} }
static int fido_unload(void) { int fido_unload() {
return PICOKEYS_OK; return PICOKEY_OK;
} }
mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) { mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
@@ -150,7 +150,7 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
return FIDO2_CURVE_P256K1; return FIDO2_CURVE_P256K1;
} }
else if (id == MBEDTLS_ECP_DP_CURVE25519) { else if (id == MBEDTLS_ECP_DP_CURVE25519) {
return FIDO2_CURVE_X25519; return MBEDTLS_ECP_DP_CURVE25519;
} }
else if (id == MBEDTLS_ECP_DP_CURVE448) { else if (id == MBEDTLS_ECP_DP_CURVE448) {
return FIDO2_CURVE_X448; return FIDO2_CURVE_X448;
@@ -173,18 +173,14 @@ int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key) {
} }
uint8_t key_path[KEY_PATH_LEN]; uint8_t key_path[KEY_PATH_LEN];
memcpy(key_path, cred_id, KEY_PATH_LEN); memcpy(key_path, cred_id, KEY_PATH_LEN);
uint32_t key_path_first = 0x80000000u | 10022u; *(uint32_t *) key_path = 0x80000000 | 10022;
memcpy(key_path, &key_path_first, sizeof(key_path_first));
for (size_t i = 1; i < KEY_PATH_ENTRIES; i++) { for (size_t i = 1; i < KEY_PATH_ENTRIES; i++) {
uint32_t part = 0; *(uint32_t *) (key_path + i * sizeof(uint32_t)) |= 0x80000000;
memcpy(&part, key_path + i * sizeof(uint32_t), sizeof(part));
part |= 0x80000000u;
memcpy(key_path + i * sizeof(uint32_t), &part, sizeof(part));
} }
return derive_key(NULL, false, key_path, mbedtls_curve, key); return derive_key(NULL, false, key_path, mbedtls_curve, key);
} }
static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffer_size) { int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffer_size) {
mbedtls_x509write_cert ctx; mbedtls_x509write_cert ctx;
mbedtls_x509write_crt_init(&ctx); mbedtls_x509write_crt_init(&ctx);
mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3); mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3);
@@ -192,7 +188,7 @@ static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO"); mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
mbedtls_x509write_crt_set_subject_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO"); mbedtls_x509write_crt_set_subject_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
uint8_t serial[16]; uint8_t serial[16];
random_fill_buffer(serial, sizeof(serial)); random_gen(NULL, serial, sizeof(serial));
mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial)); mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial));
mbedtls_pk_context key; mbedtls_pk_context key;
mbedtls_pk_init(&key); mbedtls_pk_init(&key);
@@ -207,7 +203,7 @@ static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_
mbedtls_x509write_crt_set_key_usage(&ctx, mbedtls_x509write_crt_set_key_usage(&ctx,
MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
MBEDTLS_X509_KU_KEY_CERT_SIGN); MBEDTLS_X509_KU_KEY_CERT_SIGN);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_fill_iterator, NULL); int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL);
mbedtls_x509write_crt_free(&ctx); mbedtls_x509write_crt_free(&ctx);
/* pk cannot be freed, as it is freed later */ /* pk cannot be freed, as it is freed later */
//mbedtls_pk_free(&key); //mbedtls_pk_free(&key);
@@ -216,7 +212,7 @@ static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_
int load_keydev(uint8_t key[32]) { int load_keydev(uint8_t key[32]) {
if (has_keydev_dec == false && !file_has_data(ef_keydev)) { if (has_keydev_dec == false && !file_has_data(ef_keydev)) {
return PICOKEYS_ERR_MEMORY_FATAL; return PICOKEY_ERR_MEMORY_FATAL;
} }
if (has_keydev_dec == true) { if (has_keydev_dec == true) {
@@ -226,54 +222,45 @@ int load_keydev(uint8_t key[32]) {
uint16_t fid_size = file_get_size(ef_keydev); uint16_t fid_size = file_get_size(ef_keydev);
if (fid_size == 32) { if (fid_size == 32) {
memcpy(key, file_get_data(ef_keydev), 32); memcpy(key, file_get_data(ef_keydev), 32);
if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICOKEYS_AES_MODE_CBC, key, 32) != PICOKEYS_OK) { if (mkek_decrypt(key, 32) != PICOKEY_OK) {
return PICOKEYS_EXEC_ERROR; return PICOKEY_EXEC_ERROR;
}
if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
} }
} }
else if (fid_size == 33 || fid_size == 61) { else if (fid_size == 33 || fid_size == 61) {
uint8_t format = *file_get_data(ef_keydev); uint8_t format = *file_get_data(ef_keydev);
if (format == 0x01 || format == 0x02 || format == 0x03) { // Format indicator if (format == 0x01 || format == 0x02) { // Format indicator
if (format == 0x02 || format == 0x03) { if (format == 0x02) {
uint8_t tmp_key[61], version = format == 0x03 ? 2 : 1; uint8_t tmp_key[61];
memcpy(tmp_key, file_get_data(ef_keydev), sizeof(tmp_key)); memcpy(tmp_key, file_get_data(ef_keydev), sizeof(tmp_key));
int ret = decrypt_with_aad(session_pin, tmp_key + 1, 60, version, key); int ret = decrypt_with_aad(session_pin, tmp_key + 1, 60, key);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
return PICOKEYS_EXEC_ERROR; return PICOKEY_EXEC_ERROR;
} }
if (format == 0x02) {
tmp_key[0] = 0x03;
ret = encrypt_with_aad(session_pin, key, 32, 2, tmp_key + 1);
if (ret != PICOKEYS_OK) {
mbedtls_platform_zeroize(tmp_key, sizeof(tmp_key));
return PICOKEYS_EXEC_ERROR;
}
file_put_data(ef_keydev, tmp_key, sizeof(tmp_key));
flash_commit();
}
mbedtls_platform_zeroize(tmp_key, sizeof(tmp_key));
} }
else { else {
memcpy(key, file_get_data(ef_keydev) + 1, 32); memcpy(key, file_get_data(ef_keydev) + 1, 32);
} }
uint8_t kbase[32]; uint8_t kbase[32];
derive_kbase(kbase); derive_kbase(kbase);
int ret = aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, key, 32); int ret = aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
mbedtls_platform_zeroize(kbase, sizeof(kbase)); mbedtls_platform_zeroize(kbase, sizeof(kbase));
return PICOKEYS_EXEC_ERROR; return PICOKEY_EXEC_ERROR;
} }
mbedtls_platform_zeroize(kbase, sizeof(kbase)); mbedtls_platform_zeroize(kbase, sizeof(kbase));
} }
} }
} }
return PICOKEYS_OK; return PICOKEY_OK;
} }
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) { int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) {
for (size_t i = 0; i < KEY_PATH_ENTRIES; i++) { for (size_t i = 0; i < KEY_PATH_ENTRIES; i++) {
uint32_t k = 0; uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
memcpy(&k, &keyHandle[i * sizeof(uint32_t)], sizeof(k));
if (!(k & 0x80000000)) { if (!(k & 0x80000000)) {
return -1; return -1;
} }
@@ -308,7 +295,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length
int r = 0; int r = 0;
memset(outk, 0, sizeof(outk)); memset(outk, 0, sizeof(outk));
if ((r = load_keydev(outk)) != PICOKEYS_OK) { if ((r = load_keydev(outk)) != PICOKEY_OK) {
printf("Error loading keydev: %d\n", r); printf("Error loading keydev: %d\n", r);
return r; return r;
} }
@@ -316,7 +303,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
for (size_t i = 0; i < KEY_PATH_ENTRIES; i++) { for (size_t i = 0; i < KEY_PATH_ENTRIES; i++) {
if (new_key == true) { if (new_key == true) {
uint32_t val = 0; uint32_t val = 0;
random_fill_buffer((uint8_t *) &val, sizeof(val)); random_gen(NULL, (uint8_t *) &val, sizeof(val));
val |= 0x80000000; val |= 0x80000000;
memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t)); memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t));
} }
@@ -344,12 +331,17 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (cinfo->bit_size % 8 != 0) { if (cinfo->bit_size % 8 != 0) {
outk[0] >>= 8 - (cinfo->bit_size % 8); outk[0] >>= 8 - (cinfo->bit_size % 8);
} }
r = mbedtls_ecp_read_key(curve, key, outk, (size_t)((cinfo->bit_size + 7) / 8)); r = mbedtls_ecp_read_key(curve, key, outk, (size_t)ceil((float) cinfo->bit_size / 8));
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
if (r != 0) { if (r != 0) {
return r; return r;
} }
return mbedtls_ecp_keypair_calc_public(key, random_fill_iterator, NULL); #ifdef MBEDTLS_EDDSA_C
if (curve == MBEDTLS_ECP_DP_ED25519) {
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
}
#endif
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
} }
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
return r; return r;
@@ -361,26 +353,28 @@ int encrypt_keydev_f1(const uint8_t keydev[32]) {
memcpy(kdata + 1, keydev, 32); memcpy(kdata + 1, keydev, 32);
uint8_t kbase[32]; uint8_t kbase[32];
derive_kbase(kbase); derive_kbase(kbase);
int ret = aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, kdata + 1, 32); int ret = aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, kdata + 1, 32);
mbedtls_platform_zeroize(kbase, sizeof(kbase)); mbedtls_platform_zeroize(kbase, sizeof(kbase));
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
return ret; return ret;
} }
ret = file_put_data(ef_keydev, kdata, 33); ret = file_put_data(ef_keydev, kdata, 33);
mbedtls_platform_zeroize(kdata, sizeof(kdata)); mbedtls_platform_zeroize(kdata, sizeof(kdata));
flash_commit(); low_flash_available();
return ret; return ret;
} }
int scan_files_fido(void) { int scan_files_fido() {
ef_keydev = file_search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF); ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF);
ef_keydev_enc = file_search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF); ef_keydev_enc = search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF);
ef_mkek = search_by_fid(EF_MKEK, NULL, SPECIFY_EF);
if (ef_keydev) { if (ef_keydev) {
if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) { if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) {
printf("KEY DEVICE is empty. Generating SECP256R1 curve..."); printf("KEY DEVICE is empty. Generating SECP256R1 curve...");
mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa); mbedtls_ecdsa_init(&ecdsa);
int ret = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP256R1, random_fill_iterator, NULL); uint8_t index = 0;
int ret = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP256R1, random_gen, &index);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return ret; return ret;
@@ -391,12 +385,12 @@ int scan_files_fido(void) {
if (ret != 0 || key_size != 32) { if (ret != 0 || key_size != 32) {
mbedtls_platform_zeroize(keydev, sizeof(keydev)); mbedtls_platform_zeroize(keydev, sizeof(keydev));
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return ret != 0 ? ret : PICOKEYS_EXEC_ERROR; return ret != 0 ? ret : PICOKEY_EXEC_ERROR;
} }
encrypt_keydev_f1(keydev); encrypt_keydev_f1(keydev);
mbedtls_platform_zeroize(keydev, sizeof(keydev)); mbedtls_platform_zeroize(keydev, sizeof(keydev));
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
return ret; return ret;
} }
printf(" done!\n"); printf(" done!\n");
@@ -405,7 +399,7 @@ int scan_files_fido(void) {
else { else {
printf("FATAL ERROR: KEY DEV not found in memory!\r\n"); printf("FATAL ERROR: KEY DEV not found in memory!\r\n");
} }
ef_certdev = file_search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF); ef_certdev = search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF);
if (ef_certdev) { if (ef_certdev) {
if (!file_has_data(ef_certdev)) { if (!file_has_data(ef_certdev)) {
uint8_t cert[2048], outk[32]; uint8_t cert[2048], outk[32];
@@ -421,7 +415,7 @@ int scan_files_fido(void) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return ret; return ret;
} }
ret = mbedtls_ecp_keypair_calc_public(&key, random_fill_iterator, NULL); ret = mbedtls_ecp_mul(&key.grp, &key.Q, &key.d, &key.grp.G, random_gen, NULL);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return ret; return ret;
@@ -437,7 +431,7 @@ int scan_files_fido(void) {
else { else {
printf("FATAL ERROR: CERT DEV not found in memory!\r\n"); printf("FATAL ERROR: CERT DEV not found in memory!\r\n");
} }
ef_counter = file_search_by_fid(EF_COUNTER, NULL, SPECIFY_EF); ef_counter = search_by_fid(EF_COUNTER, NULL, SPECIFY_EF);
if (ef_counter) { if (ef_counter) {
if (!file_has_data(ef_counter)) { if (!file_has_data(ef_counter)) {
uint32_t v = 0; uint32_t v = 0;
@@ -447,13 +441,12 @@ int scan_files_fido(void) {
else { else {
printf("FATAL ERROR: Global counter not found in memory!\r\n"); printf("FATAL ERROR: Global counter not found in memory!\r\n");
} }
ef_pin = file_search_by_fid(EF_PIN, NULL, SPECIFY_EF); ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF);
ef_pin_admin = file_search_by_fid(EF_PIN_ADMIN, NULL, SPECIFY_EF); ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
ef_authtoken = file_search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
if (ef_authtoken) { if (ef_authtoken) {
if (!file_has_data(ef_authtoken)) { if (!file_has_data(ef_authtoken)) {
uint8_t t[32]; uint8_t t[32];
random_fill_buffer(t, sizeof(t)); random_gen(NULL, t, sizeof(t));
file_put_data(ef_authtoken, t, sizeof(t)); file_put_data(ef_authtoken, t, sizeof(t));
} }
paut.data = file_get_data(ef_authtoken); paut.data = file_get_data(ef_authtoken);
@@ -462,11 +455,11 @@ int scan_files_fido(void) {
else { else {
printf("FATAL ERROR: Auth Token not found in memory!\r\n"); printf("FATAL ERROR: Auth Token not found in memory!\r\n");
} }
file_t *ef_pauthtoken = file_search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF); file_t *ef_pauthtoken = search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF);
if (ef_pauthtoken) { if (ef_pauthtoken) {
if (!file_has_data(ef_pauthtoken)) { if (!file_has_data(ef_pauthtoken)) {
uint8_t t[32]; uint8_t t[32];
random_fill_buffer(t, sizeof(t)); random_gen(NULL, t, sizeof(t));
file_put_data(ef_pauthtoken, t, sizeof(t)); file_put_data(ef_pauthtoken, t, sizeof(t));
} }
ppaut.data = file_get_data(ef_pauthtoken); ppaut.data = file_get_data(ef_pauthtoken);
@@ -475,22 +468,23 @@ int scan_files_fido(void) {
else { else {
printf("FATAL ERROR: Persistent Auth Token not found in memory!\r\n"); printf("FATAL ERROR: Persistent Auth Token not found in memory!\r\n");
} }
ef_largeblob = file_search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF); ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF);
if (!file_has_data(ef_largeblob)) { if (!file_has_data(ef_largeblob)) {
file_put_data(ef_largeblob, (const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17); file_put_data(ef_largeblob, (const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17);
} }
flash_commit(); low_flash_available();
return PICOKEYS_OK; return PICOKEY_OK;
} }
void scan_all(void) { void scan_all() {
file_scan_flash(); scan_flash();
scan_files_fido(); scan_files_fido();
} }
extern void init_otp();
extern bool needs_power_cycle; extern bool needs_power_cycle;
void init_fido(void) { void init_fido() {
scan_all(); scan_all();
#ifdef ENABLE_OTP_APP #ifdef ENABLE_OTP_APP
init_otp(); init_otp();
@@ -498,28 +492,22 @@ void init_fido(void) {
needs_power_cycle = false; needs_power_cycle = false;
} }
int wait_button_pressed(void) { bool wait_button_pressed() {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM) #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
queue_try_add(&card_to_usb_q, &val); queue_try_add(&card_to_usb_q, &val);
do { do {
queue_remove_blocking(&usb_to_card_q, &val); queue_remove_blocking(&usb_to_card_q, &val);
} while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT && val != EV_BUTTON_CANCELLED); } while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
#endif #endif
if (val == EV_BUTTON_TIMEOUT) { return val == EV_BUTTON_TIMEOUT;
return 1;
}
else if (val == EV_BUTTON_CANCELLED) {
return 2;
}
return 0;
} }
uint32_t user_present_time_limit = 0; uint32_t user_present_time_limit = 0;
bool check_user_presence(void) { bool check_user_presence() {
if (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) { if (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
if (wait_button_pressed() > 0) { //timeout if (wait_button_pressed() == true) { //timeout
return false; return false;
} }
//user_present_time_limit = board_millis(); //user_present_time_limit = board_millis();
@@ -527,13 +515,13 @@ bool check_user_presence(void) {
return true; return true;
} }
uint32_t get_sign_counter(void) { uint32_t get_sign_counter() {
uint8_t *caddr = file_get_data(ef_counter); uint8_t *caddr = file_get_data(ef_counter);
return get_uint32_le(caddr); return get_uint32_t_le(caddr);
} }
uint8_t get_opts(void) { uint8_t get_opts() {
file_t *ef = file_search_by_fid(EF_OPTS, NULL, SPECIFY_EF); file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
if (file_has_data(ef)) { if (file_has_data(ef)) {
return *file_get_data(ef); return *file_get_data(ef);
} }
@@ -541,14 +529,21 @@ uint8_t get_opts(void) {
} }
void set_opts(uint8_t opts) { void set_opts(uint8_t opts) {
file_t *ef = file_search_by_fid(EF_OPTS, NULL, SPECIFY_EF); file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
file_put_data(ef, &opts, sizeof(uint8_t)); file_put_data(ef, &opts, sizeof(uint8_t));
flash_commit(); low_flash_available();
} }
extern int cmd_register();
extern int cmd_authenticate();
extern int cmd_version();
extern int cbor_parse(int, uint8_t *, size_t);
extern int cbor_vendor(const uint8_t *data, size_t len);
extern void driver_init_hid();
#define CTAP_CBOR 0x10 #define CTAP_CBOR 0x10
static int cmd_vendor(void) { int cmd_vendor() {
uint8_t *old_buf = res_APDU; uint8_t *old_buf = res_APDU;
driver_init_hid(); driver_init_hid();
int ret = cbor_vendor(apdu.data, apdu.nc); int ret = cbor_vendor(apdu.data, apdu.nc);
@@ -561,7 +556,7 @@ static int cmd_vendor(void) {
return SW_OK(); return SW_OK();
} }
static int cmd_cbor(void) { int cmd_cbor() {
uint8_t *old_buf = res_APDU; uint8_t *old_buf = res_APDU;
driver_init_hid(); driver_init_hid();
int ret = cbor_parse(0x90, apdu.data, apdu.nc); int ret = cbor_parse(0x90, apdu.data, apdu.nc);
@@ -583,7 +578,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int fido_process_apdu(void) { int fido_process_apdu() {
if (CLA(apdu) != 0x00 && CLA(apdu) != 0x80) { if (CLA(apdu) != 0x00 && CLA(apdu) != 0x80) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -21,6 +21,11 @@
#if defined(PICO_PLATFORM) #if defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#endif #endif
#ifndef ESP_PLATFORM
#include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#ifdef MBEDTLS_EDDSA_C #ifdef MBEDTLS_EDDSA_C
@@ -34,17 +39,15 @@
#define SHA256_DIGEST_LENGTH (32) #define SHA256_DIGEST_LENGTH (32)
#define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH) #define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH)
extern int scan_files_fido(void); extern int scan_files_fido();
extern int derive_key(const uint8_t *app_id, extern int derive_key(const uint8_t *app_id,
bool new_key, bool new_key,
uint8_t *key_handle, uint8_t *key_handle,
int, int,
mbedtls_ecp_keypair *key); mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *); extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
extern int wait_button_pressed(void); extern bool wait_button_pressed();
extern void init_fido(void); extern void init_fido();
extern void init_otp(void);
extern void scan_all(void);
extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve);
extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id); extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id);
extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key); extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key);
@@ -92,14 +95,14 @@ extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSec
#define FIDO2_OPT_AUV 0x02 // User Verification #define FIDO2_OPT_AUV 0x02 // User Verification
#define MAX_PIN_RETRIES 8 #define MAX_PIN_RETRIES 8
extern bool getUserPresentFlagValue(void); extern bool getUserPresentFlagValue();
extern bool getUserVerifiedFlagValue(void); extern bool getUserVerifiedFlagValue();
extern void clearUserPresentFlag(void); extern void clearUserPresentFlag();
extern void clearUserVerifiedFlag(void); extern void clearUserVerifiedFlag();
extern void clearPinUvAuthTokenPermissionsExceptLbw(void); extern void clearPinUvAuthTokenPermissionsExceptLbw();
extern void send_keepalive(void); extern void send_keepalive();
extern uint32_t get_sign_counter(void); extern uint32_t get_sign_counter();
extern uint8_t get_opts(void); extern uint8_t get_opts();
extern void set_opts(uint8_t); extern void set_opts(uint8_t);
#define MAX_CREDENTIAL_COUNT_IN_LIST 16 #define MAX_CREDENTIAL_COUNT_IN_LIST 16
#define MAX_CRED_ID_LENGTH 1024 #define MAX_CRED_ID_LENGTH 1024
@@ -120,19 +123,7 @@ extern const known_app_t *find_app_by_rp_id_hash(const uint8_t *rp_id_hash);
#define TRANSPORT_TIME_LIMIT (30 * 1000) //USB #define TRANSPORT_TIME_LIMIT (30 * 1000) //USB
bool check_user_presence(void); bool check_user_presence();
int fido_process_apdu(void);
int cmd_register(void);
int cmd_authenticate(void);
int cmd_version(void);
int calculate_oath(uint8_t truncate,
const uint8_t *key,
size_t key_len,
const uint8_t *chal,
size_t chal_len);
int encrypt_keydev_f1(const uint8_t keydev[32]);
int resetPinUvAuthToken(void);
int resetPersistentPinUvAuthToken(void);
typedef struct pinUvAuthToken { typedef struct pinUvAuthToken {
uint8_t *data; uint8_t *data;

View File

@@ -21,6 +21,7 @@ file_t file_entries[] = {
{ .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = { 0 } }, // MF { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = { 0 } }, // MF
{ .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key { .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key
{ .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc { .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc
{ .fid = EF_MKEK, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MKEK
{ .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device { .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device
{ .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate { .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate
{ .fid = EF_COUNTER, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter { .fid = EF_COUNTER, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter
@@ -31,7 +32,6 @@ file_t file_entries[] = {
{ .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options { .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob { .fid = EF_LARGEBLOB, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, { .fid = EF_OTP_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
{ .fid = EF_PIN_ADMIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // ADMIN PIN
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, .ef_structure = 0, .acl = { 0 } } //end { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, .ef_structure = 0, .acl = { 0 } } //end
}; };
@@ -41,7 +41,7 @@ file_t *ef_keydev = NULL;
file_t *ef_certdev = NULL; file_t *ef_certdev = NULL;
file_t *ef_counter = NULL; file_t *ef_counter = NULL;
file_t *ef_pin = NULL; file_t *ef_pin = NULL;
file_t *ef_pin_admin = NULL;
file_t *ef_authtoken = NULL; file_t *ef_authtoken = NULL;
file_t *ef_keydev_enc = NULL; file_t *ef_keydev_enc = NULL;
file_t *ef_largeblob = NULL; file_t *ef_largeblob = NULL;
file_t *ef_mkek = NULL;

View File

@@ -22,12 +22,12 @@
#define EF_KEY_DEV 0xCC00 #define EF_KEY_DEV 0xCC00
#define EF_KEY_DEV_ENC 0xCC01 #define EF_KEY_DEV_ENC 0xCC01
#define EF_MKEK 0xCC0F
#define EF_EE_DEV 0xCE00 #define EF_EE_DEV 0xCE00
#define EF_EE_DEV_EA 0xCE01 #define EF_EE_DEV_EA 0xCE01
#define EF_COUNTER 0xC000 #define EF_COUNTER 0xC000
#define EF_OPTS 0xC001 #define EF_OPTS 0xC001
#define EF_PIN 0x1080 #define EF_PIN 0x1080
#define EF_PIN_ADMIN 0x1084
#define EF_AUTHTOKEN 0x1090 #define EF_AUTHTOKEN 0x1090
#define EF_PAUTHTOKEN 0x1091 #define EF_PAUTHTOKEN 0x1091
#define EF_MINPINLEN 0x1100 #define EF_MINPINLEN 0x1100
@@ -48,9 +48,9 @@ extern file_t *ef_keydev;
extern file_t *ef_certdev; extern file_t *ef_certdev;
extern file_t *ef_counter; extern file_t *ef_counter;
extern file_t *ef_pin; extern file_t *ef_pin;
extern file_t *ef_pin_admin;
extern file_t *ef_authtoken; extern file_t *ef_authtoken;
extern file_t *ef_keydev_enc; extern file_t *ef_keydev_enc;
extern file_t *ef_largeblob; extern file_t *ef_largeblob;
extern file_t *ef_mkek;
#endif //_FILES_H_ #endif //_FILES_H_

97
src/fido/kek.c Normal file
View File

@@ -0,0 +1,97 @@
/*
* This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "fido.h"
#include "stdlib.h"
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#endif
#include "kek.h"
#include "crypto_utils.h"
#include "random.h"
#include "mbedtls/md.h"
#include "mbedtls/cmac.h"
#include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/chachapoly.h"
#include "files.h"
#include "otp.h"
extern uint8_t session_pin[32];
uint8_t mkek_mask[MKEK_KEY_SIZE];
bool has_mkek_mask = false;
#define POLY 0xedb88320
uint32_t crc32c(const uint8_t *buf, size_t len) {
uint32_t crc = 0xffffffff;
while (len--) {
crc ^= *buf++;
for (int k = 0; k < 8; k++) {
crc = (crc >> 1) ^ (POLY & (0 - (crc & 1)));
}
}
return ~crc;
}
void mkek_masked(uint8_t *mkek, const uint8_t *mask) {
if (mask) {
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
MKEK_KEY(mkek)[i] ^= mask[i];
}
}
}
int load_mkek(uint8_t *mkek) {
file_t *tf = search_file(EF_MKEK);
if (file_has_data(tf)) {
memcpy(mkek, file_get_data(tf), MKEK_SIZE);
}
if (has_mkek_mask) {
mkek_masked(mkek, mkek_mask);
}
if (file_get_size(tf) == MKEK_SIZE) {
int ret = aes_decrypt_cfb_256(session_pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
if (ret != 0) {
return PICOKEY_EXEC_ERROR;
}
if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != *(uint32_t *) MKEK_CHECKSUM(mkek)) {
return PICOKEY_WRONG_DKEK;
}
if (otp_key_1) {
mkek_masked(mkek, otp_key_1);
}
}
return PICOKEY_OK;
}
void release_mkek(uint8_t *mkek) {
mbedtls_platform_zeroize(mkek, MKEK_SIZE);
}
int mkek_decrypt(uint8_t *data, uint16_t len) {
int r;
uint8_t mkek[MKEK_SIZE + 4];
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
return r;
}
r = aes_decrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len);
release_mkek(mkek);
return r;
}

46
src/fido/kek.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _KEK_H_
#define _KEK_H_
#include "crypto_utils.h"
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#include <stdbool.h>
#endif
extern int load_mkek(uint8_t *);
extern int store_mkek(const uint8_t *);
extern void init_mkek();
extern void release_mkek(uint8_t *);
extern int mkek_encrypt(uint8_t *data, uint16_t len);
extern int mkek_decrypt(uint8_t *data, uint16_t len);
#define MKEK_IV_SIZE (IV_SIZE)
#define MKEK_KEY_SIZE (32)
#define MKEK_KEY_CS_SIZE (4)
#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE)
#define MKEK_IV(p) (p)
#define MKEK_KEY(p) (MKEK_IV(p) + MKEK_IV_SIZE)
#define MKEK_CHECKSUM(p) (MKEK_KEY(p) + MKEK_KEY_SIZE)
#define DKEK_KEY_SIZE (32)
extern uint8_t mkek_mask[MKEK_KEY_SIZE];
extern bool has_mkek_mask;
#endif

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "fido.h" #include "fido.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"

View File

@@ -15,26 +15,26 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include "pico_keys.h"
#include "picokeys.h"
#include "serial.h"
#include "fido.h" #include "fido.h"
#include "apdu.h" #include "apdu.h"
#include "version.h" #include "version.h"
#include "files.h" #include "files.h"
#include "tlv.h" #include "asn1.h"
#include "management.h" #include "management.h"
bool is_gpg = true; bool is_gpg = true;
static int man_process_apdu(void); int man_process_apdu();
static int man_unload(void); int man_unload();
const uint8_t man_aid[] = { const uint8_t man_aid[] = {
8, 8,
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
}; };
static int man_select(app_t *a, uint8_t force) { extern void scan_all();
extern void init_otp();
int man_select(app_t *a, uint8_t force) {
a->process_apdu = man_process_apdu; a->process_apdu = man_process_apdu;
a->unload = man_unload; a->unload = man_unload;
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR); sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
@@ -47,30 +47,30 @@ static int man_select(app_t *a, uint8_t force) {
#endif #endif
} }
is_gpg = false; is_gpg = false;
return PICOKEYS_OK; return PICOKEY_OK;
} }
INITIALIZER ( man_ctor ) { INITIALIZER ( man_ctor ) {
register_app(man_select, man_aid); register_app(man_select, man_aid);
} }
static int man_unload(void) { int man_unload() {
return PICOKEYS_OK; return PICOKEY_OK;
} }
bool cap_supported(uint16_t cap) { bool cap_supported(uint16_t cap) {
file_t *ef = file_search(EF_DEV_CONF); file_t *ef = search_dynamic_file(EF_DEV_CONF);
if (file_has_data(ef)) { if (file_has_data(ef)) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
tlv_ctx_t ctxi; asn1_ctx_t ctxi;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == TAG_USB_ENABLED) { if (tag == TAG_USB_ENABLED) {
uint16_t ecaps = tag_data[0]; uint16_t ecaps = tag_data[0];
if (tag_len == 2) { if (tag_len == 2) {
ecaps = get_uint16_be(tag_data); ecaps = get_uint16_t_be(tag_data);
} }
return ecaps & cap; return ecaps & cap;
} }
@@ -88,8 +88,8 @@ static uint8_t _piv_aid[] = {
0xA0, 0x00, 0x00, 0x03, 0x8, 0xA0, 0x00, 0x00, 0x03, 0x8,
}; };
int man_get_config(void) { int man_get_config() {
file_t *ef = file_search(EF_DEV_CONF); file_t *ef = search_dynamic_file(EF_DEV_CONF);
res_APDU_size = 0; res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0; // Overall length. Filled later res_APDU[res_APDU_size++] = 0; // Overall length. Filled later
res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED; res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED;
@@ -155,18 +155,18 @@ int man_get_config(void) {
return 0; return 0;
} }
static int cmd_read_config(void) { int cmd_read_config() {
man_get_config(); man_get_config();
return SW_OK(); return SW_OK();
} }
static int cmd_write_config(void) { int cmd_write_config() {
if (apdu.data[0] != apdu.nc - 1) { if (apdu.data[0] != apdu.nc - 1) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = file_new(EF_DEV_CONF); file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1)); file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1));
flash_commit(); low_flash_available();
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
if (cap_supported(CAP_OTP)) { if (cap_supported(CAP_OTP)) {
phy_data.enabled_usb_itf |= PHY_USB_ITF_KB; phy_data.enabled_usb_itf |= PHY_USB_ITF_KB;
@@ -179,8 +179,8 @@ static int cmd_write_config(void) {
return SW_OK(); return SW_OK();
} }
extern int cbor_reset(void); extern int cbor_reset();
static int cmd_factory_reset(void) { int cmd_factory_reset() {
cbor_reset(); cbor_reset();
return SW_OK(); return SW_OK();
} }
@@ -196,7 +196,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
static int man_process_apdu(void) { int man_process_apdu() {
if (CLA(apdu) != 0x00) { if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -50,6 +50,6 @@
#define FLAG_EJECT 0x80 #define FLAG_EJECT 0x80
extern bool cap_supported(uint16_t cap); extern bool cap_supported(uint16_t cap);
extern int man_get_config(void); extern int man_get_config();
#endif //_MANAGEMENT_H #endif //_MANAGEMENT_H

View File

@@ -15,16 +15,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h" #include "pico_keys.h"
#include "serial.h"
#include "fido.h" #include "fido.h"
#include "apdu.h" #include "apdu.h"
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
#include "version.h" #include "version.h"
#include "tlv.h" #include "asn1.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "management.h" #include "management.h"
extern bool is_nk;
#define MAX_OATH_CRED 255 #define MAX_OATH_CRED 255
#define CHALLENGE_LEN 8 #define CHALLENGE_LEN 8
@@ -63,8 +63,8 @@
#define PROP_TOUCH 0x02 #define PROP_TOUCH 0x02
#define PROP_PIN 0x03 #define PROP_PIN 0x03
static int oath_process_apdu(void); int oath_process_apdu();
static int oath_unload(void); int oath_unload();
static bool validated = true; static bool validated = true;
static uint8_t challenge[CHALLENGE_LEN] = { 0 }; static uint8_t challenge[CHALLENGE_LEN] = { 0 };
@@ -74,7 +74,7 @@ const uint8_t oath_aid[] = {
0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01 0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01
}; };
static int oath_select(app_t *a, uint8_t force) { int oath_select(app_t *a, uint8_t force) {
(void) force; (void) force;
if (cap_supported(CAP_OATH)) { if (cap_supported(CAP_OATH)) {
a->process_apdu = oath_process_apdu; a->process_apdu = oath_process_apdu;
@@ -88,8 +88,8 @@ static int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = 8; res_APDU[res_APDU_size++] = 8;
memcpy(res_APDU + res_APDU_size, pico_serial_str, 8); res_APDU_size += 8; memcpy(res_APDU + res_APDU_size, pico_serial_str, 8); res_APDU_size += 8;
if (file_has_data(file_search(EF_OATH_CODE)) == true) { if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) {
random_fill_buffer(challenge, sizeof(challenge)); random_gen(NULL, challenge, sizeof(challenge));
res_APDU[res_APDU_size++] = TAG_CHALLENGE; res_APDU[res_APDU_size++] = TAG_CHALLENGE;
res_APDU[res_APDU_size++] = sizeof(challenge); res_APDU[res_APDU_size++] = sizeof(challenge);
memcpy(res_APDU + res_APDU_size, challenge, sizeof(challenge)); memcpy(res_APDU + res_APDU_size, challenge, sizeof(challenge));
@@ -103,7 +103,7 @@ static int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = 8; res_APDU[res_APDU_size++] = 8;
memcpy(res_APDU + res_APDU_size, pico_serial_str, 8); memcpy(res_APDU + res_APDU_size, pico_serial_str, 8);
res_APDU_size += 8; res_APDU_size += 8;
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF); file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) { if (file_has_data(ef_otp_pin)) {
const uint8_t *pin_data = file_get_data(ef_otp_pin); const uint8_t *pin_data = file_get_data(ef_otp_pin);
res_APDU[res_APDU_size++] = TAG_PIN_COUNTER; res_APDU[res_APDU_size++] = TAG_PIN_COUNTER;
@@ -112,45 +112,45 @@ static int oath_select(app_t *a, uint8_t force) {
} }
} }
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEYS_OK; return PICOKEY_OK;
} }
return PICOKEYS_ERR_FILE_NOT_FOUND; return PICOKEY_ERR_FILE_NOT_FOUND;
} }
INITIALIZER ( oath_ctor ) { INITIALIZER ( oath_ctor ) {
register_app(oath_select, oath_aid); register_app(oath_select, oath_aid);
} }
static int oath_unload(void) { int oath_unload() {
return PICOKEYS_OK; return PICOKEY_OK;
} }
static file_t *find_oath_cred(const uint8_t *name, size_t name_len) { file_t *find_oath_cred(const uint8_t *name, size_t name_len) {
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
tlv_ctx_t ctxi, ef_tag = { 0 }; asn1_ctx_t ctxi, ef_tag = { 0 };
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (file_has_data(ef) && tlv_find_tag(&ctxi, TAG_NAME, &ef_tag) == true && ef_tag.len == name_len && memcmp(ef_tag.data, name, name_len) == 0) { if (file_has_data(ef) && asn1_find_tag(&ctxi, TAG_NAME, &ef_tag) == true && ef_tag.len == name_len && memcmp(ef_tag.data, name, name_len) == 0) {
return ef; return ef;
} }
} }
return NULL; return NULL;
} }
static int cmd_put(void) { int cmd_put() {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
tlv_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 }; asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_KEY, &key) == false) { if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (tlv_find_tag(&ctxi, TAG_IMF, &imf) == false) { if (asn1_find_tag(&ctxi, TAG_IMF, &imf) == false) {
memcpy(apdu.data + apdu.nc, "\x7a\x08\x00\x00\x00\x00\x00\x00\x00\x00", 10); memcpy(apdu.data + apdu.nc, "\x7a\x08\x00\x00\x00\x00\x00\x00\x00\x00", 10);
apdu.nc += 10; apdu.nc += 10;
} }
@@ -167,15 +167,15 @@ static int cmd_put(void) {
file_t *ef = find_oath_cred(name.data, name.len); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef)) { if (file_has_data(ef)) {
file_put_data(ef, apdu.data, (uint16_t)apdu.nc); file_put_data(ef, apdu.data, (uint16_t)apdu.nc);
flash_commit(); low_flash_available();
} }
else { else {
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *tef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *tef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
if (!file_has_data(tef)) { if (!file_has_data(tef)) {
tef = file_new((uint16_t)(EF_OATH_CRED + i)); tef = file_new((uint16_t)(EF_OATH_CRED + i));
file_put_data(tef, apdu.data, (uint16_t)apdu.nc); file_put_data(tef, apdu.data, (uint16_t)apdu.nc);
flash_commit(); low_flash_available();
return SW_OK(); return SW_OK();
} }
} }
@@ -185,16 +185,16 @@ static int cmd_put(void) {
} }
static int cmd_delete(void) { int cmd_delete() {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
tlv_ctx_t ctxi, ctxo = { 0 }; asn1_ctx_t ctxi, ctxo = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &ctxo) == true) { if (asn1_find_tag(&ctxi, TAG_NAME, &ctxo) == true) {
file_t *ef = find_oath_cred(ctxo.data, ctxo.len); file_t *ef = find_oath_cred(ctxo.data, ctxo.len);
if (ef) { if (ef) {
file_delete(ef); delete_file(ef);
return SW_OK(); return SW_OK();
} }
return SW_DATA_INVALID(); return SW_DATA_INVALID();
@@ -202,7 +202,7 @@ static int cmd_delete(void) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
static const mbedtls_md_info_t *get_oath_md_info(uint8_t alg) { const mbedtls_md_info_t *get_oath_md_info(uint8_t alg) {
if ((alg & ALG_MASK) == ALG_HMAC_SHA1) { if ((alg & ALG_MASK) == ALG_HMAC_SHA1) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); return mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
} }
@@ -215,29 +215,29 @@ static const mbedtls_md_info_t *get_oath_md_info(uint8_t alg) {
return NULL; return NULL;
} }
static int cmd_set_code(void) { int cmd_set_code() {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (apdu.nc == 0) { if (apdu.nc == 0) {
file_delete(file_search(EF_OATH_CODE)); delete_file(search_dynamic_file(EF_OATH_CODE));
validated = true; validated = true;
return SW_OK(); return SW_OK();
} }
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 }; asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_KEY, &key) == false) { if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (key.len == 0) { if (key.len == 0) {
file_delete(file_search(EF_OATH_CODE)); delete_file(search_dynamic_file(EF_OATH_CODE));
validated = true; validated = true;
return SW_OK(); return SW_OK();
} }
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) { if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (tlv_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) { if (asn1_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
@@ -253,52 +253,52 @@ static int cmd_set_code(void) {
if (memcmp(hmac, resp.data, resp.len) != 0) { if (memcmp(hmac, resp.data, resp.len) != 0) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
random_fill_buffer(challenge, sizeof(challenge)); random_gen(NULL, challenge, sizeof(challenge));
file_t *ef = file_new(EF_OATH_CODE); file_t *ef = file_new(EF_OATH_CODE);
file_put_data(ef, key.data, key.len); file_put_data(ef, key.data, key.len);
flash_commit(); low_flash_available();
validated = false; validated = false;
return SW_OK(); return SW_OK();
} }
static int cmd_reset(void) { int cmd_reset() {
if (P1(apdu) != 0xde || P2(apdu) != 0xad) { if (P1(apdu) != 0xde || P2(apdu) != 0xad) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) { if (file_has_data(ef)) {
file_delete(ef); delete_file(ef);
} }
} }
file_delete(file_search(EF_OATH_CODE)); delete_file(search_dynamic_file(EF_OATH_CODE));
flash_clear_file(file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF)); flash_clear_file(search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF));
flash_commit(); low_flash_available();
validated = true; validated = true;
return SW_OK(); return SW_OK();
} }
static int cmd_list(void) { int cmd_list() {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
bool ext = (apdu.nc == 1 && apdu.data[0] == 0x01); bool ext = (apdu.nc == 1 && apdu.data[0] == 0x01);
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) { if (file_has_data(ef)) {
tlv_ctx_t ctxi, key = { 0 }, name = { 0 }, pws = { 0 }; asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, pws = { 0 };
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == true && tlv_find_tag(&ctxi, TAG_KEY, &key) == true) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == true && asn1_find_tag(&ctxi, TAG_KEY, &key) == true) {
res_APDU[res_APDU_size++] = TAG_NAME_LIST; res_APDU[res_APDU_size++] = TAG_NAME_LIST;
res_APDU[res_APDU_size++] = (uint8_t)(name.len + 1 + (ext ? 1 : 0)); res_APDU[res_APDU_size++] = (uint8_t)(name.len + 1 + (ext ? 1 : 0));
res_APDU[res_APDU_size++] = key.data[0]; res_APDU[res_APDU_size++] = key.data[0];
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len; memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
if (ext) { if (ext) {
uint8_t props = 0x0; uint8_t props = 0x0;
if (tlv_find_tag(&ctxi, TAG_PWS_LOGIN, &pws) == true || tlv_find_tag(&ctxi, TAG_PWS_PASSWORD, &pws) == true || tlv_find_tag(&ctxi, TAG_PWS_METADATA, &pws) == true) { if (asn1_find_tag(&ctxi, TAG_PWS_LOGIN, &pws) == true || asn1_find_tag(&ctxi, TAG_PWS_PASSWORD, &pws) == true || asn1_find_tag(&ctxi, TAG_PWS_METADATA, &pws) == true) {
props |= 0x4; props |= 0x4;
} }
if (tlv_find_tag(&ctxi, TAG_PROPERTY, &pws) == true && (pws.data[0] & PROP_TOUCH)) { if (asn1_find_tag(&ctxi, TAG_PROPERTY, &pws) == true && (pws.data[0] & PROP_TOUCH)) {
props |= 0x1; props |= 0x1;
} }
res_APDU[res_APDU_size++] = props; res_APDU[res_APDU_size++] = props;
@@ -310,16 +310,16 @@ static int cmd_list(void) {
return SW_OK(); return SW_OK();
} }
static int cmd_validate(void) { int cmd_validate() {
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 }; asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) { if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (tlv_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) { if (asn1_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
file_t *ef = file_search(EF_OATH_CODE); file_t *ef = search_dynamic_file(EF_OATH_CODE);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
validated = true; validated = true;
return SW_DATA_INVALID(); return SW_DATA_INVALID();
@@ -360,7 +360,7 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
int r = mbedtls_md_hmac(md_info, key + 2, key_len - 2, chal, chal_len, hmac); int r = mbedtls_md_hmac(md_info, key + 2, key_len - 2, chal, chal_len, hmac);
size_t hmac_size = mbedtls_md_get_size(md_info); size_t hmac_size = mbedtls_md_get_size(md_info);
if (r != 0) { if (r != 0) {
return PICOKEYS_EXEC_ERROR; return PICOKEY_EXEC_ERROR;
} }
if (truncate == 0x01) { if (truncate == 0x01) {
res_APDU[res_APDU_size++] = 4 + 1; res_APDU[res_APDU_size++] = 4 + 1;
@@ -377,36 +377,36 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += (uint16_t)hmac_size; memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += (uint16_t)hmac_size;
} }
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEYS_OK; return PICOKEY_OK;
} }
static int cmd_calculate(void) { int cmd_calculate() {
if (P2(apdu) != 0x0 && P2(apdu) != 0x1) { if (P2(apdu) != 0x0 && P2(apdu) != 0x1) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }; asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) { if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
file_t *ef = find_oath_cred(name.data, name.len); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
tlv_ctx_t ctxe; asn1_ctx_t ctxe;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe); asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (tlv_find_tag(&ctxe, TAG_KEY, &key) == false) { if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (tlv_find_tag(&ctxe, TAG_IMF, &chal) == false) { if (asn1_find_tag(&ctxe, TAG_IMF, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
} }
@@ -414,48 +414,48 @@ static int cmd_calculate(void) {
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu); res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len); int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
uint64_t v = get_uint64_be(chal.data); uint64_t v = get_uint64_t_be(chal.data);
size_t ef_size = file_get_size(ef); size_t ef_size = file_get_size(ef);
v++; v++;
uint8_t *tmp = (uint8_t *) calloc(1, ef_size); uint8_t *tmp = (uint8_t *) calloc(1, ef_size);
memcpy(tmp, file_get_data(ef), ef_size); memcpy(tmp, file_get_data(ef), ef_size);
tlv_ctx_t ctxt; asn1_ctx_t ctxt;
tlv_ctx_init(tmp, (uint16_t)ef_size, &ctxt); asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
tlv_find_tag(&ctxt, TAG_IMF, &chal); asn1_find_tag(&ctxt, TAG_IMF, &chal);
put_uint64_be(v, chal.data); put_uint64_t_be(v, chal.data);
file_put_data(ef, tmp, (uint16_t)ef_size); file_put_data(ef, tmp, (uint16_t)ef_size);
flash_commit(); low_flash_available();
free(tmp); free(tmp);
} }
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return SW_OK(); return SW_OK();
} }
static int cmd_calculate_all(void) { int cmd_calculate_all() {
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 }; asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (P2(apdu) != 0x0 && P2(apdu) != 0x1) { if (P2(apdu) != 0x0 && P2(apdu) != 0x1) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) { if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
res_APDU_size = 0; res_APDU_size = 0;
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) { if (file_has_data(ef)) {
const uint8_t *ef_data = file_get_data(ef); const uint8_t *ef_data = file_get_data(ef);
size_t ef_len = file_get_size(ef); size_t ef_len = file_get_size(ef);
tlv_ctx_t ctxe; asn1_ctx_t ctxe;
tlv_ctx_init((uint8_t *)ef_data, (uint16_t)ef_len, &ctxe); asn1_ctx_init((uint8_t *)ef_data, (uint16_t)ef_len, &ctxe);
if (tlv_find_tag(&ctxe, TAG_NAME, &name) == false || tlv_find_tag(&ctxe, TAG_KEY, &key) == false) { if (asn1_find_tag(&ctxe, TAG_NAME, &name) == false || asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
continue; continue;
} }
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
@@ -466,7 +466,7 @@ static int cmd_calculate_all(void) {
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1]; res_APDU[res_APDU_size++] = key.data[1];
} }
else if (tlv_find_tag(&ctxe, TAG_PROPERTY, &prop) == true && (prop.data[0] & PROP_TOUCH)) { else if (asn1_find_tag(&ctxe, TAG_PROPERTY, &prop) == true && (prop.data[0] & PROP_TOUCH)) {
res_APDU[res_APDU_size++] = TAG_TOUCH_RESPONSE; res_APDU[res_APDU_size++] = TAG_TOUCH_RESPONSE;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1]; res_APDU[res_APDU_size++] = key.data[1];
@@ -474,7 +474,7 @@ static int cmd_calculate_all(void) {
else { else {
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu); res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len); int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1]; res_APDU[res_APDU_size++] = key.data[1];
} }
@@ -485,62 +485,62 @@ static int cmd_calculate_all(void) {
return SW_OK(); return SW_OK();
} }
static int cmd_send_remaining(void) { int cmd_send_remaining() {
return SW_OK(); return SW_OK();
} }
static int cmd_set_otp_pin(void) { int cmd_set_otp_pin() {
uint8_t hsh[33] = { 0 }; uint8_t hsh[33] = { 0 };
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF); file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) { if (file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
tlv_ctx_t ctxi, pw = { 0 }; asn1_ctx_t ctxi, pw = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) { if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
hsh[0] = MAX_OTP_COUNTER; hsh[0] = MAX_OTP_COUNTER;
double_hash_pin(pw.data, pw.len, hsh + 1); double_hash_pin(pw.data, pw.len, hsh + 1);
file_put_data(ef_otp_pin, hsh, sizeof(hsh)); file_put_data(ef_otp_pin, hsh, sizeof(hsh));
flash_commit(); low_flash_available();
return SW_OK(); return SW_OK();
} }
static int cmd_change_otp_pin(void) { int cmd_change_otp_pin() {
uint8_t hsh[33] = { 0 }; uint8_t hsh[33] = { 0 };
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF); file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (!file_has_data(ef_otp_pin)) { if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
tlv_ctx_t ctxi, pw = { 0 }, new_pw = { 0 }; asn1_ctx_t ctxi, pw = { 0 }, new_pw = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) { if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
double_hash_pin(pw.data, pw.len, hsh + 1); double_hash_pin(pw.data, pw.len, hsh + 1);
if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) { if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (tlv_find_tag(&ctxi, TAG_NEW_PASSWORD, &new_pw) == false) { if (asn1_find_tag(&ctxi, TAG_NEW_PASSWORD, &new_pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
hsh[0] = MAX_OTP_COUNTER; hsh[0] = MAX_OTP_COUNTER;
double_hash_pin(new_pw.data, new_pw.len, hsh + 1); double_hash_pin(new_pw.data, new_pw.len, hsh + 1);
file_put_data(ef_otp_pin, hsh, sizeof(hsh)); file_put_data(ef_otp_pin, hsh, sizeof(hsh));
flash_commit(); low_flash_available();
return SW_OK(); return SW_OK();
} }
static int cmd_verify_otp_pin(void) { int cmd_verify_otp_pin() {
uint8_t hsh[33] = { 0 }, data_hsh[33]; uint8_t hsh[33] = { 0 }, data_hsh[33];
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF); file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (!file_has_data(ef_otp_pin)) { if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
tlv_ctx_t ctxi, pw = { 0 }; asn1_ctx_t ctxi, pw = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) { if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
double_hash_pin(pw.data, pw.len, hsh + 1); double_hash_pin(pw.data, pw.len, hsh + 1);
@@ -550,49 +550,49 @@ static int cmd_verify_otp_pin(void) {
data_hsh[0] -= 1; data_hsh[0] -= 1;
} }
file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh)); file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh));
flash_commit(); low_flash_available();
validated = false; validated = false;
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
data_hsh[0] = MAX_OTP_COUNTER; data_hsh[0] = MAX_OTP_COUNTER;
file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh)); file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh));
flash_commit(); low_flash_available();
validated = true; validated = true;
return SW_OK(); return SW_OK();
} }
static int cmd_verify_hotp(void) { int cmd_verify_hotp() {
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 }; asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
uint32_t code_int = 0; uint32_t code_int = 0;
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
file_t *ef = file_search_by_fid(EF_OATH_CRED, NULL, SPECIFY_EF); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
tlv_ctx_t ctxe; asn1_ctx_t ctxe;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe); asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (tlv_find_tag(&ctxe, TAG_KEY, &key) == false) { if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if ((key.data[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) { if ((key.data[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
if (tlv_find_tag(&ctxe, TAG_IMF, &chal) == false) { if (asn1_find_tag(&ctxe, TAG_IMF, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (tlv_find_tag(&ctxi, TAG_RESPONSE, &code) == true) { if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = get_uint32_be(code.data); code_int = get_uint32_t_be(code.data);
} }
int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len); int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len);
if (ret != PICOKEYS_OK) { if (ret != PICOKEY_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
uint32_t res_int = get_uint32_be(res_APDU + 2); uint32_t res_int = get_uint32_t_be(res_APDU + 2);
if (res_APDU[1] == 6) { if (res_APDU[1] == 6) {
res_int %= (uint32_t) 1e6; res_int %= (uint32_t) 1e6;
} }
@@ -607,8 +607,8 @@ static int cmd_verify_hotp(void) {
return SW_OK(); return SW_OK();
} }
static int cmd_rename(void) { int cmd_rename() {
tlv_ctx_t ctxi, name = { 0 }, new_name = { 0 }; asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 };
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
@@ -616,16 +616,16 @@ static int cmd_rename(void) {
if (apdu.data[0] != TAG_NAME) { if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
tlv_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi); asn1_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &new_name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
if (name.len == new_name.len && memcmp(name.data, new_name.data, name.len) == 0) { if (memcmp(name.data, new_name.data, name.len) == 0) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = find_oath_cred(name.data, name.len); file_t *ef = find_oath_cred(name.data, name.len);
@@ -634,8 +634,8 @@ static int cmd_rename(void) {
} }
uint8_t *fdata = file_get_data(ef); uint8_t *fdata = file_get_data(ef);
uint16_t fsize = file_get_size(ef); uint16_t fsize = file_get_size(ef);
tlv_ctx_init(fdata, fsize, &ctxi); asn1_ctx_init(fdata, fsize, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
uint8_t *new_data = (uint8_t *) calloc(fsize + new_name.len - name.len, sizeof(uint8_t)); uint8_t *new_data = (uint8_t *) calloc(fsize + new_name.len - name.len, sizeof(uint8_t));
@@ -644,50 +644,50 @@ static int cmd_rename(void) {
memcpy(new_data + (name.data - fdata), new_name.data, new_name.len); memcpy(new_data + (name.data - fdata), new_name.data, new_name.len);
memcpy(new_data + (name.data - fdata) + new_name.len, name.data + name.len, fsize - (name.data + name.len - fdata)); memcpy(new_data + (name.data - fdata) + new_name.len, name.data + name.len, fsize - (name.data + name.len - fdata));
file_put_data(ef, new_data, fsize + new_name.len - name.len); file_put_data(ef, new_data, fsize + new_name.len - name.len);
flash_commit(); low_flash_available();
free(new_data); free(new_data);
return SW_OK(); return SW_OK();
} }
static int cmd_get_credential(void) { int cmd_get_credential() {
tlv_ctx_t ctxi, name = { 0 }; asn1_ctx_t ctxi, name = { 0 };
if (apdu.nc < 3) { if (apdu.nc < 3) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (apdu.data[0] != TAG_NAME) { if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = find_oath_cred(name.data, name.len); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
tlv_ctx_t login = { 0 }, pw = { 0 }, meta = { 0 }, prop = { 0 }; asn1_ctx_t login = { 0 }, pw = { 0 }, meta = { 0 }, prop = { 0 };
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == true) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == true) {
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = (uint8_t)(name.len); res_APDU[res_APDU_size++] = (uint8_t)(name.len);
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len; memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
} }
if (tlv_find_tag(&ctxi, TAG_PWS_LOGIN, &login) == true) { if (asn1_find_tag(&ctxi, TAG_PWS_LOGIN, &login) == true) {
res_APDU[res_APDU_size++] = TAG_PWS_LOGIN; res_APDU[res_APDU_size++] = TAG_PWS_LOGIN;
res_APDU[res_APDU_size++] = (uint8_t)(login.len); res_APDU[res_APDU_size++] = (uint8_t)(login.len);
memcpy(res_APDU + res_APDU_size, login.data, login.len); res_APDU_size += login.len; memcpy(res_APDU + res_APDU_size, login.data, login.len); res_APDU_size += login.len;
} }
if (tlv_find_tag(&ctxi, TAG_PWS_PASSWORD, &pw) == true) { if (asn1_find_tag(&ctxi, TAG_PWS_PASSWORD, &pw) == true) {
res_APDU[res_APDU_size++] = TAG_PWS_PASSWORD; res_APDU[res_APDU_size++] = TAG_PWS_PASSWORD;
res_APDU[res_APDU_size++] = (uint8_t)(pw.len); res_APDU[res_APDU_size++] = (uint8_t)(pw.len);
memcpy(res_APDU + res_APDU_size, pw.data, pw.len); res_APDU_size += pw.len; memcpy(res_APDU + res_APDU_size, pw.data, pw.len); res_APDU_size += pw.len;
} }
if (tlv_find_tag(&ctxi, TAG_PWS_METADATA, &meta) == true) { if (asn1_find_tag(&ctxi, TAG_PWS_METADATA, &meta) == true) {
res_APDU[res_APDU_size++] = TAG_PWS_METADATA; res_APDU[res_APDU_size++] = TAG_PWS_METADATA;
res_APDU[res_APDU_size++] = (uint8_t)(meta.len); res_APDU[res_APDU_size++] = (uint8_t)(meta.len);
memcpy(res_APDU + res_APDU_size, meta.data, meta.len); res_APDU_size += meta.len; memcpy(res_APDU + res_APDU_size, meta.data, meta.len); res_APDU_size += meta.len;
} }
if (tlv_find_tag(&ctxi, TAG_PROPERTY, &prop) == true) { if (asn1_find_tag(&ctxi, TAG_PROPERTY, &prop) == true) {
res_APDU[res_APDU_size++] = TAG_PROPERTY; res_APDU[res_APDU_size++] = TAG_PROPERTY;
res_APDU[res_APDU_size++] = (uint8_t)(prop.len); res_APDU[res_APDU_size++] = (uint8_t)(prop.len);
memcpy(res_APDU + res_APDU_size, prop.data, prop.len); res_APDU_size += prop.len; memcpy(res_APDU + res_APDU_size, prop.data, prop.len); res_APDU_size += prop.len;
@@ -731,7 +731,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
static int oath_process_apdu(void) { int oath_process_apdu() {
if (CLA(apdu) != 0x00) { if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -15,30 +15,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include "pico_keys.h"
#include "picokeys.h"
#include "serial.h"
#include "button.h"
#include "fido.h" #include "fido.h"
#include "apdu.h" #include "apdu.h"
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
#include "version.h" #include "version.h"
#include "asn1.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "usb.h" #include "usb.h"
#if defined(PICO_PLATFORM) #if defined(PICO_PLATFORM)
#include "bsp/board.h" #include "bsp/board.h"
#endif #endif
#ifdef ENABLE_EMULATION #ifdef ENABLE_EMULATION
void add_keyboard_buffer(const uint8_t *buf, size_t len, bool press_enter) { void add_keyboard_buffer(const uint8_t *buf, size_t len, bool press_enter) {}
(void)buf; void append_keyboard_buffer(const uint8_t *buf, size_t len) {}
(void)len;
(void)press_enter;
}
void append_keyboard_buffer(const uint8_t *buf, size_t len) {
(void)buf;
(void)len;
}
#else #else
#include "tusb.h" #include "tusb.h"
#endif #endif
@@ -128,40 +119,42 @@ typedef struct otp_config {
}) otp_config_t; }) otp_config_t;
#define otp_config_size sizeof(otp_config_t) #define otp_config_size sizeof(otp_config_t)
static uint16_t otp_status(bool is_otp); uint16_t otp_status(bool is_otp);
static int otp_process_apdu(void);
static int otp_unload(void); int otp_process_apdu();
int otp_unload();
extern int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t); extern int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t);
extern uint16_t (*hid_get_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t); extern uint16_t (*hid_get_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t);
static int otp_hid_set_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t); int otp_hid_set_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t);
static uint16_t otp_hid_get_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t); uint16_t otp_hid_get_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t);
const uint8_t otp_aid[] = { const uint8_t otp_aid[] = {
7, 7,
0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01
}; };
static int otp_select(app_t *a, uint8_t force) { int otp_select(app_t *a, uint8_t force) {
(void) force; (void) force;
if (cap_supported(CAP_OTP)) { if (cap_supported(CAP_OTP)) {
a->process_apdu = otp_process_apdu; a->process_apdu = otp_process_apdu;
a->unload = otp_unload; a->unload = otp_unload;
if (file_has_data(file_search(EF_OTP_SLOT1)) || file_has_data(file_search(EF_OTP_SLOT2))) { if (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ||
file_has_data(search_dynamic_file(EF_OTP_SLOT2))) {
config_seq = 1; config_seq = 1;
} }
else { else {
config_seq = 0; config_seq = 0;
} }
otp_status(false); otp_status(false);
return PICOKEYS_OK; return PICOKEY_OK;
} }
return PICOKEYS_ERR_FILE_NOT_FOUND; return PICOKEY_ERR_FILE_NOT_FOUND;
} }
uint8_t modhex_tab[] = uint8_t modhex_tab[] =
{ 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v' }; { 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v' };
static int encode_modhex(const uint8_t *in, size_t len, uint8_t *out) { int encode_modhex(const uint8_t *in, size_t len, uint8_t *out) {
for (size_t l = 0; l < len; l++) { for (size_t l = 0; l < len; l++) {
*out++ = modhex_tab[in[l] >> 4]; *out++ = modhex_tab[in[l] >> 4];
*out++ = modhex_tab[in[l] & 0xf]; *out++ = modhex_tab[in[l] & 0xf];
@@ -169,29 +162,36 @@ static int encode_modhex(const uint8_t *in, size_t len, uint8_t *out) {
return 0; return 0;
} }
static bool scanned = false; static bool scanned = false;
void init_otp(void) { extern void scan_all();
void init_otp() {
if (scanned == false) { if (scanned == false) {
scan_all(); scan_all();
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
file_t *ef = file_search(EF_OTP_SLOT1 + i); file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
uint8_t *data = file_get_data(ef); uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data; otp_config_t *otp_config = (otp_config_t *) data;
if (file_has_data(ef) && !(otp_config->tkt_flags & OATH_HOTP) && if (file_has_data(ef) && !(otp_config->tkt_flags & OATH_HOTP) &&
!(otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET)) { !(otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET)) {
uint16_t counter = get_uint16_be(data + otp_config_size); uint16_t counter = get_uint16_t_be(data + otp_config_size);
if (++counter <= 0x7fff) { if (++counter <= 0x7fff) {
uint8_t new_data[otp_config_size + 8]; uint8_t new_data[otp_config_size + 8];
memcpy(new_data, data, sizeof(new_data)); memcpy(new_data, data, sizeof(new_data));
put_uint16_be(counter, new_data + otp_config_size); put_uint16_t_be(counter, new_data + otp_config_size);
file_put_data(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
} }
} }
} }
scanned = true; scanned = true;
flash_commit(); low_flash_available();
} }
} }
static uint16_t calculate_crc(const uint8_t *data, size_t data_len) { extern int calculate_oath(uint8_t truncate,
const uint8_t *key,
size_t key_len,
const uint8_t *chal,
size_t chal_len);
uint16_t calculate_crc(const uint8_t *data, size_t data_len) {
uint16_t crc = 0xFFFF; uint16_t crc = 0xFFFF;
for (size_t idx = 0; idx < data_len; idx++) { for (size_t idx = 0; idx < data_len; idx++) {
crc ^= data[idx]; crc ^= data[idx];
@@ -207,13 +207,13 @@ static uint16_t calculate_crc(const uint8_t *data, size_t data_len) {
} }
static uint8_t session_counter[2] = { 0 }; static uint8_t session_counter[2] = { 0 };
static int otp_button_pressed(uint8_t slot) { int otp_button_pressed(uint8_t slot) {
init_otp(); init_otp();
if (!cap_supported(CAP_OTP)) { if (!cap_supported(CAP_OTP)) {
return 3; return 3;
} }
uint16_t slot_ef = EF_OTP_SLOT1 + slot - 1; uint16_t slot_ef = EF_OTP_SLOT1 + slot - 1;
file_t *ef = file_search(slot_ef); file_t *ef = search_dynamic_file(slot_ef);
const uint8_t *data = file_get_data(ef); const uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data; otp_config_t *otp_config = (otp_config_t *) data;
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
@@ -229,18 +229,18 @@ static int otp_button_pressed(uint8_t slot) {
memcpy(tmp_key + 2, otp_config->aes_key, KEY_SIZE); memcpy(tmp_key + 2, otp_config->aes_key, KEY_SIZE);
uint64_t imf = 0; uint64_t imf = 0;
const uint8_t *p = data + otp_config_size; const uint8_t *p = data + otp_config_size;
imf = get_uint64_be(p); imf = get_uint64_t_be(p);
p += 8; p += 8;
if (imf == 0) { if (imf == 0) {
imf = get_uint16_be(otp_config->uid + 4); imf = get_uint16_t_be(otp_config->uid + 4);
} }
uint8_t chal[8]; uint8_t chal[8];
put_uint64_be(imf, chal); put_uint64_t_be(imf, chal);
res_APDU_size = 0; res_APDU_size = 0;
int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal)); int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal));
if (ret == PICOKEYS_OK) { if (ret == PICOKEY_OK) {
uint32_t base = otp_config->cfg_flags & OATH_HOTP8 ? 1e8 : 1e6; uint32_t base = otp_config->cfg_flags & OATH_HOTP8 ? 1e8 : 1e6;
uint32_t number = get_uint16_be(res_APDU + 2); uint32_t number = get_uint16_t_be(res_APDU + 2);
number %= base; number %= base;
char number_str[9]; char number_str[9];
if (otp_config->cfg_flags & OATH_HOTP8) { if (otp_config->cfg_flags & OATH_HOTP8) {
@@ -253,12 +253,12 @@ static int otp_button_pressed(uint8_t slot) {
} }
imf++; imf++;
uint8_t new_chal[8]; uint8_t new_chal[8];
put_uint64_be(imf, new_chal); put_uint64_t_be(imf, new_chal);
uint8_t new_otp_config[otp_config_size + sizeof(new_chal)]; uint8_t new_otp_config[otp_config_size + sizeof(new_chal)];
memcpy(new_otp_config, otp_config, otp_config_size); memcpy(new_otp_config, otp_config, otp_config_size);
memcpy(new_otp_config + otp_config_size, new_chal, sizeof(new_chal)); memcpy(new_otp_config + otp_config_size, new_chal, sizeof(new_chal));
file_put_data(ef, new_otp_config, sizeof(new_otp_config)); file_put_data(ef, new_otp_config, sizeof(new_otp_config));
flash_commit(); low_flash_available();
} }
if (otp_config->tkt_flags & APPEND_CR) { if (otp_config->tkt_flags & APPEND_CR) {
append_keyboard_buffer((const uint8_t *) "\r", 1); append_keyboard_buffer((const uint8_t *) "\r", 1);
@@ -278,7 +278,7 @@ static int otp_button_pressed(uint8_t slot) {
else { else {
uint8_t otpk[22], *po = otpk; uint8_t otpk[22], *po = otpk;
bool update_counter = false; bool update_counter = false;
uint16_t counter = get_uint16_be(data + otp_config_size), crc = 0; uint16_t counter = get_uint16_t_be(data + otp_config_size), crc = 0;
uint32_t ts = board_millis() / 1000; uint32_t ts = board_millis() / 1000;
if (counter == 0) { if (counter == 0) {
update_counter = true; update_counter = true;
@@ -288,16 +288,16 @@ static int otp_button_pressed(uint8_t slot) {
po += 6; po += 6;
memcpy(po, otp_config->uid, UID_SIZE); memcpy(po, otp_config->uid, UID_SIZE);
po += UID_SIZE; po += UID_SIZE;
po += put_uint16_le(counter, po); po += put_uint16_t_le(counter, po);
ts >>= 1; ts >>= 1;
*po++ = ts & 0xff; *po++ = ts & 0xff;
*po++ = ts >> 8; *po++ = ts >> 8;
*po++ = ts >> 16; *po++ = ts >> 16;
*po++ = session_counter[slot - 1]; *po++ = session_counter[slot - 1];
random_fill_buffer(po, 2); random_gen(NULL, po, 2);
po += 2; po += 2;
crc = calculate_crc(otpk + 6, 14); crc = calculate_crc(otpk + 6, 14);
po += put_uint16_le(~crc, po); po += put_uint16_t_le(~crc, po);
mbedtls_aes_context ctx; mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx); mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128); mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128);
@@ -318,9 +318,9 @@ static int otp_button_pressed(uint8_t slot) {
if (update_counter == true) { if (update_counter == true) {
uint8_t new_data[otp_config_size + 8]; uint8_t new_data[otp_config_size + 8];
memcpy(new_data, data, sizeof(new_data)); memcpy(new_data, data, sizeof(new_data));
put_uint16_be(counter, new_data + otp_config_size); put_uint16_t_be(counter, new_data + otp_config_size);
file_put_data(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
flash_commit(); low_flash_available();
} }
} }
@@ -334,14 +334,14 @@ INITIALIZER( otp_ctor ) {
hid_get_report_cb = otp_hid_get_report_cb; hid_get_report_cb = otp_hid_get_report_cb;
} }
static int otp_unload(void) { int otp_unload() {
return PICOKEYS_OK; return PICOKEY_OK;
} }
uint8_t status_byte = 0x0; uint8_t status_byte = 0x0;
static uint16_t otp_status_ext(void) { uint16_t otp_status_ext() {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
file_t *ef = file_search(EF_OTP_SLOT1 + i); file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
if (file_has_data(ef)) { if (file_has_data(ef)) {
res_APDU[res_APDU_size++] = 0xB0 + i; res_APDU[res_APDU_size++] = 0xB0 + i;
res_APDU[res_APDU_size++] = 0; // Filled later res_APDU[res_APDU_size++] = 0; // Filled later
@@ -372,7 +372,7 @@ static uint16_t otp_status_ext(void) {
return SW_OK(); return SW_OK();
} }
static uint16_t otp_status(bool is_otp) { uint16_t otp_status(bool is_otp) {
if (scanned == false) { if (scanned == false) {
scan_all(); scan_all();
scanned = true; scanned = true;
@@ -386,7 +386,7 @@ static uint16_t otp_status(bool is_otp) {
res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq; res_APDU[res_APDU_size++] = config_seq;
uint8_t opts = 0; uint8_t opts = 0;
file_t *ef = file_search(EF_OTP_SLOT1); file_t *ef = search_dynamic_file(EF_OTP_SLOT1);
if (file_has_data(ef)) { if (file_has_data(ef)) {
opts |= CONFIG1_VALID; opts |= CONFIG1_VALID;
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef); otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
@@ -394,7 +394,7 @@ static uint16_t otp_status(bool is_otp) {
opts |= CONFIG1_TOUCH; opts |= CONFIG1_TOUCH;
} }
} }
ef = file_search(EF_OTP_SLOT2); ef = search_dynamic_file(EF_OTP_SLOT2);
if (file_has_data(ef)) { if (file_has_data(ef)) {
opts |= CONFIG2_VALID; opts |= CONFIG2_VALID;
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef); otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
@@ -415,13 +415,13 @@ static uint16_t otp_status(bool is_otp) {
return SW_OK(); return SW_OK();
} }
static bool check_crc(const otp_config_t *data) { bool check_crc(const otp_config_t *data) {
uint16_t crc = calculate_crc((const uint8_t *) data, otp_config_size); uint16_t crc = calculate_crc((const uint8_t *) data, otp_config_size);
return crc == 0xF0B8; return crc == 0xF0B8;
} }
bool _is_otp = false; bool _is_otp = false;
static int cmd_otp(void) { int cmd_otp() {
uint8_t p1 = P1(apdu), p2 = P2(apdu); uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p1 == 0x01 || p1 == 0x03) { // Configure slot if (p1 == 0x01 || p1 == 0x03) { // Configure slot
otp_config_t *odata = (otp_config_t *) apdu.data; otp_config_t *odata = (otp_config_t *) apdu.data;
@@ -436,20 +436,20 @@ static int cmd_otp(void) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
} }
for (size_t c = 0; c < otp_config_size; c++) { for (int c = 0; c < otp_config_size; c++) {
if (apdu.data[c] != 0) { if (apdu.data[c] != 0) {
if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) { if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
memset(apdu.data + otp_config_size, 0, 8); // Add 8 bytes extra memset(apdu.data + otp_config_size, 0, 8); // Add 8 bytes extra
file_put_data(ef, apdu.data, otp_config_size + 8); file_put_data(ef, apdu.data, otp_config_size + 8);
flash_commit(); low_flash_available();
config_seq++; config_seq++;
return otp_status(_is_otp); return otp_status(_is_otp);
} }
} }
// Delete slot // Delete slot
file_delete(ef); delete_file(ef);
config_seq++; config_seq++;
return otp_status(_is_otp); return otp_status(_is_otp);
} }
@@ -462,7 +462,7 @@ static int cmd_otp(void) {
if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) { if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = file_search(slot); file_t *ef = search_dynamic_file(slot);
if (file_has_data(ef)) { if (file_has_data(ef)) {
otp_config_t *otpc = (otp_config_t *) file_get_data(ef); otp_config_t *otpc = (otp_config_t *) file_get_data(ef);
if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) { if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) {
@@ -482,7 +482,7 @@ static int cmd_otp(void) {
odata->cfg_flags = otpc->cfg_flags; odata->cfg_flags = otpc->cfg_flags;
} }
file_put_data(ef, apdu.data, otp_config_size); file_put_data(ef, apdu.data, otp_config_size);
flash_commit(); low_flash_available();
config_seq++; config_seq++;
} }
return otp_status(_is_otp); return otp_status(_is_otp);
@@ -508,7 +508,7 @@ static int cmd_otp(void) {
file_put_data(ef1, file_get_data(ef2), file_get_size(ef2)); file_put_data(ef1, file_get_data(ef2), file_get_size(ef2));
} }
else { else {
file_delete(ef1); delete_file(ef1);
// When a dynamic file is deleted, existing referenes are invalidated // When a dynamic file is deleted, existing referenes are invalidated
ef2 = file_new(slot2); ef2 = file_new(slot2);
} }
@@ -516,9 +516,9 @@ static int cmd_otp(void) {
file_put_data(ef2, tmp, sizeof(tmp)); file_put_data(ef2, tmp, sizeof(tmp));
} }
else { else {
file_delete(ef2); delete_file(ef2);
} }
flash_commit(); low_flash_available();
config_seq++; config_seq++;
return otp_status(_is_otp); return otp_status(_is_otp);
} }
@@ -538,7 +538,7 @@ static int cmd_otp(void) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
uint16_t slot = (p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2; uint16_t slot = (p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2;
file_t *ef = file_search(slot); file_t *ef = search_dynamic_file(slot);
if (file_has_data(ef)) { if (file_has_data(ef)) {
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef); otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
if (!(otp_config->tkt_flags & CHAL_RESP)) { if (!(otp_config->tkt_flags & CHAL_RESP)) {
@@ -550,7 +550,7 @@ static int cmd_otp(void) {
status_byte = 0x20; status_byte = 0x20;
otp_status(_is_otp); otp_status(_is_otp);
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
if (button_wait()) { if (wait_button() == true) {
status_byte = 0x00; status_byte = 0x00;
otp_status(_is_otp); otp_status(_is_otp);
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
@@ -608,7 +608,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
static int otp_process_apdu(void) { int otp_process_apdu() {
if (CLA(apdu) != 0x00) { if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }
@@ -628,9 +628,11 @@ uint8_t otp_frame_tx[70] = {0};
uint8_t otp_exp_seq = 0, otp_curr_seq = 0; uint8_t otp_exp_seq = 0, otp_curr_seq = 0;
uint8_t otp_header[4] = {0}; uint8_t otp_header[4] = {0};
static int otp_send_frame(uint8_t *frame, size_t frame_len) { extern uint16_t *get_send_buffer_size(uint8_t itf);
int otp_send_frame(uint8_t *frame, size_t frame_len) {
uint16_t crc = calculate_crc(frame, frame_len); uint16_t crc = calculate_crc(frame, frame_len);
frame_len += put_uint16_le(~crc, frame + frame_len); frame_len += put_uint16_t_le(~crc, frame + frame_len);
*get_send_buffer_size(ITF_KEYBOARD) = frame_len; *get_send_buffer_size(ITF_KEYBOARD) = frame_len;
otp_exp_seq = (frame_len / 7); otp_exp_seq = (frame_len / 7);
if (frame_len % 7) { if (frame_len % 7) {
@@ -640,10 +642,7 @@ static int otp_send_frame(uint8_t *frame, size_t frame_len) {
return 0; return 0;
} }
static int otp_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { int otp_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
(void)itf;
(void)report_id;
(void)bufsize;
if (report_type == 3) { if (report_type == 3) {
DEBUG_PAYLOAD(buffer, bufsize); DEBUG_PAYLOAD(buffer, bufsize);
if (buffer[7] == 0xFF) { // reset if (buffer[7] == 0xFF) { // reset
@@ -661,7 +660,7 @@ static int otp_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type
if (rseq == 9) { if (rseq == 9) {
DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx)); DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx));
DEBUG_PAYLOAD(otp_frame_rx, sizeof(otp_frame_rx)); DEBUG_PAYLOAD(otp_frame_rx, sizeof(otp_frame_rx));
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_le(otp_frame_rx + 65); uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_t_le(otp_frame_rx + 65);
uint8_t slot_id = otp_frame_rx[64]; uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) { if (residual_crc == rcrc) {
uint8_t hdr[5]; uint8_t hdr[5];
@@ -691,11 +690,11 @@ static int otp_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type
return 0; return 0;
} }
static uint16_t otp_hid_get_report_cb(uint8_t itf, uint16_t otp_hid_get_report_cb(uint8_t itf,
uint8_t report_id, uint8_t report_id,
hid_report_type_t report_type, hid_report_type_t report_type,
uint8_t *buffer, uint8_t *buffer,
uint16_t reqlen) { uint16_t reqlen) {
// TODO not Implemented // TODO not Implemented
(void) itf; (void) itf;
(void) report_id; (void) report_id;

View File

@@ -18,7 +18,7 @@
#ifndef __VERSION_H_ #ifndef __VERSION_H_
#define __VERSION_H_ #define __VERSION_H_
#define PICO_FIDO_VERSION 0x0706 #define PICO_FIDO_VERSION 0x0704
#define PICO_FIDO_VERSION_MAJOR ((PICO_FIDO_VERSION >> 8) & 0xff) #define PICO_FIDO_VERSION_MAJOR ((PICO_FIDO_VERSION >> 8) & 0xff)
#define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff) #define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff)

View File

@@ -22,9 +22,6 @@ RUN apt install -y libccid \
cmake \ cmake \
libfuse-dev \ libfuse-dev \
python3-pyscard \ python3-pyscard \
libtss2-dev \
tpm2-tools \
swtpm \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN pip3 install pytest pycvc cryptography inputimeout fido2==2.0.0 --break-system-packages RUN pip3 install pytest pycvc cryptography inputimeout fido2==2.0.0 --break-system-packages
WORKDIR / WORKDIR /

View File

@@ -25,7 +25,6 @@ INS_PUT = 0x01
INS_DELETE = 0x02 INS_DELETE = 0x02
INS_SET_CODE = 0x03 INS_SET_CODE = 0x03
INS_RESET = 0x04 INS_RESET = 0x04
INS_RENAME = 0x05
INS_LIST = 0xa1 INS_LIST = 0xa1
INS_CALCULATE = 0xa2 INS_CALCULATE = 0xa2
INS_VALIDATE = 0xa3 INS_VALIDATE = 0xa3
@@ -90,24 +89,6 @@ def test_life(reset_oath):
resp = list_apdu(reset_oath) resp = list_apdu(reset_oath)
assert(len(resp) == 0) assert(len(resp) == 0)
def test_rename_prefix_extension(reset_oath):
old_name = b"30/test"
new_name = b"30/test2"
key = list(bytes(b"foo bar"))
put_data = [TAG_NAME, len(old_name)] + list(old_name)
put_data += [TAG_KEY, len(key) + 2, TYPE_TOTP | ALG_SHA1, 6] + key
send_apdu(reset_oath, INS_PUT, p1=0, p2=0, data=put_data)
rename_data = [TAG_NAME, len(old_name)] + list(old_name)
rename_data += [TAG_NAME, len(new_name)] + list(new_name)
send_apdu(reset_oath, INS_RENAME, p1=0, p2=0, data=rename_data)
resp = list_apdu(reset_oath)
exp = [TAG_NAME_LIST, len(new_name) + 1, TYPE_TOTP | ALG_SHA1] + list(new_name)
assert resp == exp
def test_overwrite(reset_oath): def test_overwrite(reset_oath):
data = data_name + data_key data = data_name + data_key
resp = send_apdu(reset_oath, INS_PUT, p1=0, p2=0, data=list(data)) resp = send_apdu(reset_oath, INS_PUT, p1=0, p2=0, data=list(data))

View File

@@ -22,13 +22,13 @@ cd ../..
mkdir build_pico mkdir build_pico
cd build_pico cd build_pico
cmake -DPICO_SDK_PATH=../pico-sdk .. cmake -DPICO_SDK_PATH=../pico-sdk ..
make make -j`nproc`
cd .. cd ..
elif [[ $1 == "esp32" ]]; then elif [[ $1 == "esp32" ]]; then
sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
git clone --recursive https://github.com/espressif/esp-idf.git git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf cd esp-idf
git checkout tags/v5.5 git checkout tags/v5.5.1
./install.sh esp32s3 ./install.sh esp32s3
. ./export.sh . ./export.sh
cd .. cd ..
@@ -49,7 +49,6 @@ cd build
esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_fido_esp32-s2.bin @flash_args esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_fido_esp32-s2.bin @flash_args
cd .. cd ..
else else
sudo apt install -y libtss2-dev tpm2-tools swtpm cmake
mkdir build mkdir build
cd build cd build
cmake -DENABLE_EMULATION=1 .. cmake -DENABLE_EMULATION=1 ..