30 Commits

Author SHA1 Message Date
Pol Henarejos
c443dec4a0 Upgrade to version 6.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-10 01:50:22 +01:00
Pol Henarejos
8ae4ab5af4 Upgrade to version 5.12
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 20:21:58 +02:00
Pol Henarejos
d2c25b69bc Merge branch 'main' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 10:18:08 +02:00
Pol Henarejos
21765a6f10 Move pico-keys-sdk pointer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 13:10:58 +01:00
Pol Henarejos
eb2c92bc5c Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 13:01:10 +01:00
Pol Henarejos
233c5a7c7d Merge branch 'development' into eddsa 2023-09-18 09:33:56 +02:00
Pol Henarejos
3b4ac12d0f Merge branch 'development' into eddsa 2023-09-18 09:02:26 +02:00
Pol Henarejos
7c5bab8b05 Merge branch 'development' into eddsa 2023-09-18 01:38:39 +02:00
Pol Henarejos
21035d649d Upgrade to version 5.7
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 01:38:31 +02:00
Pol Henarejos
abe91823c0 Build firmwares with -eddsa1 suffix.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-17 19:29:54 +02:00
Pol Henarejos
91e049b997 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-17 19:28:41 +02:00
Pol Henarejos
8836902dc1 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-22 15:32:10 +02:00
Pol Henarejos
a019b54d69 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-22 13:27:35 +02:00
Pol Henarejos
3adb1a8422 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-21 19:12:51 +02:00
Pol Henarejos
95a9fe4214 Added flow triggering for eddsa branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:49:58 +02:00
Pol Henarejos
8af7cac57a Added authentication tests with EdDSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:48:12 +02:00
Pol Henarejos
7997eefdc8 Fixed EdDSA signature encapsulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:46:55 +02:00
Pol Henarejos
e18f841a34 Fix Edwards load key.
It did not compute the correct public point.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:46:37 +02:00
Pol Henarejos
73b51cabfc Merge branch 'development' into eddsa 2023-08-18 14:10:58 +02:00
Pol Henarejos
ad3b2bbe4b Added EdDSA credential creation test.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 13:07:52 +02:00
Pol Henarejos
b9ad8f4745 Merge branch 'development' into eddsa 2023-08-18 13:07:13 +02:00
Pol Henarejos
8242dc8d80 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 12:44:52 +02:00
Pol Henarejos
2f6e4d5568 Upgraded COSE key functions to accept EDDSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-17 01:40:22 +02:00
Pol Henarejos
911dab031e Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-17 01:36:35 +02:00
Pol Henarejos
3a71275bc8 Add EDDSA algorithm in get_info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 18:06:29 +02:00
Pol Henarejos
9f1e879efe Fix OTP applet selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 17:32:17 +02:00
Pol Henarejos
57bf97196d Updated readme.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 14:48:44 +02:00
Pol Henarejos
e8c8ce4d15 Adding support for EdDSA with Ed25519 curve.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 14:47:34 +02:00
Pol Henarejos
69d618cc6b Point to proper EdDSA branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 13:13:58 +02:00
Pol Henarejos
e057f17180 Using Pico HSM SDK EdDSA branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 13:07:01 +02:00
36 changed files with 422 additions and 683 deletions

View File

