mirror of
https://github.com/polhenarejos/pico-fido
synced 2026-06-05 20:39:06 +02:00
Compare commits
13 Commits
nightly-de
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab6cc09c08 | ||
|
|
cba1db783f | ||
|
|
9788029e8a | ||
|
|
dfd7927413 | ||
|
|
cfc23a1f0e | ||
|
|
a7630dca5c | ||
|
|
7f31e6a00f | ||
|
|
a1cb2fa3bf | ||
|
|
faceaf8fc6 | ||
|
|
c33b133c6b | ||
|
|
8036a5dda4 | ||
|
|
f3866c4a93 | ||
|
|
105cf61866 |
304
CMakeLists.txt
304
CMakeLists.txt
@@ -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()
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
Submodule pico-keys-sdk updated: 13d2e84595...12b4940662
@@ -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 ||
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
189
src/fido/fido.c
189
src/fido/fido.c
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
97
src/fido/kek.c
Normal 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
46
src/fido/kek.h
Normal 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
|
||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
292
src/fido/oath.c
292
src/fido/oath.c
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
151
src/fido/otp.c
151
src/fido/otp.c
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 /
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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 ..
|
||||||
|
|||||||
Reference in New Issue
Block a user