@@ -13,10 +13,10 @@ name: "CodeQL"
on: on:
push: push:
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
schedule: schedule:
- cron: '23 5 * * 4' - cron: '23 5 * * 4'
workflow_dispatch: workflow_dispatch:
@@ -36,7 +36,7 @@ jobs:
language: [ 'cpp', 'python' ] language: [ 'cpp', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
mode: [ 'pico', 'esp32', 'local' ] mode: [ 'pico', 'local' ]
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@@ -25,7 +25,6 @@ jobs:
run: | run: |
./workflows/autobuild.sh pico ./workflows/autobuild.sh pico
./build_pico_fido.sh ./build_pico_fido.sh
./workflows/autobuild.sh esp32
- name: Update nightly release - name: Update nightly release
uses: pyTooling/Actions/releaser@main uses: pyTooling/Actions/releaser@main
with: with:

View File

@@ -13,10 +13,10 @@ name: "Emulation and test"
on: on:
push: push:
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
schedule: schedule:
- cron: '23 5 * * 4' - cron: '23 5 * * 4'
workflow_dispatch: workflow_dispatch:

View File

@@ -18,15 +18,12 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
if(ESP_PLATFORM) if(ESP_PLATFORM)
set(DEBUG_APDU 1)
set(DENABLE_POWER_ON_RESET 0)
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src) set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else() else()
if(ENABLE_EMULATION) if(ENABLE_EMULATION)
else() else()
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
include(pico_sdk_import.cmake) include(pico_sdk_import.cmake)
endif() endif()
@@ -42,6 +39,14 @@ endif()
add_executable(pico_fido) add_executable(pico_fido)
endif() endif()
option(ENABLE_UP_BUTTON "Enable/disable user presence button" ON)
if(ENABLE_UP_BUTTON)
add_definitions(-DENABLE_UP_BUTTON=1)
message(STATUS "User presence with button: \t enabled")
else()
add_definitions(-DENABLE_UP_BUTTON=0)
message(STATUS "User presence with button: \t disabled")
endif(ENABLE_UP_BUTTON)
option(ENABLE_POWER_ON_RESET "Enable/disable power cycle on reset" ON) option(ENABLE_POWER_ON_RESET "Enable/disable power cycle on reset" ON)
if(ENABLE_POWER_ON_RESET) if(ENABLE_POWER_ON_RESET)
@@ -80,7 +85,6 @@ endif()
set(SOURCES ${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/kek.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c
@@ -112,7 +116,6 @@ endif()
set(USB_ITF_HID 1) set(USB_ITF_HID 1)
include(pico-keys-sdk/pico_keys_sdk_import.cmake) include(pico-keys-sdk/pico_keys_sdk_import.cmake)
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/fido/version.h" 1)
if(ESP_PLATFORM) if(ESP_PLATFORM)
project(pico_fido) project(pico_fido)
endif() endif()
@@ -158,6 +161,5 @@ if(ENABLE_EMULATION)
target_link_libraries(pico_fido PRIVATE pthread m) target_link_libraries(pico_fido PRIVATE pthread m)
else() 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) 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() endif()

View File

@@ -13,8 +13,8 @@ Pico FIDO includes the following features:
- User verification with PIN - User verification with PIN
- Discoverable credentials (resident keys) - Discoverable credentials (resident keys)
- Credential management - Credential management
- ECDSA authentication - ECDSA and EDDSA authentication
- Support for SECP256R1, SECP384R1, SECP521R1, and SECP256K1 curves - Support for SECP256R1, SECP384R1, SECP521R1, SECP256K1 and Ed25519 curves
- App registration and login - App registration and login
- Device selection - Device selection
- Support for vendor configuration - Support for vendor configuration

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="6" VERSION_MAJOR="6"
VERSION_MINOR="4" VERSION_MINOR="0-eddsa1"
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}"
@@ -11,13 +11,98 @@ rm -rf release/*
mkdir -p build_release mkdir -p build_release
mkdir -p release mkdir -p release
cd build_release cd build_release
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}"
board_dir=${PICO_SDK_PATH}/src/boards/include/boards for board in 0xcb_helios \
for board in "$board_dir"/* adafruit_feather_rp2040_usb_host \
adafruit_feather_rp2040 \
adafruit_itsybitsy_rp2040 \
adafruit_kb2040 \
adafruit_macropad_rp2040 \
adafruit_qtpy_rp2040 \
adafruit_trinkey_qt2040 \
amethyst_fpga \
archi \
arduino_nano_rp2040_connect \
cytron_maker_pi_rp2040 \
datanoisetv_rp2040_dsp \
eetree_gamekit_rp2040 \
garatronic_pybstick26_rp2040 \
gen4_rp2350_24 \
gen4_rp2350_24ct \
gen4_rp2350_24t \
gen4_rp2350_28 \
gen4_rp2350_28ct \
gen4_rp2350_28t \
gen4_rp2350_32 \
gen4_rp2350_32ct \
gen4_rp2350_32t \
gen4_rp2350_35 \
gen4_rp2350_35ct \
gen4_rp2350_35t \
hellbender_2350A_devboard \
ilabs_challenger_rp2350_bconnect \
ilabs_challenger_rp2350_wifi_ble \
ilabs_opendec02 \
melopero_perpetuo_rp2350_lora \
melopero_shake_rp2040 \
metrotech_xerxes_rp2040 \
net8086_usb_interposer \
nullbits_bit_c_pro \
phyx_rick_tny_rp2350 \
pi-plates_micropi \
pico \
pico_w \
pico2 \
pimoroni_badger2040 \
pimoroni_interstate75 \
pimoroni_keybow2040 \
pimoroni_motor2040 \
pimoroni_pga2040 \
pimoroni_pga2350 \
pimoroni_pico_plus2_rp2350 \
pimoroni_picolipo_4mb \
pimoroni_picolipo_16mb \
pimoroni_picosystem \
pimoroni_plasma2040 \
pimoroni_plasma2350 \
pimoroni_servo2040 \
pimoroni_tiny2040 \
pimoroni_tiny2040_2mb \
pimoroni_tiny2350 \
pololu_3pi_2040_robot \
pololu_zumo_2040_robot \
seeed_xiao_rp2040 \
seeed_xiao_rp2350 \
solderparty_rp2040_stamp \
solderparty_rp2040_stamp_carrier \
solderparty_rp2040_stamp_round_carrier \
solderparty_rp2350_stamp_xl \
solderparty_rp2350_stamp \
sparkfun_micromod \
sparkfun_promicro \
sparkfun_promicro_rp2350 \
sparkfun_thingplus \
switchscience_picossci2_conta_base \
switchscience_picossci2_dev_board \
switchscience_picossci2_micro \
switchscience_picossci2_rp2350_breakout \
switchscience_picossci2_tiny \
tinycircuits_thumby_color_rp2350 \
vgaboard \
waveshare_rp2040_lcd_0.96 \
waveshare_rp2040_lcd_1.28 \
waveshare_rp2040_one \
waveshare_rp2040_plus_4mb \
waveshare_rp2040_plus_16mb \
waveshare_rp2040_zero \
weact_studio_rp2040_2mb \
weact_studio_rp2040_4mb \
weact_studio_rp2040_8mb \
weact_studio_rp2040_16mb \
wiznet_w5100s_evb_pico
do do
board_name="$(basename -- $board .h)"
rm -rf * rm -rf *
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}" cmake .. -DPICO_BOARD=$board
make -j`nproc` make -j`nproc`
mv pico_fido.uf2 ../release/pico_fido_$board_name-$SUFFIX.uf2 mv pico_fido.uf2 ../release/pico_fido_$board-$SUFFIX.uf2
done done

View File

@@ -4,7 +4,6 @@
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1 IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
CONFIG_TINYUSB=y CONFIG_TINYUSB=y
CONFIG_TINYUSB_TASK_STACK_SIZE=16384
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv" CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"

View File

@@ -210,6 +210,9 @@ CborError COSE_key(mbedtls_ecp_keypair *key, CborEncoder *mapEncoderParent,
else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) { else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
alg = FIDO2_ALG_ECDH_ES_HKDF_256; alg = FIDO2_ALG_ECDH_ES_HKDF_256;
} }
else if (key->grp.id == MBEDTLS_ECP_DP_ED25519) {
alg = FIDO2_ALG_EDDSA;
}
return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder); return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder);
} }
CborError COSE_key_shared(mbedtls_ecdh_context *key, CborError COSE_key_shared(mbedtls_ecdh_context *key,

View File

@@ -37,7 +37,6 @@
#include "crypto_utils.h" #include "crypto_utils.h"
#include "pico_keys.h" #include "pico_keys.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;
@@ -280,21 +279,6 @@ int pinUvAuthTokenUsageTimerObserver() {
return 0; return 0;
} }
int check_mkek_encrypted(const uint8_t *dhash) {
if (file_get_size(ef_mkek) == MKEK_IV_SIZE + MKEK_KEY_SIZE) {
hash_multi(dhash, 16, session_pin); // Only for storing MKEK
uint8_t mkek[MKEK_SIZE] = {0};
memcpy(mkek, file_get_data(ef_mkek), MKEK_IV_SIZE + MKEK_KEY_SIZE);
int ret = store_mkek(mkek);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
mbedtls_platform_zeroize(session_pin, sizeof(session_pin));
if (ret != PICOKEY_OK) {
return CTAP2_ERR_PIN_AUTH_INVALID;
}
}
return PICOKEY_OK;
}
uint8_t new_pin_mismatches = 0; uint8_t new_pin_mismatches = 0;
int cbor_client_pin(const uint8_t *data, size_t len) { int cbor_client_pin(const uint8_t *data, size_t len) {
@@ -431,20 +415,12 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
if (pin_len < minPin) { if (pin_len < minPin) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
} }
uint8_t hsh[34], dhash[32]; uint8_t hsh[34];
hsh[0] = MAX_PIN_RETRIES; hsh[0] = MAX_PIN_RETRIES;
hsh[1] = pin_len; hsh[1] = pin_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, hsh + 2);
double_hash_pin(dhash, 16, hsh + 2); file_put_data(ef_pin, hsh, 2 + 16);
file_put_data(ef_pin, hsh, 2 + 32);
low_flash_available(); low_flash_available();
ret = check_mkek_encrypted(dhash);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
mbedtls_platform_zeroize(hsh, sizeof(hsh));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
goto err; //No return goto err; //No return
} }
else if (subcommand == 0x4) { //changePIN else if (subcommand == 0x4) { //changePIN
@@ -486,8 +462,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
uint8_t pin_data[34]; uint8_t pin_data[18];
memcpy(pin_data, file_get_data(ef_pin), 34); memcpy(pin_data, file_get_data(ef_pin), 18);
pin_data[0] -= 1; pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
@@ -498,9 +474,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
uint8_t dhash[32]; if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
double_hash_pin(paddedNewPin, 16, dhash);
if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
@@ -514,7 +488,6 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
} }
hash_multi(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));
low_flash_available(); low_flash_available();
@@ -542,33 +515,12 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
uint8_t hsh[34]; uint8_t hsh[34];
hsh[0] = MAX_PIN_RETRIES; hsh[0] = MAX_PIN_RETRIES;
hsh[1] = pin_len; hsh[1] = pin_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, hsh + 2);
double_hash_pin(dhash, 16, hsh + 2);
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 &&
memcmp(hsh + 2, file_get_data(ef_pin) + 2, 32) == 0) { memcmp(hsh + 2, file_get_data(ef_pin) + 2, 16) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
} }
file_put_data(ef_pin, hsh, 2 + 16);
uint8_t mkek[MKEK_SIZE] = {0};
ret = load_mkek(mkek);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
file_put_data(ef_pin, hsh, 2 + 32);
ret = check_mkek_encrypted(dhash);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
hash_multi(dhash, 16, session_pin);
ret = store_mkek(mkek);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
mbedtls_platform_zeroize(hsh, sizeof(hsh));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
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) {
uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin)); uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin));
memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin)); memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin));
@@ -618,8 +570,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
uint8_t pin_data[34]; uint8_t pin_data[18];
memcpy(pin_data, file_get_data(ef_pin), 34); memcpy(pin_data, file_get_data(ef_pin), 18);
pin_data[0] -= 1; pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
@@ -630,9 +582,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
uint8_t dhash[32]; if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
double_hash_pin(paddedNewPin, 16, dhash);
if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
@@ -646,19 +596,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
} }
ret = check_mkek_encrypted(paddedNewPin);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
hash_multi(paddedNewPin, 16, session_pin);
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
new_pin_mismatches = 0; new_pin_mismatches = 0;
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(dhash, sizeof(dhash));
low_flash_available(); low_flash_available();
file_t *ef_minpin = 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) {

View File

@@ -246,9 +246,14 @@ int cbor_config(const uint8_t *data, size_t len) {
else { else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
} }
if (phy_save() != PICOKEY_OK) { uint8_t tmp[PHY_MAX_SIZE];
uint16_t tmp_len = 0;
memset(tmp, 0, sizeof(tmp));
if (phy_serialize_data(&phy_data, tmp, &tmp_len) != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
} }
#endif #endif
else { else {

View File

@@ -279,8 +279,6 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
} }
bool silent = (up == false && uv == false);
if (allowList_len > 0) { if (allowList_len > 0) {
for (size_t e = 0; e < allowList_len; e++) { for (size_t e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) { if (allowList[e].type.present == false || allowList[e].id.present == false) {
@@ -290,6 +288,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
continue; continue;
} }
if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash, &creds[creds_len]) != 0) { if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash, &creds[creds_len]) != 0) {
CBOR_FREE_BYTE_STRING(allowList[e].id);
credential_free(&creds[creds_len]); credential_free(&creds[creds_len]);
} }
else { else {
@@ -343,32 +342,15 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
} }
if (numberOfCredentials == 0) { if (numberOfCredentials == 0) {
if (silent && allowList_len > 0) { CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
for (size_t e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (strcmp(allowList[e].type.data, "public-key") != 0) {
continue;
}
if (credential_verify(allowList[e].id.data, allowList[e].id.len, rp_id_hash, true) == 0) {
numberOfCredentials++;
}
}
}
if (numberOfCredentials == 0) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
}
} }
if (!silent) { for (int i = 0; i < numberOfCredentials; i++) {
for (int i = 0; i < numberOfCredentials; i++) { for (int j = i + 1; j < numberOfCredentials; j++) {
for (int j = i + 1; j < numberOfCredentials; j++) { if (creds[j].creation > creds[i].creation) {
if (creds[j].creation > creds[i].creation) { Credential tmp = creds[j];
Credential tmp = creds[j]; creds[j] = creds[i];
creds[j] = creds[i]; creds[i] = tmp;
creds[i] = tmp;
}
} }
} }
} }
@@ -398,8 +380,8 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
} }
if (silent && !resident) { if (up == false && uv == false) {
// Silent authentication, do nothing selcred = &creds[0];
} }
else { else {
selcred = &creds[0]; selcred = &creds[0];
@@ -428,18 +410,16 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
int ret = 0; int ret = 0;
uint8_t largeBlobKey[32] = {0}; uint8_t largeBlobKey[32] = {0};
if (selcred) { if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey);
ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey); if (ret != 0) {
if (ret != 0) { CBOR_ERROR(CTAP2_ERR_PROCESSING);
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
} }
} }
size_t ext_len = 0; size_t ext_len = 0;
uint8_t ext[512] = {0}; uint8_t ext[512] = {0};
if (selcred && extensions.present == true) { if (extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0); cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0; int l = 0;
if (options.up == pfalse) { if (options.up == pfalse) {
@@ -539,7 +519,10 @@ 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_t_be(ctr, pa); *pa++ = (ctr >> 24) & 0xFF;
*pa++ = (ctr >> 16) & 0xFF;
*pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xFF;
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);
@@ -550,39 +533,43 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_ecdsa_context ekey; mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecdsa_init(&ekey);
ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey);
if (ret != 0) {
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
}
if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
}
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
}
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
size_t olen = 0; size_t olen = 0;
if (selcred) { if (md != NULL) {
ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey);
if (ret != 0) {
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
}
if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
}
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
}
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_gen, 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);
} }
else { else {
// Bogus signature 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);
olen = 64; }
memset(sig, 0x0B, olen); mbedtls_ecp_keypair_free(&ekey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
mbedtls_ecdsa_free(&ekey);
uint8_t lfields = 3; uint8_t lfields = 3;
if (selcred && selcred->opts.present == true && selcred->opts.rk == ptrue) { if (selcred->opts.present == true && selcred->opts.rk == ptrue) {
lfields++; lfields++;
} }
if (numberOfCredentials > 1 && next == false) { if (numberOfCredentials > 1 && next == false) {
lfields++; lfields++;
} }
if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
lfields++; lfields++;
} }
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);
@@ -591,12 +578,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 2)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 2));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id"));
if (selcred) { CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->id.data, selcred->id.len));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->id.data, selcred->id.len));
}
else {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, (uint8_t *)"\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01", 16));
}
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "type")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "type"));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "public-key")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "public-key"));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -606,7 +588,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, sig, olen)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, sig, olen));
if (selcred && selcred->opts.present == true && selcred->opts.rk == ptrue) { if (selcred->opts.present == true && selcred->opts.rk == ptrue) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
uint8_t lu = 1; uint8_t lu = 1;
if (numberOfCredentials > 1 && allowList_len == 0) { if (numberOfCredentials > 1 && allowList_len == 0) {
@@ -637,7 +619,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials));
} }
if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x07)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x07));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey)));
} }

View File

@@ -90,11 +90,14 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 4));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 5));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_EDDSA, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES384, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES384, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));

View File

@@ -129,7 +129,10 @@ 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_t_le(offset, verify_data + 34); verify_data[34] = offset & 0xFF;
verify_data[35] = (offset >> 8) & 0xFF;
verify_data[36] = (offset >> 16) & 0xFF;
verify_data[37] = (offset >> 24) & 0xFF;
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);

View File

@@ -221,6 +221,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (curve <= 0) { if (curve <= 0) {
curve = FIDO2_CURVE_P256K1; curve = FIDO2_CURVE_P256K1;
} }
}
else if (pubKeyCredParams[i].alg == FIDO2_ALG_EDDSA) {
if (curve <= 0) {
curve = FIDO2_CURVE_ED25519;
}
} }
else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) { else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass // pass
@@ -286,7 +291,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) { if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) {
continue; continue;
} }
Credential ecred = {0}; Credential ecred;
if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash, if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash,
&ecred) == 0 && &ecred) == 0 &&
(ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED || (ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED ||
@@ -385,16 +390,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
ext_len = cbor_encoder_get_buffer_size(&encoder, ext); ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED; flags |= FIDO2_AUT_FLAG_ED;
} }
mbedtls_ecdsa_context ekey; mbedtls_ecp_keypair ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
int ret = fido_load_key(curve, cred_id, &ekey); int ret = fido_load_key(curve, cred_id, &ekey);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id); const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id);
if (cinfo == NULL) { if (cinfo == NULL) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
size_t olen = 0; size_t olen = 0;
@@ -409,14 +414,18 @@ 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_t_be(ctr, pa); *pa++ = (ctr >> 24) & 0xFF;
*pa++ = (ctr >> 16) & 0xFF;
*pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xFF;
memcpy(pa, aaguid, 16); pa += 16; memcpy(pa, aaguid, 16); pa += 16;
pa += put_uint16_t_be(cred_id_len, pa); *pa++ = ((uint16_t)cred_id_len >> 8) & 0xFF;
*pa++ = (uint16_t)cred_id_len & 0xFF;
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;
memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len; memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) { if ((size_t)(pa - aut_data) != aut_data_len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
@@ -429,12 +438,17 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) { else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
} }
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash); else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
if (md != NULL) {
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
}
bool self_attestation = true; bool self_attestation = true;
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) { if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
uint8_t key[32] = {0}; uint8_t key[32] = {0};
if (load_keydev(key) != 0) { if (load_keydev(key) != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
@@ -444,8 +458,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
self_attestation = false; self_attestation = false;
} }
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL); if (md != NULL) {
mbedtls_ecdsa_free(&ekey); ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
}
else {
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);
}
mbedtls_ecp_keypair_free(&ekey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) { if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) {
if (memcmp(user.parent.name.data, "+pico", 5) == 0) { if (memcmp(user.parent.name.data, "+pico", 5) == 0) {
@@ -455,13 +477,14 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (memcmp(p, "CommissionProfile", 17) == 0) { if (memcmp(p, "CommissionProfile", 17) == 0) {
ret = phy_unserialize_data(user.id.data, user.id.len, &phy_data); ret = phy_unserialize_data(user.id.data, user.id.len, &phy_data);
if (ret == PICOKEY_OK) { if (ret == PICOKEY_OK) {
ret = phy_save(); file_put_data(ef_phy, user.id.data, user.id.len);
} }
} }
#endif #endif
if (ret != PICOKEY_OK) { if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
low_flash_available();
} }
} }

View File

@@ -24,14 +24,13 @@
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#endif #endif
#include "fs/phy.h"
extern void scan_all(); extern void scan_all();
int cbor_reset() { 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 (board_millis() > 10000) {
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
#endif #endif

View File

@@ -255,7 +255,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint16_t opts = 0; uint16_t opts = 0;
if (file_has_data(ef_phy)) { if (file_has_data(ef_phy)) {
uint8_t *data = file_get_data(ef_phy); uint8_t *data = file_get_data(ef_phy);
opts = get_uint16_t_be(data + PHY_OPTS); opts = (data[PHY_OPTS] << 8) | data[PHY_OPTS+1];
} }
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
@@ -266,24 +266,6 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
} }
} }
#endif #endif
else if (cmd == CTAP_VENDOR_MEMORY) {
if (vendorCmd == 0x01) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 5));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_free_space()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_used_space()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_total_space()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_num_files()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_size()));
}
else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
}
else { else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
} }

View File

@@ -43,7 +43,7 @@ int cmd_authenticate() {
int ret = 0; int ret = 0;
uint8_t *tmp_kh = (uint8_t *) calloc(1, req->keyHandleLen); uint8_t *tmp_kh = (uint8_t *) calloc(1, req->keyHandleLen);
memcpy(tmp_kh, req->keyHandle, req->keyHandleLen); memcpy(tmp_kh, req->keyHandle, req->keyHandleLen);
if (credential_verify(tmp_kh, req->keyHandleLen, req->appId, false) == 0) { if (credential_verify(tmp_kh, req->keyHandleLen, req->appId) == 0) {
ret = fido_load_key(FIDO2_CURVE_P256, req->keyHandle, &key); ret = fido_load_key(FIDO2_CURVE_P256, req->keyHandle, &key);
} }
else { else {
@@ -66,7 +66,10 @@ int cmd_authenticate() {
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_t_be(ctr, resp->ctr); resp->ctr[0] = (ctr >> 24) & 0xFF;
resp->ctr[1] = (ctr >> 16) & 0xFF;
resp->ctr[2] = (ctr >> 8) & 0xFF;
resp->ctr[3] = ctr & 0xFF;
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));

View File

@@ -27,52 +27,22 @@
#include "random.h" #include "random.h"
#include "files.h" #include "files.h"
#include "pico_keys.h" #include "pico_keys.h"
#include "otp.h"
int credential_derive_chacha_key(uint8_t *outk, const uint8_t *); int credential_derive_chacha_key(uint8_t *outk);
static int credential_silent_tag(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) { int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) {
if (otp_key_1) {
memcpy(outk, otp_key_1, 32);
}
else {
mbedtls_sha256(pico_serial.id, PICO_UNIQUE_BOARD_ID_SIZE_BYTES, outk, 0);
}
return mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, cred_id, cred_id_len - CRED_SILENT_TAG_LEN, outk);
}
int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, bool silent) {
if (cred_id_len < 4 + 12 + 16) { if (cred_id_len < 4 + 12 + 16) {
return -1; return -1;
} }
uint8_t key[32] = {0}, *iv = cred_id + CRED_PROTO_LEN, *cipher = cred_id + CRED_PROTO_LEN + CRED_IV_LEN, uint8_t key[32], *iv = cred_id + 4, *cipher = cred_id + 4 + 12,
*tag = cred_id + cred_id_len - CRED_TAG_LEN; *tag = cred_id + cred_id_len - 16;
cred_proto_t proto = CRED_PROTO_21; memset(key, 0, sizeof(key));
if (memcmp(cred_id, CRED_PROTO_22_S, CRED_PROTO_LEN) == 0) { // New format credential_derive_chacha_key(key);
tag = cred_id + cred_id_len - CRED_SILENT_TAG_LEN - CRED_TAG_LEN; mbedtls_chachapoly_context chatx;
proto = CRED_PROTO_22; mbedtls_chachapoly_init(&chatx);
} mbedtls_chachapoly_setkey(&chatx, key);
int ret = 0; int ret = mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - (4 + 12 + 16), iv, rp_id_hash, 32, tag, cipher, cipher);
if (!silent) { mbedtls_chachapoly_free(&chatx);
int hdr_len = CRED_PROTO_LEN + CRED_IV_LEN + CRED_TAG_LEN;
if (proto == CRED_PROTO_22) {
hdr_len += CRED_SILENT_TAG_LEN;
}
credential_derive_chacha_key(key, cred_id);
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key);
ret = mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - hdr_len, iv, rp_id_hash, 32, tag, cipher, cipher);
mbedtls_chachapoly_free(&chatx);
}
else {
if (proto <= CRED_PROTO_21) {
return -1;
}
uint8_t outk[32];
ret = credential_silent_tag(cred_id, cred_id_len, outk);
ret = memcmp(outk, cred_id + cred_id_len - CRED_SILENT_TAG_LEN, CRED_SILENT_TAG_LEN);
}
return ret; return ret;
} }
@@ -143,25 +113,25 @@ int credential_create(CborCharString *rpId,
} }
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
size_t rs = cbor_encoder_get_buffer_size(&encoder, cred_id); size_t rs = cbor_encoder_get_buffer_size(&encoder, cred_id);
*cred_id_len = CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN + CRED_SILENT_TAG_LEN; *cred_id_len = 4 + 12 + rs + 16;
uint8_t key[32] = {0}; uint8_t key[32];
credential_derive_chacha_key(key, (const uint8_t *)CRED_PROTO); memset(key, 0, sizeof(key));
uint8_t iv[CRED_IV_LEN] = {0}; credential_derive_chacha_key(key);
uint8_t iv[12];
random_gen(NULL, 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);
int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32, int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32,
cred_id + CRED_PROTO_LEN + CRED_IV_LEN, cred_id + 4 + 12,
cred_id + CRED_PROTO_LEN + CRED_IV_LEN, cred_id + 4 + 12,
cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs); cred_id + 4 + 12 + rs);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
memcpy(cred_id, CRED_PROTO, CRED_PROTO_LEN); memcpy(cred_id, CRED_PROTO, 4);
memcpy(cred_id + CRED_PROTO_LEN, iv, CRED_IV_LEN); memcpy(cred_id + 4, iv, 12);
credential_silent_tag(cred_id, *cred_id_len, cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN);
err: err:
if (error != CborNoError) { if (error != CborNoError) {
@@ -177,12 +147,8 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
int ret = 0; int ret = 0;
CborError error = CborNoError; CborError error = CborNoError;
uint8_t *copy_cred_id = (uint8_t *) calloc(1, cred_id_len); uint8_t *copy_cred_id = (uint8_t *) calloc(1, cred_id_len);
if (!cred) {
CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL);
}
memset(cred, 0, sizeof(Credential));
memcpy(copy_cred_id, cred_id, cred_id_len); memcpy(copy_cred_id, cred_id, cred_id_len);
ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash, false); ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash);
if (ret != 0) { // U2F? if (ret != 0) { // U2F?
if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) { if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) {
CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL); CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL);
@@ -270,19 +236,17 @@ err:
} }
void credential_free(Credential *cred) { void credential_free(Credential *cred) {
if (cred) { CBOR_FREE_BYTE_STRING(cred->rpId);
CBOR_FREE_BYTE_STRING(cred->rpId); CBOR_FREE_BYTE_STRING(cred->userId);
CBOR_FREE_BYTE_STRING(cred->userId); CBOR_FREE_BYTE_STRING(cred->userName);
CBOR_FREE_BYTE_STRING(cred->userName); CBOR_FREE_BYTE_STRING(cred->userDisplayName);
CBOR_FREE_BYTE_STRING(cred->userDisplayName); CBOR_FREE_BYTE_STRING(cred->id);
CBOR_FREE_BYTE_STRING(cred->id); if (cred->extensions.present) {
if (cred->extensions.present) { CBOR_FREE_BYTE_STRING(cred->extensions.credBlob);
CBOR_FREE_BYTE_STRING(cred->extensions.credBlob);
}
cred->present = false;
cred->extensions.present = false;
cred->opts.present = false;
} }
cred->present = false;
cred->extensions.present = false;
cred->opts.present = false;
} }
int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) { int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) {
@@ -380,13 +344,13 @@ int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) cred_id, CRED_PROTO_LEN, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "hmac-secret", 11, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "hmac-secret", 11, outk);
mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk); mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk);
return 0; return 0;
} }
int credential_derive_chacha_key(uint8_t *outk, const uint8_t *proto) { int credential_derive_chacha_key(uint8_t *outk) {
memset(outk, 0, 32); memset(outk, 0, 32);
int r = 0; int r = 0;
if ((r = load_keydev(outk)) != 0) { if ((r = load_keydev(outk)) != 0) {
@@ -395,7 +359,7 @@ int credential_derive_chacha_key(uint8_t *outk, const uint8_t *proto) {
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) (proto ? proto : (const uint8_t *)CRED_PROTO), CRED_PROTO_LEN, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "Encryption key", 14, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "Encryption key", 14, outk);
return 0; return 0;
} }
@@ -409,7 +373,7 @@ int credential_derive_large_blob_key(const uint8_t *cred_id, size_t cred_id_len,
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) cred_id, CRED_PROTO_LEN, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "largeBlobKey", 12, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "largeBlobKey", 12, outk);
mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk); mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk);
return 0; return 0;

View File

@@ -56,23 +56,9 @@ typedef struct Credential {
#define CRED_PROT_UV_OPTIONAL_WITH_LIST 0x02 #define CRED_PROT_UV_OPTIONAL_WITH_LIST 0x02
#define CRED_PROT_UV_REQUIRED 0x03 #define CRED_PROT_UV_REQUIRED 0x03
#define CRED_PROTO_21_S "\xf1\xd0\x02\x01" #define CRED_PROTO "\xf1\xd0\x02\x01"
#define CRED_PROTO_22_S "\xf1\xd0\x02\x02"
#define CRED_PROTO CRED_PROTO_22_S extern int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash);
#define CRED_PROTO_LEN 4
#define CRED_IV_LEN 12
#define CRED_TAG_LEN 16
#define CRED_SILENT_TAG_LEN 16
typedef enum
{
CRED_PROTO_21 = 0x01,
CRED_PROTO_22 = 0x02,
} cred_proto_t;
extern int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, bool silent);
extern int credential_create(CborCharString *rpId, extern int credential_create(CborCharString *rpId,
CborByteString *userId, CborByteString *userId,
CborCharString *userName, CborCharString *userName,

View File

@@ -126,7 +126,6 @@ typedef struct {
#define CTAP_VENDOR_UNLOCK 0x03 #define CTAP_VENDOR_UNLOCK 0x03
#define CTAP_VENDOR_EA 0x04 #define CTAP_VENDOR_EA 0x04
#define CTAP_VENDOR_PHY_OPTS 0x05 #define CTAP_VENDOR_PHY_OPTS 0x05
#define CTAP_VENDOR_MEMORY 0x06
#define CTAP_PERMISSION_MC 0x01 // MakeCredential #define CTAP_PERMISSION_MC 0x01 // MakeCredential
#define CTAP_PERMISSION_GA 0x02 // GetAssertion #define CTAP_PERMISSION_GA 0x02 // GetAssertion

View File

@@ -16,7 +16,6 @@
*/ */
#include "fido.h" #include "fido.h"
#include "kek.h"
#include "pico_keys.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
@@ -47,7 +46,6 @@ pinUvAuthToken_t paut = { 0 };
uint8_t keydev_dec[32]; uint8_t keydev_dec[32];
bool has_keydev_dec = false; bool has_keydev_dec = false;
uint8_t session_pin[32] = { 0 };
const uint8_t fido_aid[] = { const uint8_t fido_aid[] = {
8, 8,
@@ -112,6 +110,12 @@ mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
else if (curve == FIDO2_CURVE_X448) { else if (curve == FIDO2_CURVE_X448) {
return MBEDTLS_ECP_DP_CURVE448; return MBEDTLS_ECP_DP_CURVE448;
} }
else if (curve == FIDO2_CURVE_ED25519) {
return MBEDTLS_ECP_DP_ED25519;
}
else if (curve == FIDO2_CURVE_ED448) {
return MBEDTLS_ECP_DP_ED448;
}
return MBEDTLS_ECP_DP_NONE; return MBEDTLS_ECP_DP_NONE;
} }
int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) { int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
@@ -133,10 +137,16 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
else if (id == MBEDTLS_ECP_DP_CURVE448) { else if (id == MBEDTLS_ECP_DP_CURVE448) {
return FIDO2_CURVE_X448; return FIDO2_CURVE_X448;
} }
else if (id == MBEDTLS_ECP_DP_ED25519) {
return FIDO2_CURVE_ED25519;
}
else if (id == MBEDTLS_ECP_DP_ED448) {
return FIDO2_CURVE_ED448;
}
return 0; return 0;
} }
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) { int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key) {
mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve); mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve);
if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) { if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) {
return CTAP2_ERR_UNSUPPORTED_ALGORITHM; return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
@@ -190,19 +200,16 @@ int load_keydev(uint8_t *key) {
} }
else { else {
memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev)); memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev));
if (mkek_decrypt(key, 32) != PICOKEY_OK) {
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) { 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; return PICOKEY_EXEC_ERROR;
} }
} }
//return mkek_decrypt(key, file_get_size(ef_keydev));
return PICOKEY_OK; return PICOKEY_OK;
} }
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) { int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) {
for (int i = 0; i < KEY_PATH_ENTRIES; i++) { for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)]; uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
if (!(k & 0x80000000)) { if (!(k & 0x80000000)) {
@@ -235,7 +242,7 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac)); return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac));
} }
int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecdsa_context *key) { int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecp_keypair *key) {
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));
@@ -280,6 +287,9 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (r != 0) { if (r != 0) {
return r; return r;
} }
if (curve == MBEDTLS_ECP_DP_ED25519) {
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
}
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL); 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));
@@ -289,7 +299,6 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
int scan_files() { int scan_files() {
ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF); ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF);
ef_keydev_enc = 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...");
@@ -322,33 +331,13 @@ int scan_files() {
else { else {
printf("FATAL ERROR: KEY DEV not found in memory!\r\n"); printf("FATAL ERROR: KEY DEV not found in memory!\r\n");
} }
if (ef_mkek) { // No encrypted MKEK
if (!file_has_data(ef_mkek)) {
uint8_t mkek[MKEK_IV_SIZE + MKEK_KEY_SIZE];
random_gen(NULL, mkek, sizeof(mkek));
file_put_data(ef_mkek, mkek, sizeof(mkek));
int ret = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), file_get_data(ef_keydev), 32);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
if (ret != 0) {
printf("FATAL ERROR: MKEK encryption failed!\r\n");
}
}
}
else {
printf("FATAL ERROR: MKEK not found in memory!\r\n");
}
ef_certdev = 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];
memset(outk, 0, sizeof(outk));
int ret = 0;
if ((ret = load_keydev(outk)) != 0) {
return ret;
}
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, outk, sizeof(outk)); int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), file_get_size(ef_keydev));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return ret; return ret;
@@ -380,13 +369,6 @@ int scan_files() {
printf("FATAL ERROR: Global counter not found in memory!\r\n"); printf("FATAL ERROR: Global counter not found in memory!\r\n");
} }
ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF); ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF);
if (file_get_size(ef_pin) == 18) { // Upgrade PIN storage
uint8_t pin_data[34] = { 0 }, dhash[32];
memcpy(pin_data, file_get_data(ef_pin), 18);
double_hash_pin(pin_data + 2, 16, dhash);
memcpy(pin_data + 2, dhash, 32);
file_put_data(ef_pin, pin_data, 34);
}
ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF); ef_authtoken = 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)) {
@@ -404,7 +386,6 @@ int scan_files() {
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);
} }
low_flash_available(); low_flash_available();
return PICOKEY_OK; return PICOKEY_OK;
} }
@@ -423,10 +404,12 @@ void init_fido() {
bool wait_button_pressed() { bool wait_button_pressed() {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1
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); } while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
#endif
#endif #endif
return val == EV_BUTTON_TIMEOUT; return val == EV_BUTTON_TIMEOUT;
} }
@@ -434,18 +417,21 @@ bool wait_button_pressed() {
uint32_t user_present_time_limit = 0; uint32_t user_present_time_limit = 0;
bool check_user_presence() { bool check_user_presence() {
if (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) { #if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1
if (user_present_time_limit == 0 ||
user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
if (wait_button_pressed() == true) { //timeout if (wait_button_pressed() == true) { //timeout
return false; return false;
} }
//user_present_time_limit = board_millis(); //user_present_time_limit = board_millis();
} }
#endif
return true; return true;
} }
uint32_t get_sign_counter() { uint32_t get_sign_counter() {
uint8_t *caddr = file_get_data(ef_counter); uint8_t *caddr = file_get_data(ef_counter);
return get_uint32_t_le(caddr); return (*caddr) | (*(caddr + 1) << 8) | (*(caddr + 2) << 16) | (*(caddr + 3) << 24);
} }
uint8_t get_opts() { uint8_t get_opts() {

View File

@@ -28,6 +28,7 @@
#endif #endif
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "mbedtls/eddsa.h"
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#else #else
@@ -45,13 +46,13 @@ 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_ecdsa_context *key); mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *); extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
extern bool wait_button_pressed(); extern bool wait_button_pressed();
extern void init_fido(); extern void init_fido();
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_ecdsa_context *key); extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key);
extern int load_keydev(uint8_t *key); extern int load_keydev(uint8_t *key);
extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
@@ -130,6 +131,4 @@ extern uint32_t user_present_time_limit;
extern pinUvAuthToken_t paut; extern pinUvAuthToken_t paut;
extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign); extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign);
extern uint8_t session_pin[32];
#endif //_FIDO_H #endif //_FIDO_H

View File

@@ -18,20 +18,39 @@
#include "files.h" #include "files.h"
file_t file_entries[] = { 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,
{ .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 .ef_structure = 0, .acl = { 0 } }, // MF
{ .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, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
{ .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 .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key
{ .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_KEY_DEV_ENC, .parent = 0, .name = NULL,
{ .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 .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
{ .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 .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN { .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH { .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL,
{ .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 .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
{ .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 .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate
{ .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_COUNTER, .parent = 0, .name = NULL,
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, .ef_structure = 0, .acl = { 0 } } //end .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH
{ .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_OTP_PIN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
.ef_structure = 0, .acl = { 0 } } //end
}; };
const file_t *MF = &file_entries[0]; const file_t *MF = &file_entries[0];
@@ -43,4 +62,3 @@ file_t *ef_pin = NULL;
file_t *ef_authtoken = NULL; file_t *ef_authtoken = NULL;
file_t *ef_keydev_enc = NULL; file_t *ef_keydev_enc = NULL;
file_t *ef_largeblob = NULL; file_t *ef_largeblob = NULL;
file_t *ef_mkek = NULL;

View File

@@ -22,7 +22,6 @@
#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
@@ -47,6 +46,5 @@ extern file_t *ef_pin;
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_

View File

@@ -1,137 +0,0 @@
/*
* 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 General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "fido.h"
#include "pico_keys.h"
#include "stdlib.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_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 store_mkek(const uint8_t *mkek) {
uint8_t tmp_mkek[MKEK_SIZE];
if (mkek == NULL) {
const uint8_t *rd = random_bytes_get(MKEK_IV_SIZE + MKEK_KEY_SIZE);
memcpy(tmp_mkek, rd, MKEK_IV_SIZE + MKEK_KEY_SIZE);
}
else {
memcpy(tmp_mkek, mkek, MKEK_SIZE);
}
if (otp_key_1) {
mkek_masked(tmp_mkek, otp_key_1);
}
*(uint32_t *) MKEK_CHECKSUM(tmp_mkek) = crc32c(MKEK_KEY(tmp_mkek), MKEK_KEY_SIZE);
uint8_t tmp_mkek_pin[MKEK_SIZE];
memcpy(tmp_mkek_pin, tmp_mkek, MKEK_SIZE);
file_t *tf = search_file(EF_MKEK);
if (!tf) {
release_mkek(tmp_mkek);
release_mkek(tmp_mkek_pin);
return PICOKEY_ERR_FILE_NOT_FOUND;
}
aes_encrypt_cfb_256(session_pin, MKEK_IV(tmp_mkek_pin), MKEK_KEY(tmp_mkek_pin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
file_put_data(tf, tmp_mkek_pin, MKEK_SIZE);
release_mkek(tmp_mkek_pin);
low_flash_available();
release_mkek(tmp_mkek);
return PICOKEY_OK;
}
int mkek_encrypt(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_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len);
release_mkek(mkek);
return r;
}
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;
}

View File

@@ -1,46 +0,0 @@
/*
* 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 General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KEK_H_
#define _KEK_H_
#include "crypto_utils.h"
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#include <stdbool.h>
#endif
extern int load_mkek(uint8_t *);
extern int store_mkek(const uint8_t *);
extern void init_mkek();
extern void release_mkek(uint8_t *);
extern int mkek_encrypt(uint8_t *data, uint16_t len);
extern int mkek_decrypt(uint8_t *data, uint16_t len);
#define MKEK_IV_SIZE (IV_SIZE)
#define MKEK_KEY_SIZE (32)
#define MKEK_KEY_CS_SIZE (4)
#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE)
#define MKEK_IV(p) (p)
#define MKEK_KEY(p) (MKEK_IV(p) + MKEK_IV_SIZE)
#define MKEK_CHECKSUM(p) (MKEK_KEY(p) + MKEK_KEY_SIZE)
#define DKEK_KEY_SIZE (32)
extern uint8_t mkek_mask[MKEK_KEY_SIZE];
extern bool has_mkek_mask;
#endif

View File

@@ -65,7 +65,7 @@ bool cap_supported(uint16_t cap) {
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_t_be(tag_data); ecaps = (tag_data[0] << 8) | tag_data[1];
} }
return ecaps & cap; return ecaps & cap;
} }
@@ -94,6 +94,9 @@ int man_get_config() {
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = TAG_NFC_SUPPORTED;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = 0x00;
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
res_APDU[res_APDU_size++] = TAG_USB_ENABLED; res_APDU[res_APDU_size++] = TAG_USB_ENABLED;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
@@ -105,6 +108,9 @@ int man_get_config() {
res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK; res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
res_APDU[res_APDU_size++] = TAG_NFC_ENABLED;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = 0x00;
} }
else { else {
memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef)); memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef));

View File

@@ -395,7 +395,15 @@ int cmd_calculate() {
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_t_be(chal.data); uint64_t v =
((uint64_t) chal.data[0] << 56) |
((uint64_t) chal.data[1] << 48) |
((uint64_t) chal.data[2] << 40) |
((uint64_t) chal.data[3] << 32) |
((uint64_t) chal.data[4] << 24) |
((uint64_t) chal.data[5] << 16) |
((uint64_t) chal.data[6] << 8) |
(uint64_t) chal.data[7];
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);
@@ -403,7 +411,14 @@ int cmd_calculate() {
asn1_ctx_t ctxt; asn1_ctx_t ctxt;
asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt); asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
asn1_find_tag(&ctxt, TAG_IMF, &chal); asn1_find_tag(&ctxt, TAG_IMF, &chal);
put_uint64_t_be(v, chal.data); chal.data[0] = (v >> 56) & 0xFF;
chal.data[1] = (v >> 48) & 0xFF;
chal.data[2] = (v >> 40) & 0xFF;
chal.data[3] = (v >> 32) & 0xFF;
chal.data[4] = (v >> 24) & 0xFF;
chal.data[5] = (v >> 16) & 0xFF;
chal.data[6] = (v >> 8) & 0xFF;
chal.data[7] = v & 0xff;
file_put_data(ef, tmp, (uint16_t)ef_size); file_put_data(ef, tmp, (uint16_t)ef_size);
low_flash_available(); low_flash_available();
free(tmp); free(tmp);
@@ -562,14 +577,14 @@ int cmd_verify_hotp() {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) { if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = get_uint32_t_be(code.data); code_int = (code.data[0] << 24) | (code.data[1] << 16) | (code.data[2] << 8) | code.data[3];
} }
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 != PICOKEY_OK) { if (ret != PICOKEY_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
uint32_t res_int = get_uint32_t_be(res_APDU + 2); uint32_t res_int = (res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5];
if (res_APDU[1] == 6) { if (res_APDU[1] == 6) {
res_int %= (uint32_t) 1e6; res_int %= (uint32_t) 1e6;
} }
@@ -584,52 +599,10 @@ int cmd_verify_hotp() {
return SW_OK(); return SW_OK();
} }
int cmd_rename() {
asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 };
if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA();
}
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
asn1_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
return SW_WRONG_DATA();
}
file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
uint8_t *fdata = file_get_data(ef);
uint16_t fsize = file_get_size(ef);
asn1_ctx_init(fdata, fsize, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
uint8_t *new_data;
if (new_name.len > name.len) {
new_data = (uint8_t *) calloc(1, file_get_size(ef) + new_name.len - name.len);
}
else {
new_data = (uint8_t *) calloc(1, file_get_size(ef));
}
memcpy(new_data, fdata, name.data - fdata);
*(new_data + (name.data - fdata) - 1) = 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));
file_put_data(ef, new_data, fsize + new_name.len - name.len);
low_flash_available();
free(new_data);
return SW_OK();
}
#define INS_PUT 0x01 #define INS_PUT 0x01
#define INS_DELETE 0x02 #define INS_DELETE 0x02
#define INS_SET_CODE 0x03 #define INS_SET_CODE 0x03
#define INS_RESET 0x04 #define INS_RESET 0x04
#define INS_RENAME 0x05
#define INS_LIST 0xa1 #define INS_LIST 0xa1
#define INS_CALCULATE 0xa2 #define INS_CALCULATE 0xa2
#define INS_VALIDATE 0xa3 #define INS_VALIDATE 0xa3
@@ -645,7 +618,6 @@ static const cmd_t cmds[] = {
{ INS_DELETE, cmd_delete }, { INS_DELETE, cmd_delete },
{ INS_SET_CODE, cmd_set_code }, { INS_SET_CODE, cmd_set_code },
{ INS_RESET, cmd_reset }, { INS_RESET, cmd_reset },
{ INS_RENAME, cmd_rename },
{ INS_LIST, cmd_list }, { INS_LIST, cmd_list },
{ INS_VALIDATE, cmd_validate }, { INS_VALIDATE, cmd_validate },
{ INS_CALCULATE, cmd_calculate }, { INS_CALCULATE, cmd_calculate },

View File

@@ -111,7 +111,7 @@ 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)
uint16_t otp_status(bool is_otp); uint16_t otp_status();
int otp_process_apdu(); int otp_process_apdu();
int otp_unload(); int otp_unload();
@@ -140,7 +140,10 @@ int otp_select(app_t *a, uint8_t force) {
else { else {
config_seq = 0; config_seq = 0;
} }
otp_status(false); otp_status();
memmove(res_APDU, res_APDU + 1, 6);
res_APDU_size = 6;
apdu.ne = res_APDU_size;
return PICOKEY_OK; return PICOKEY_OK;
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEY_ERR_FILE_NOT_FOUND;
@@ -166,11 +169,12 @@ void init_otp() {
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_t_be(data + otp_config_size); uint16_t counter = (data[otp_config_size] << 8) | data[otp_config_size + 1];
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_t_be(counter, new_data + otp_config_size); new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff;
file_put_data(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
} }
} }
@@ -224,18 +228,25 @@ 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_t_be(p); imf |= (uint64_t) *p++ << 56;
p += 8; imf |= (uint64_t) *p++ << 48;
imf |= (uint64_t) *p++ << 40;
imf |= (uint64_t) *p++ << 32;
imf |= *p++ << 24;
imf |= *p++ << 16;
imf |= *p++ << 8;
imf |= *p++;
if (imf == 0) { if (imf == 0) {
imf = get_uint16_t_be(otp_config->uid + 4); imf = ((otp_config->uid[4] << 8) | otp_config->uid[5]) << 4;
} }
uint8_t chal[8]; uint8_t chal[8] =
put_uint64_t_be(imf, chal); { imf >> 56, imf >> 48, imf >> 40, imf >> 32, imf >> 24, imf >> 16, imf >> 8, imf & 0xff };
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 == PICOKEY_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_t_be(res_APDU + 2); uint32_t number =
(res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5];
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) {
@@ -247,8 +258,9 @@ int otp_button_pressed(uint8_t slot) {
add_keyboard_buffer((const uint8_t *) number_str, 6, true); add_keyboard_buffer((const uint8_t *) number_str, 6, true);
} }
imf++; imf++;
uint8_t new_chal[8]; uint8_t new_chal[8] =
put_uint64_t_be(imf, new_chal); { imf >> 56, imf >> 48, imf >> 40, imf >> 32, imf >> 24, imf >> 16, imf >> 8,
imf & 0xff };
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));
@@ -272,7 +284,7 @@ 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_t_be(data + otp_config_size), crc = 0; uint16_t counter = (data[otp_config_size] << 8) | data[otp_config_size + 1], 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;
@@ -282,8 +294,9 @@ 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_t_le(counter, po); *po++ = counter & 0xff;
ts >>= 1; *po++ = counter >> 8;
ts >>= 3;
*po++ = ts & 0xff; *po++ = ts & 0xff;
*po++ = ts >> 8; *po++ = ts >> 8;
*po++ = ts >> 16; *po++ = ts >> 16;
@@ -291,7 +304,8 @@ int otp_button_pressed(uint8_t slot) {
random_gen(NULL, 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_t_le(~crc, po); *po++ = ~crc & 0xff;
*po++ = ~crc >> 8;
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);
@@ -312,7 +326,8 @@ 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_t_be(counter, new_data + otp_config_size); new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff;
file_put_data(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
low_flash_available(); low_flash_available();
} }
@@ -336,32 +351,22 @@ int otp_unload() {
return PICOKEY_OK; return PICOKEY_OK;
} }
uint16_t otp_status(bool is_otp) { uint16_t otp_status() {
if (scanned == false) { if (scanned == false) {
scan_all(); scan_all();
scanned = true; scanned = true;
} }
res_APDU_size = 0; res_APDU_size = 0;
if (is_otp) { res_APDU[1] = PICO_FIDO_VERSION_MAJOR;
res_APDU_size++; res_APDU[2] = PICO_FIDO_VERSION_MINOR;
} res_APDU[3] = 0;
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[4] = config_seq;
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[5] = (CONFIG2_TOUCH | CONFIG1_TOUCH) |
res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq;
res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID : (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID :
0x00) | 0x00) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID : (file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID :
0x00); 0x00);
res_APDU[res_APDU_size++] = 0; res_APDU[6] = 0;
if (is_otp) {
res_APDU_size = 0;
}
else {
apdu.ne = res_APDU_size;
}
return SW_OK(); return SW_OK();
} }
@@ -370,7 +375,6 @@ bool check_crc(const otp_config_t *data) {
return crc == 0xF0B8; return crc == 0xF0B8;
} }
bool _is_otp = false;
int cmd_otp() { int cmd_otp() {
uint8_t p1 = P1(apdu), p2 = P2(apdu); uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p2 != 0x00) { if (p2 != 0x00) {
@@ -394,13 +398,16 @@ int cmd_otp() {
file_put_data(ef, apdu.data, otp_config_size + 8); file_put_data(ef, apdu.data, otp_config_size + 8);
low_flash_available(); low_flash_available();
config_seq++; config_seq++;
return otp_status(_is_otp); return otp_status();
} }
} }
// Delete slot // Delete slot
delete_file(ef); delete_file(ef);
config_seq++; if (!file_has_data(search_dynamic_file(EF_OTP_SLOT1)) &&
return otp_status(_is_otp); !file_has_data(search_dynamic_file(EF_OTP_SLOT2))) {
config_seq = 0;
}
return otp_status();
} }
else if (p1 == 0x04 || p1 == 0x05) { else if (p1 == 0x04 || p1 == 0x05) {
otp_config_t *odata = (otp_config_t *) apdu.data; otp_config_t *odata = (otp_config_t *) apdu.data;
@@ -424,7 +431,6 @@ int cmd_otp() {
file_put_data(ef, apdu.data, otp_config_size); file_put_data(ef, apdu.data, otp_config_size);
low_flash_available(); low_flash_available();
} }
return otp_status(_is_otp);
} }
else if (p1 == 0x06) { else if (p1 == 0x06) {
uint8_t tmp[otp_config_size + 8]; uint8_t tmp[otp_config_size + 8];
@@ -448,7 +454,6 @@ int cmd_otp() {
delete_file(ef2); delete_file(ef2);
} }
low_flash_available(); low_flash_available();
return otp_status(_is_otp);
} }
else if (p1 == 0x10) { else if (p1 == 0x10) {
memcpy(res_APDU, pico_serial.id, 4); memcpy(res_APDU, pico_serial.id, 4);
@@ -466,7 +471,12 @@ int cmd_otp() {
} }
int ret = 0; int ret = 0;
if (p1 == 0x30 || p1 == 0x38) { if (p1 == 0x30 || p1 == 0x38) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), otp_config->aes_key, KEY_SIZE, apdu.data, 8, res_APDU); mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
otp_config->aes_key,
KEY_SIZE,
apdu.data,
8,
res_APDU);
if (ret == 0) { if (ret == 0) {
res_APDU_size = 20; res_APDU_size = 20;
} }
@@ -522,7 +532,9 @@ extern uint16_t *get_send_buffer_size(uint8_t itf);
int otp_send_frame(uint8_t *frame, size_t frame_len) { 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_t_le(~crc, frame + frame_len); frame[frame_len] = ~crc & 0xff;
frame[frame_len + 1] = ~crc >> 8;
frame_len += 2;
*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) {
@@ -555,7 +567,7 @@ int otp_hid_set_report_cb(uint8_t itf,
memcpy(otp_frame_rx + rseq * 7, buffer, 7); memcpy(otp_frame_rx + rseq * 7, buffer, 7);
if (rseq == 9) { if (rseq == 9) {
DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx)); DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx));
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_t_le(otp_frame_rx + 65); uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = (otp_frame_rx[66] << 8 | 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];
@@ -567,12 +579,10 @@ int otp_hid_set_report_cb(uint8_t itf,
apdu.header[1] = 0x01; apdu.header[1] = 0x01;
apdu.header[2] = slot_id; apdu.header[2] = slot_id;
apdu.header[3] = 0; apdu.header[3] = 0;
_is_otp = true;
int ret = otp_process_apdu(); int ret = otp_process_apdu();
if (ret == 0x9000 && res_APDU_size > 0) { if (ret == 0x9000 && res_APDU_size > 0) {
otp_send_frame(apdu.rdata, apdu.rlen); otp_send_frame(apdu.rdata, apdu.rlen);
} }
_is_otp = false;
} }
else { else {
printf("[OTP] Bad CRC!\n"); printf("[OTP] Bad CRC!\n");
@@ -614,7 +624,7 @@ uint16_t otp_hid_get_report_cb(uint8_t itf,
} }
else { else {
res_APDU = buffer; res_APDU = buffer;
otp_status(true); otp_status();
} }
return reqlen; return reqlen;

View File

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

View File

@@ -19,7 +19,7 @@
from fido2.client import CtapError from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512 from fido2.cose import ES256, ES384, ES512, EdDSA
import fido2.features import fido2.features
fido2.features.webauthn_json_mapping.enabled = False fido2.features.webauthn_json_mapping.enabled = False
from utils import ES256K from utils import ES256K
@@ -124,7 +124,7 @@ def test_bad_type_pubKeyCredParams(device):
device.doMC(key_params=["wrong"]) device.doMC(key_params=["wrong"])
@pytest.mark.parametrize( @pytest.mark.parametrize(
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM] "alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
) )
def test_algorithms(device, info, alg): def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms): if ({'alg': alg, 'type': 'public-key'} in info.algorithms):

View File

@@ -19,7 +19,7 @@
from fido2.client import CtapError from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512 from fido2.cose import ES256, ES384, ES512, EdDSA
from utils import verify, ES256K from utils import verify, ES256K
import pytest import pytest
@@ -49,7 +49,7 @@ def test_empty_allowList(device):
assert e.value.code == CtapError.ERR.NO_CREDENTIALS assert e.value.code == CtapError.ERR.NO_CREDENTIALS
@pytest.mark.parametrize( @pytest.mark.parametrize(
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM] "alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
) )
def test_algorithms(device, info, alg): def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms): if ({'alg': alg, 'type': 'public-key'} in info.algorithms):
@@ -213,19 +213,11 @@ def test_allow_list_missing_id(device, MCRes):
] ]
) )
def test_silent_ok(device, MCRes): def test_user_presence_option_false(device, MCRes):
res = device.GA(options={"up": False}, allow_list=[ res = device.GA(options={"up": False}, allow_list=[
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"} {"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
]) ])
def test_silent_ko(device, MCRes):
cred = MCRes['res'].attestation_object.auth_data.credential_data.credential_id + b'\x00'
with pytest.raises(CtapError) as e:
res = device.GA(options={"up": False}, allow_list=[
{"id": cred, "type": "public-key"}
])
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_credential_resets(device, MCRes, GARes): def test_credential_resets(device, MCRes, GARes):
device.reset() device.reset()
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:

View File

@@ -255,5 +255,5 @@ def test_returned_credential(device):
device.GNA() device.GNA()
# the returned credential should have user id in it # the returned credential should have user id in it
#print(ga_res) print(ga_res)
#assert 'id' in ga_res.user and len(ga_res.user["id"]) > 0 assert 'id' in ga_res.user and len(ga_res.user["id"]) > 0

View File

@@ -233,7 +233,6 @@ class Vendor:
VENDOR_UNLOCK = 0x03 VENDOR_UNLOCK = 0x03
VENDOR_EA = 0x04 VENDOR_EA = 0x04
VENDOR_PHY = 0x05 VENDOR_PHY = 0x05
VENDOR_MEMORY = 0x06
@unique @unique
class PARAM(IntEnum): class PARAM(IntEnum):
@@ -476,13 +475,6 @@ class Vendor:
Vendor.SUBCMD.ENABLE, Vendor.SUBCMD.ENABLE,
)[Vendor.RESP.PARAM] )[Vendor.RESP.PARAM]
def memory(self):
resp = self._call(
Vendor.CMD.VENDOR_MEMORY,
Vendor.SUBCMD.ENABLE,
)
return { 'free': resp[1], 'used': resp[2], 'total': resp[3], 'files': resp[4], 'size': resp[5] }
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
subparser = parser.add_subparsers(title="commands", dest="command") subparser = parser.add_subparsers(title="commands", dest="command")
@@ -511,8 +503,6 @@ def parse_args():
parser_phy_optdimm = subparser_phy.add_parser('led_dimmable', help='Enable/Disable LED dimming.') parser_phy_optdimm = subparser_phy.add_parser('led_dimmable', help='Enable/Disable LED dimming.')
parser_phy_optdimm.add_argument('value', choices=['enable', 'disable'], help='Enable/Disable LED dimming.', nargs='?') parser_phy_optdimm.add_argument('value', choices=['enable', 'disable'], help='Enable/Disable LED dimming.', nargs='?')
parser_mem = subparser.add_parser('memory', help='Get current memory usage.')
args = parser.parse_args() args = parser.parse_args()
return args return args
@@ -570,17 +560,9 @@ def phy(vdr, args):
else: else:
print('Command executed successfully. Please, restart your Pico Key.') print('Command executed successfully. Please, restart your Pico Key.')
def memory(vdr, args):
mem = vdr.memory()
print(f'Memory usage:')
print(f'\tFree: {mem["free"]/1024:.2f} kilobytes ({mem["free"]*100/mem["total"]:.2f}%)')
print(f'\tUsed: {mem["used"]/1024:.2f} kilobytes ({mem["used"]*100/mem["total"]:.2f}%)')
print(f'\tTotal: {mem["total"]/1024:.2f} kilobytes')
print(f'\tFlash size: {mem["size"]/1024:.2f} kilobytes')
print(f'\tFiles: {mem["files"]}')
def main(args): def main(args):
print('Pico Fido Tool v1.10') print('Pico Fido Tool v1.8')
print('Author: Pol Henarejos') print('Author: Pol Henarejos')
print('Report bugs to https://github.com/polhenarejos/pico-fido/issues') print('Report bugs to https://github.com/polhenarejos/pico-fido/issues')
print('') print('')
@@ -600,8 +582,6 @@ def main(args):
attestation(vdr, args) attestation(vdr, args)
elif (args.command == 'phy'): elif (args.command == 'phy'):
phy(vdr, args) phy(vdr, args)
elif (args.command == 'memory'):
memory(vdr, args)
def run(): def run():
args = parse_args() args = parse_args()

View File

@@ -7,7 +7,6 @@ if [[ $1 == "pico" ]]; then
sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
git clone https://github.com/raspberrypi/pico-sdk git clone https://github.com/raspberrypi/pico-sdk
cd pico-sdk cd pico-sdk
git checkout tags/2.1.1
git submodule update --init git submodule update --init
cd .. cd ..
git clone https://github.com/raspberrypi/picotool git clone https://github.com/raspberrypi/picotool
@@ -23,7 +22,6 @@ mkdir build_pico
cd build_pico cd build_pico
cmake -DPICO_SDK_PATH=../pico-sdk .. cmake -DPICO_SDK_PATH=../pico-sdk ..
make make
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
@@ -33,20 +31,6 @@ cd esp-idf
cd .. cd ..
idf.py set-target esp32s3 idf.py set-target esp32s3
idf.py all idf.py all
mkdir -p release
cd build
esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_fido_esp32-s3.bin @flash_args
cd ..
cd esp-idf
./install.sh esp32s2
. ./export.sh
cd ..
idf.py set-target esp32s2
idf.py all
mkdir -p release
cd build
esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_fido_esp32-s2.bin @flash_args
cd ..
else else
mkdir build mkdir build
cd build cd build