From e994078790bbea8d3a798d4c246ed5ab247c6df8 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 25 Nov 2024 12:59:12 +0100 Subject: [PATCH 01/25] Add UP button timeout to PHY. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 6a18e3a..812f075 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 6a18e3aa833b4b794cd13d01957a32cf494073fb +Subproject commit 812f075ee4c49b07bce245321f119d71515aa1df From d5af2cd8ed155fee47bdb02c5d67ddea20d5457e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 25 Nov 2024 12:59:25 +0100 Subject: [PATCH 02/25] Remove ENABLE_UP_BUTTON macro. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 8 -------- src/fido/fido.c | 7 +------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c89573a..c066d63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,14 +39,6 @@ endif() add_executable(pico_fido) 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) if(ENABLE_POWER_ON_RESET) diff --git a/src/fido/fido.c b/src/fido/fido.c index e59d3c2..d63fa46 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -389,12 +389,10 @@ void init_fido() { bool wait_button_pressed() { uint32_t val = EV_PRESS_BUTTON; #ifndef ENABLE_EMULATION -#if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1 queue_try_add(&card_to_usb_q, &val); do { queue_remove_blocking(&usb_to_card_q, &val); } while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT); -#endif #endif return val == EV_BUTTON_TIMEOUT; } @@ -402,15 +400,12 @@ bool wait_button_pressed() { uint32_t user_present_time_limit = 0; bool check_user_presence() { -#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 (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) { if (wait_button_pressed() == true) { //timeout return false; } //user_present_time_limit = board_millis(); } -#endif return true; } From 4a64c1174030919e973e4d20a93850be0721fb2f Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 25 Nov 2024 22:44:22 +0100 Subject: [PATCH 03/25] Add support for Pico SDK 2.1.0 Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- workflows/autobuild.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 812f075..9f79693 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 812f075ee4c49b07bce245321f119d71515aa1df +Subproject commit 9f796930252a4379afd9b84575f6b95e7465e730 diff --git a/workflows/autobuild.sh b/workflows/autobuild.sh index 9b3ceae..66c978f 100755 --- a/workflows/autobuild.sh +++ b/workflows/autobuild.sh @@ -7,7 +7,7 @@ if [[ $1 == "pico" ]]; then 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 cd pico-sdk -git checkout tags/2.0.0 +git checkout tags/2.1.0 git submodule update --init cd .. git clone https://github.com/raspberrypi/picotool From 3c40706aaede1ef0ee9bd0abaecddfe64bdca13c Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 25 Nov 2024 22:59:08 +0100 Subject: [PATCH 04/25] Fix ESP32 build. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 9f79693..49758c6 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 9f796930252a4379afd9b84575f6b95e7465e730 +Subproject commit 49758c6ac7415c99aa68ea8a33a87e276eec092c From 3148649f861a1d57f6cece887cb5b6e66cd9822a Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 25 Nov 2024 23:48:35 +0100 Subject: [PATCH 05/25] Fix RP2350 build. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 1 + pico-keys-sdk | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c066d63..a01ac9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,5 +153,6 @@ if(ENABLE_EMULATION) target_link_libraries(pico_fido PRIVATE pthread m) else() target_link_libraries(pico_fido PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id pico_aon_timer tinyusb_device tinyusb_board) +pico_add_extra_outputs(${CMAKE_PROJECT_NAME}) endif() endif() diff --git a/pico-keys-sdk b/pico-keys-sdk index 49758c6..a271785 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 49758c6ac7415c99aa68ea8a33a87e276eec092c +Subproject commit a271785814583757e493bedaab24635a4f8a6a54 From 5faab169a8cfa27864323089283f3b9de97db37b Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 1 Dec 2024 01:07:33 +0100 Subject: [PATCH 06/25] Add option to disable power cycle on reset via Commissioner. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- src/fido/cbor_reset.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index a271785..a61f768 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit a271785814583757e493bedaab24635a4f8a6a54 +Subproject commit a61f7683b6602c4bee367be44ad38b090b7f7ecd diff --git a/src/fido/cbor_reset.c b/src/fido/cbor_reset.c index b3a07d5..afc8298 100644 --- a/src/fido/cbor_reset.c +++ b/src/fido/cbor_reset.c @@ -24,13 +24,14 @@ #ifdef ESP_PLATFORM #include "esp_compat.h" #endif +#include "fs/phy.h" extern void scan_all(); int cbor_reset() { #ifndef ENABLE_EMULATION #if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET == 1 - if (board_millis() > 10000) { + if (!(phy_data.opts & PHY_OPT_DISABLE_POWER_RESET) && board_millis() > 10000) { return CTAP2_ERR_NOT_ALLOWED; } #endif From 46ada2c1f73e0191a58d7d69f90ac1a5685edcbc Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 1 Dec 2024 01:24:01 +0100 Subject: [PATCH 07/25] Add support for tinyusb 0.17 in ESP32. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index a61f768..fcae98e 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit a61f7683b6602c4bee367be44ad38b090b7f7ecd +Subproject commit fcae98eeccb3bcd793467114cfe35defe7be0baf From 2eca08161d2594e7fb48537d4b6b42bbac881482 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 11 Dec 2024 12:15:00 +0100 Subject: [PATCH 08/25] ESP32-S3 only supports 4 IN endpoints. Fixes #77. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index fcae98e..cb4e2ba 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit fcae98eeccb3bcd793467114cfe35defe7be0baf +Subproject commit cb4e2ba0ebe75f19b88c9c1a812fd9a51e81d0c8 From bbf474811b7233cda7797037990340fe3b6ee9b7 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 11 Dec 2024 21:58:25 +0100 Subject: [PATCH 09/25] Add sanity checks. Signed-off-by: Pol Henarejos --- src/fido/credential.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/fido/credential.c b/src/fido/credential.c index ea878d5..4eea40c 100644 --- a/src/fido/credential.c +++ b/src/fido/credential.c @@ -147,6 +147,10 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r int ret = 0; CborError error = CborNoError; 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); ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash); if (ret != 0) { // U2F? @@ -236,17 +240,19 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r } void credential_free(Credential *cred) { - CBOR_FREE_BYTE_STRING(cred->rpId); - CBOR_FREE_BYTE_STRING(cred->userId); - CBOR_FREE_BYTE_STRING(cred->userName); - CBOR_FREE_BYTE_STRING(cred->userDisplayName); - CBOR_FREE_BYTE_STRING(cred->id); - if (cred->extensions.present) { - CBOR_FREE_BYTE_STRING(cred->extensions.credBlob); + if (cred) { + CBOR_FREE_BYTE_STRING(cred->rpId); + CBOR_FREE_BYTE_STRING(cred->userId); + CBOR_FREE_BYTE_STRING(cred->userName); + CBOR_FREE_BYTE_STRING(cred->userDisplayName); + CBOR_FREE_BYTE_STRING(cred->id); + if (cred->extensions.present) { + 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) { From dba805dc04d85047b9f4d7df93b91705f00f19fa Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 11 Dec 2024 21:58:48 +0100 Subject: [PATCH 10/25] Fix potential overflow due to bad initialization. Might fix #72. Signed-off-by: Pol Henarejos --- src/fido/cbor_make_credential.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index 5640b2f..3f9bd5e 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -286,7 +286,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) { if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) { continue; } - Credential ecred; + Credential ecred = {0}; if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash, &ecred) == 0 && (ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED || From 022503fdc0632b8438d946dceefc9ff3ab0c593e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 11 Dec 2024 22:36:41 +0100 Subject: [PATCH 11/25] In pure U2F mode, no keepalive is sent by authenticator. Instead, client sends commands to know the status. Fixes #72. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index cb4e2ba..1431f91 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit cb4e2ba0ebe75f19b88c9c1a812fd9a51e81d0c8 +Subproject commit 1431f91281dbe31f6327aea58df7bf3c3da259f6 From 9c9074c1eff1a6dba44cf3d9d7bc63237f68eb5e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 16 Dec 2024 18:43:04 +0100 Subject: [PATCH 12/25] Do not debug after write the buffer. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 1431f91..86999d8 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 1431f91281dbe31f6327aea58df7bf3c3da259f6 +Subproject commit 86999d8cdd4347b861d40cd7dc3a111729a7c090 From a5a0f3508ce3edf95d127900379c424389af0735 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 17 Dec 2024 11:58:39 +0100 Subject: [PATCH 13/25] Remove NFC references. Signed-off-by: Pol Henarejos --- src/fido/management.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/fido/management.c b/src/fido/management.c index 8c25a9c..b75ec3d 100644 --- a/src/fido/management.c +++ b/src/fido/management.c @@ -94,9 +94,6 @@ int man_get_config() { res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[res_APDU_size++] = 0; - res_APDU[res_APDU_size++] = TAG_NFC_SUPPORTED; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size++] = 0x00; if (!file_has_data(ef)) { res_APDU[res_APDU_size++] = TAG_USB_ENABLED; res_APDU[res_APDU_size++] = 2; @@ -108,9 +105,6 @@ int man_get_config() { res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK; res_APDU[res_APDU_size++] = 1; 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 { memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef)); From 9bfbc45f84013464867b01b0c079aefd2706c6eb Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 18 Dec 2024 20:18:41 +0100 Subject: [PATCH 14/25] Add support for variable USB product name. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 86999d8..e627b3f 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 86999d8cdd4347b861d40cd7dc3a111729a7c090 +Subproject commit e627b3fc865df1ffc573dfe33d0ebe864f8beea4 From 2d356a315e4e8b90f361c5bdccef876b27a37473 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 23 Dec 2024 19:54:11 +0100 Subject: [PATCH 15/25] Increase TinyUSB stack size for ESP32 boards. Signed-off-by: Pol Henarejos --- sdkconfig.defaults | 1 + 1 file changed, 1 insertion(+) diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 2014bb3..0420fe8 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -4,6 +4,7 @@ IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1 CONFIG_TINYUSB=y +CONFIG_TINYUSB_TASK_STACK_SIZE=16384 CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv" From b42a664ac63e0a356118e54305617a35c0851f4c Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 23 Dec 2024 19:56:13 +0100 Subject: [PATCH 16/25] Add support for displaying memory usage via "pico-fido-tool.py memory" command. Fixes #82. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- src/fido/cbor_vendor.c | 18 ++++++++++++++++++ src/fido/ctap.h | 1 + tools/pico-fido-tool.py | 22 +++++++++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index e627b3f..ffaf20d 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit e627b3fc865df1ffc573dfe33d0ebe864f8beea4 +Subproject commit ffaf20da5d65a2dfc6c92026014f818ec9382f21 diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c index 501a22e..4eb5a04 100644 --- a/src/fido/cbor_vendor.c +++ b/src/fido/cbor_vendor.c @@ -266,6 +266,24 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { } } #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 { CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); } diff --git a/src/fido/ctap.h b/src/fido/ctap.h index 6d22edf..ce5617a 100644 --- a/src/fido/ctap.h +++ b/src/fido/ctap.h @@ -126,6 +126,7 @@ typedef struct { #define CTAP_VENDOR_UNLOCK 0x03 #define CTAP_VENDOR_EA 0x04 #define CTAP_VENDOR_PHY_OPTS 0x05 +#define CTAP_VENDOR_MEMORY 0x06 #define CTAP_PERMISSION_MC 0x01 // MakeCredential #define CTAP_PERMISSION_GA 0x02 // GetAssertion diff --git a/tools/pico-fido-tool.py b/tools/pico-fido-tool.py index 377e6b6..963e70f 100644 --- a/tools/pico-fido-tool.py +++ b/tools/pico-fido-tool.py @@ -233,6 +233,7 @@ class CMD(IntEnum): VENDOR_UNLOCK = 0x03 VENDOR_EA = 0x04 VENDOR_PHY = 0x05 + VENDOR_MEMORY = 0x06 @unique class PARAM(IntEnum): @@ -475,6 +476,13 @@ def phy_opts(self): Vendor.SUBCMD.ENABLE, )[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(): parser = argparse.ArgumentParser() subparser = parser.add_subparsers(title="commands", dest="command") @@ -503,6 +511,8 @@ def parse_args(): 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_mem = subparser.add_parser('memory', help='Get current memory usage.') + args = parser.parse_args() return args @@ -560,9 +570,17 @@ def phy(vdr, args): else: 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): - print('Pico Fido Tool v1.8') + print('Pico Fido Tool v1.10') print('Author: Pol Henarejos') print('Report bugs to https://github.com/polhenarejos/pico-fido/issues') print('') @@ -582,6 +600,8 @@ def main(args): attestation(vdr, args) elif (args.command == 'phy'): phy(vdr, args) + elif (args.command == 'memory'): + memory(vdr, args) def run(): args = parse_args() From 1d20321d6920bb4dba0ae5f355f4b07e9efcff27 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 23 Dec 2024 20:51:09 +0100 Subject: [PATCH 17/25] Add BE/LE functions to pack uint16, uint32 and uint64. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- src/fido/cbor_get_assertion.c | 5 +---- src/fido/cbor_large_blobs.c | 5 +---- src/fido/cbor_make_credential.c | 5 +---- src/fido/cmd_authenticate.c | 5 +---- src/fido/oath.c | 9 +-------- src/fido/otp.c | 9 ++++----- 7 files changed, 10 insertions(+), 30 deletions(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index ffaf20d..d530ea6 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit ffaf20da5d65a2dfc6c92026014f818ec9382f21 +Subproject commit d530ea69797a3c91063ab0411840c0be384d70d1 diff --git a/src/fido/cbor_get_assertion.c b/src/fido/cbor_get_assertion.c index 22854d7..c829807 100644 --- a/src/fido/cbor_get_assertion.c +++ b/src/fido/cbor_get_assertion.c @@ -519,10 +519,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) { uint8_t *pa = aut_data; memcpy(pa, rp_id_hash, 32); pa += 32; *pa++ = flags; - *pa++ = (ctr >> 24) & 0xFF; - *pa++ = (ctr >> 16) & 0xFF; - *pa++ = (ctr >> 8) & 0xFF; - *pa++ = ctr & 0xFF; + put_uint32_t_be(ctr, pa); pa += 4; memcpy(pa, ext, ext_len); pa += ext_len; if ((size_t)(pa - aut_data) != aut_data_len) { CBOR_ERROR(CTAP1_ERR_OTHER); diff --git a/src/fido/cbor_large_blobs.c b/src/fido/cbor_large_blobs.c index 25ab8e1..e1b0aa5 100644 --- a/src/fido/cbor_large_blobs.c +++ b/src/fido/cbor_large_blobs.c @@ -129,10 +129,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) { uint8_t verify_data[70] = { 0 }; memset(verify_data, 0xff, 32); verify_data[32] = 0x0C; - verify_data[34] = offset & 0xFF; - verify_data[35] = (offset >> 8) & 0xFF; - verify_data[36] = (offset >> 16) & 0xFF; - verify_data[37] = (offset >> 24) & 0xFF; + put_uint32_t_le(offset, verify_data + 34); 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) { CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index 3f9bd5e..9083521 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -409,10 +409,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) { uint8_t *pa = aut_data; memcpy(pa, rp_id_hash, 32); pa += 32; *pa++ = flags; - *pa++ = (ctr >> 24) & 0xFF; - *pa++ = (ctr >> 16) & 0xFF; - *pa++ = (ctr >> 8) & 0xFF; - *pa++ = ctr & 0xFF; + put_uint32_t_be(ctr, pa); pa += 4; memcpy(pa, aaguid, 16); pa += 16; *pa++ = ((uint16_t)cred_id_len >> 8) & 0xFF; *pa++ = (uint16_t)cred_id_len & 0xFF; diff --git a/src/fido/cmd_authenticate.c b/src/fido/cmd_authenticate.c index aecf75b..ea74e47 100644 --- a/src/fido/cmd_authenticate.c +++ b/src/fido/cmd_authenticate.c @@ -66,10 +66,7 @@ int cmd_authenticate() { resp->flags = 0; resp->flags |= P1(apdu) == CTAP_AUTH_ENFORCE ? CTAP_AUTH_FLAG_TUP : 0x0; uint32_t ctr = get_sign_counter(); - resp->ctr[0] = (ctr >> 24) & 0xFF; - resp->ctr[1] = (ctr >> 16) & 0xFF; - resp->ctr[2] = (ctr >> 8) & 0xFF; - resp->ctr[3] = ctr & 0xFF; + put_uint32_t_be(ctr, resp->ctr); 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 + CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t)); diff --git a/src/fido/oath.c b/src/fido/oath.c index 8e396d1..dac79c5 100644 --- a/src/fido/oath.c +++ b/src/fido/oath.c @@ -411,14 +411,7 @@ int cmd_calculate() { asn1_ctx_t ctxt; asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt); asn1_find_tag(&ctxt, TAG_IMF, &chal); - 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; + put_uint64_t_be(v, chal.data); file_put_data(ef, tmp, (uint16_t)ef_size); low_flash_available(); free(tmp); diff --git a/src/fido/otp.c b/src/fido/otp.c index 2970aeb..d6442fd 100644 --- a/src/fido/otp.c +++ b/src/fido/otp.c @@ -239,8 +239,8 @@ int otp_button_pressed(uint8_t slot) { if (imf == 0) { imf = ((otp_config->uid[4] << 8) | otp_config->uid[5]) << 4; } - uint8_t chal[8] = - { imf >> 56, imf >> 48, imf >> 40, imf >> 32, imf >> 24, imf >> 16, imf >> 8, imf & 0xff }; + uint8_t chal[8]; + put_uint64_t_be(imf, chal); res_APDU_size = 0; int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal)); if (ret == PICOKEY_OK) { @@ -258,9 +258,8 @@ int otp_button_pressed(uint8_t slot) { add_keyboard_buffer((const uint8_t *) number_str, 6, true); } imf++; - uint8_t new_chal[8] = - { imf >> 56, imf >> 48, imf >> 40, imf >> 32, imf >> 24, imf >> 16, imf >> 8, - imf & 0xff }; + uint8_t new_chal[8]; + put_uint64_t_be(imf, 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_size, new_chal, sizeof(new_chal)); From 1f805b1df2401d8bf2a91e501a0c55c45cd30c06 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 23 Dec 2024 21:25:46 +0100 Subject: [PATCH 18/25] Use more uint16 funcs. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- src/fido/cbor_get_assertion.c | 2 +- src/fido/cbor_make_credential.c | 5 ++--- src/fido/cbor_vendor.c | 2 +- src/fido/fido.c | 2 +- src/fido/management.c | 2 +- src/fido/oath.c | 14 +++--------- src/fido/otp.c | 39 +++++++++++---------------------- 8 files changed, 23 insertions(+), 45 deletions(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index d530ea6..f8cb36c 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit d530ea69797a3c91063ab0411840c0be384d70d1 +Subproject commit f8cb36c2cf5de7f0e8b7cd4a497160e86de50107 diff --git a/src/fido/cbor_get_assertion.c b/src/fido/cbor_get_assertion.c index c829807..b2a28dd 100644 --- a/src/fido/cbor_get_assertion.c +++ b/src/fido/cbor_get_assertion.c @@ -519,7 +519,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) { uint8_t *pa = aut_data; memcpy(pa, rp_id_hash, 32); pa += 32; *pa++ = flags; - put_uint32_t_be(ctr, pa); pa += 4; + pa += put_uint32_t_be(ctr, pa); memcpy(pa, ext, ext_len); pa += ext_len; if ((size_t)(pa - aut_data) != aut_data_len) { CBOR_ERROR(CTAP1_ERR_OTHER); diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index 9083521..bb62795 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -409,10 +409,9 @@ int cbor_make_credential(const uint8_t *data, size_t len) { uint8_t *pa = aut_data; memcpy(pa, rp_id_hash, 32); pa += 32; *pa++ = flags; - put_uint32_t_be(ctr, pa); pa += 4; + pa += put_uint32_t_be(ctr, pa); memcpy(pa, aaguid, 16); pa += 16; - *pa++ = ((uint16_t)cred_id_len >> 8) & 0xFF; - *pa++ = (uint16_t)cred_id_len & 0xFF; + pa += put_uint16_t_be(cred_id_len, pa); memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len; memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs; memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len; diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c index 4eb5a04..e8ff439 100644 --- a/src/fido/cbor_vendor.c +++ b/src/fido/cbor_vendor.c @@ -255,7 +255,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { uint16_t opts = 0; if (file_has_data(ef_phy)) { uint8_t *data = file_get_data(ef_phy); - opts = (data[PHY_OPTS] << 8) | data[PHY_OPTS+1]; + opts = get_uint16_t_be(data + PHY_OPTS); } CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); diff --git a/src/fido/fido.c b/src/fido/fido.c index d63fa46..6ef148f 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -411,7 +411,7 @@ bool check_user_presence() { uint32_t get_sign_counter() { uint8_t *caddr = file_get_data(ef_counter); - return (*caddr) | (*(caddr + 1) << 8) | (*(caddr + 2) << 16) | (*(caddr + 3) << 24); + return get_uint32_t_le(caddr); } uint8_t get_opts() { diff --git a/src/fido/management.c b/src/fido/management.c index b75ec3d..d833d57 100644 --- a/src/fido/management.c +++ b/src/fido/management.c @@ -65,7 +65,7 @@ bool cap_supported(uint16_t cap) { if (tag == TAG_USB_ENABLED) { uint16_t ecaps = tag_data[0]; if (tag_len == 2) { - ecaps = (tag_data[0] << 8) | tag_data[1]; + ecaps = get_uint16_t_be(tag_data); } return ecaps & cap; } diff --git a/src/fido/oath.c b/src/fido/oath.c index dac79c5..477d373 100644 --- a/src/fido/oath.c +++ b/src/fido/oath.c @@ -395,15 +395,7 @@ int cmd_calculate() { return SW_EXEC_ERROR(); } if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { - 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]; + uint64_t v = get_uint64_t_be(chal.data); size_t ef_size = file_get_size(ef); v++; uint8_t *tmp = (uint8_t *) calloc(1, ef_size); @@ -570,14 +562,14 @@ int cmd_verify_hotp() { return SW_INCORRECT_PARAMS(); } if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) { - code_int = (code.data[0] << 24) | (code.data[1] << 16) | (code.data[2] << 8) | code.data[3]; + code_int = get_uint32_t_be(code.data); } int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len); if (ret != PICOKEY_OK) { return SW_EXEC_ERROR(); } - uint32_t res_int = (res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5]; + uint32_t res_int = get_uint32_t_be(res_APDU + 2); if (res_APDU[1] == 6) { res_int %= (uint32_t) 1e6; } diff --git a/src/fido/otp.c b/src/fido/otp.c index d6442fd..7337699 100644 --- a/src/fido/otp.c +++ b/src/fido/otp.c @@ -169,12 +169,11 @@ void init_otp() { otp_config_t *otp_config = (otp_config_t *) data; if (file_has_data(ef) && !(otp_config->tkt_flags & OATH_HOTP) && !(otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET)) { - uint16_t counter = (data[otp_config_size] << 8) | data[otp_config_size + 1]; + uint16_t counter = get_uint16_t_be(data + otp_config_size); if (++counter <= 0x7fff) { uint8_t new_data[otp_config_size + 8]; memcpy(new_data, data, sizeof(new_data)); - new_data[otp_config_size] = counter >> 8; - new_data[otp_config_size + 1] = counter & 0xff; + put_uint16_t_be(counter, new_data + otp_config_size); file_put_data(ef, new_data, sizeof(new_data)); } } @@ -228,16 +227,10 @@ int otp_button_pressed(uint8_t slot) { memcpy(tmp_key + 2, otp_config->aes_key, KEY_SIZE); uint64_t imf = 0; const uint8_t *p = data + otp_config_size; - imf |= (uint64_t) *p++ << 56; - 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++; + imf = get_uint64_t_be(p); + p += 8; if (imf == 0) { - imf = ((otp_config->uid[4] << 8) | otp_config->uid[5]) << 4; + imf = get_uint16_t_be(otp_config->uid + 4); } uint8_t chal[8]; put_uint64_t_be(imf, chal); @@ -245,8 +238,7 @@ int otp_button_pressed(uint8_t slot) { int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal)); if (ret == PICOKEY_OK) { uint32_t base = otp_config->cfg_flags & OATH_HOTP8 ? 1e8 : 1e6; - uint32_t number = - (res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5]; + uint32_t number = get_uint16_t_be(res_APDU + 2); number %= base; char number_str[9]; if (otp_config->cfg_flags & OATH_HOTP8) { @@ -283,7 +275,7 @@ int otp_button_pressed(uint8_t slot) { else { uint8_t otpk[22], *po = otpk; bool update_counter = false; - uint16_t counter = (data[otp_config_size] << 8) | data[otp_config_size + 1], crc = 0; + uint16_t counter = get_uint16_t_be(data + otp_config_size), crc = 0; uint32_t ts = board_millis() / 1000; if (counter == 0) { update_counter = true; @@ -293,9 +285,8 @@ int otp_button_pressed(uint8_t slot) { po += 6; memcpy(po, otp_config->uid, UID_SIZE); po += UID_SIZE; - *po++ = counter & 0xff; - *po++ = counter >> 8; - ts >>= 3; + po += put_uint16_t_le(counter, po); + ts >>= 1; *po++ = ts & 0xff; *po++ = ts >> 8; *po++ = ts >> 16; @@ -303,8 +294,7 @@ int otp_button_pressed(uint8_t slot) { random_gen(NULL, po, 2); po += 2; crc = calculate_crc(otpk + 6, 14); - *po++ = ~crc & 0xff; - *po++ = ~crc >> 8; + po += put_uint16_t_le(~crc, po); mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128); @@ -325,8 +315,7 @@ int otp_button_pressed(uint8_t slot) { if (update_counter == true) { uint8_t new_data[otp_config_size + 8]; memcpy(new_data, data, sizeof(new_data)); - new_data[otp_config_size] = counter >> 8; - new_data[otp_config_size + 1] = counter & 0xff; + put_uint16_t_be(counter, new_data + otp_config_size); file_put_data(ef, new_data, sizeof(new_data)); low_flash_available(); } @@ -531,9 +520,7 @@ extern uint16_t *get_send_buffer_size(uint8_t itf); int otp_send_frame(uint8_t *frame, size_t frame_len) { uint16_t crc = calculate_crc(frame, frame_len); - frame[frame_len] = ~crc & 0xff; - frame[frame_len + 1] = ~crc >> 8; - frame_len += 2; + frame_len += put_uint16_t_le(~crc, frame + frame_len); *get_send_buffer_size(ITF_KEYBOARD) = frame_len; otp_exp_seq = (frame_len / 7); if (frame_len % 7) { @@ -566,7 +553,7 @@ int otp_hid_set_report_cb(uint8_t itf, memcpy(otp_frame_rx + rseq * 7, buffer, 7); if (rseq == 9) { DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx)); - uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = (otp_frame_rx[66] << 8 | otp_frame_rx[65]); + uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_t_le(otp_frame_rx + 65); uint8_t slot_id = otp_frame_rx[64]; if (residual_crc == rcrc) { uint8_t hdr[5]; From cff544b4856edd723478b1e4fc4bbd1aaa237f2a Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 24 Dec 2024 02:06:50 +0100 Subject: [PATCH 19/25] Fix TX/RX buffers to align them with USB buffers and avoid overflows. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index f8cb36c..9e2b6ac 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit f8cb36c2cf5de7f0e8b7cd4a497160e86de50107 +Subproject commit 9e2b6ac4b6ad7f978b5c28600a007136fc6cb2ce From 1c456859267810cf31197bb21d8864e26a69db02 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 27 Dec 2024 02:11:31 +0100 Subject: [PATCH 20/25] Add nightly build of esp32. Signed-off-by: Pol Henarejos --- .github/workflows/nightly.yml | 1 + workflows/autobuild.sh | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 7c15511..7e9dbb8 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -25,6 +25,7 @@ jobs: run: | ./workflows/autobuild.sh pico ./build_pico_fido.sh + ./workflows/autobuild.sh esp32 - name: Update nightly release uses: pyTooling/Actions/releaser@main with: diff --git a/workflows/autobuild.sh b/workflows/autobuild.sh index 66c978f..891842e 100755 --- a/workflows/autobuild.sh +++ b/workflows/autobuild.sh @@ -23,6 +23,7 @@ mkdir build_pico cd build_pico cmake -DPICO_SDK_PATH=../pico-sdk .. make +cd .. 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 git clone --recursive https://github.com/espressif/esp-idf.git @@ -32,6 +33,10 @@ cd esp-idf cd .. idf.py set-target esp32s3 idf.py all +mkdir -p release +cd build +esptool.py --chip ESP32-S3 merge_bin -o ../release/esp32-s3.bin @flash_args +cd .. else mkdir build cd build From eeecf513cb43141aec667b2a8bbc517d280596e5 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 27 Dec 2024 02:23:11 +0100 Subject: [PATCH 21/25] Fix bin name. Signed-off-by: Pol Henarejos --- workflows/autobuild.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/autobuild.sh b/workflows/autobuild.sh index 891842e..d38a31d 100755 --- a/workflows/autobuild.sh +++ b/workflows/autobuild.sh @@ -35,7 +35,7 @@ idf.py set-target esp32s3 idf.py all mkdir -p release cd build -esptool.py --chip ESP32-S3 merge_bin -o ../release/esp32-s3.bin @flash_args +esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_fido_esp32-s3.bin @flash_args cd .. else mkdir build From a70e259a90939187879b2790c78fb362e0eaa204 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 30 Dec 2024 21:42:44 +0100 Subject: [PATCH 22/25] Use partition bounds if available. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 9e2b6ac..68a8168 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 9e2b6ac4b6ad7f978b5c28600a007136fc6cb2ce +Subproject commit 68a816895efb56a917520935f2f341960dc8db2c From 6a678000570ccf95dbc67446a0fe4fdddfc5f28e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 3 Jan 2025 01:20:58 +0100 Subject: [PATCH 23/25] Add support for PIN hash storage and MKEK. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 3 + src/fido/cbor_client_pin.c | 84 ++++++++++++++++++---- src/fido/fido.c | 31 ++++++++- src/fido/fido.h | 2 + src/fido/files.c | 48 ++++--------- src/fido/files.h | 2 + src/fido/kek.c | 138 +++++++++++++++++++++++++++++++++++++ src/fido/kek.h | 46 +++++++++++++ 8 files changed, 308 insertions(+), 46 deletions(-) create mode 100644 src/fido/kek.c create mode 100644 src/fido/kek.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a01ac9c..3ce3d40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,8 @@ cmake_minimum_required(VERSION 3.13) if(ESP_PLATFORM) +set(DEBUG_APDU 1) +set(DENABLE_POWER_ON_RESET 0) set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src) include($ENV{IDF_PATH}/tools/cmake/project.cmake) else() @@ -77,6 +79,7 @@ endif() set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c + ${CMAKE_CURRENT_LIST_DIR}/src/fido/kek.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_version.c diff --git a/src/fido/cbor_client_pin.c b/src/fido/cbor_client_pin.c index d0adfa9..1ceb701 100644 --- a/src/fido/cbor_client_pin.c +++ b/src/fido/cbor_client_pin.c @@ -37,6 +37,7 @@ #include "crypto_utils.h" #include "pico_keys.h" #include "apdu.h" +#include "kek.h" uint32_t usage_timer = 0, initial_usage_time_limit = 0; uint32_t max_usage_time_period = 600 * 1000; @@ -279,6 +280,21 @@ int pinUvAuthTokenUsageTimerObserver() { 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; int cbor_client_pin(const uint8_t *data, size_t len) { @@ -415,12 +431,20 @@ int cbor_client_pin(const uint8_t *data, size_t len) { if (pin_len < minPin) { CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); } - uint8_t hsh[34]; + uint8_t hsh[34], dhash[32]; hsh[0] = MAX_PIN_RETRIES; hsh[1] = pin_len; - mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2); - file_put_data(ef_pin, hsh, 2 + 16); + mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); + double_hash_pin(dhash, 16, hsh + 2); + file_put_data(ef_pin, hsh, 2 + 32); 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 } else if (subcommand == 0x4) { //changePIN @@ -462,8 +486,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) { mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); } - uint8_t pin_data[18]; - memcpy(pin_data, file_get_data(ef_pin), 18); + uint8_t pin_data[34]; + memcpy(pin_data, file_get_data(ef_pin), 34); pin_data[0] -= 1; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); @@ -474,7 +498,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) { mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); } - if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) { + uint8_t dhash[32]; + double_hash_pin(paddedNewPin, 16, dhash); + if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) { regenerate(); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); if (retries == 0) { @@ -488,6 +514,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) { CBOR_ERROR(CTAP2_ERR_PIN_INVALID); } } + hash_multi(paddedNewPin, 16, session_pin); pin_data[0] = MAX_PIN_RETRIES; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); @@ -515,12 +542,33 @@ int cbor_client_pin(const uint8_t *data, size_t len) { uint8_t hsh[34]; hsh[0] = MAX_PIN_RETRIES; hsh[1] = pin_len; - mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2); + mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); + double_hash_pin(dhash, 16, hsh + 2); if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && - memcmp(hsh + 2, file_get_data(ef_pin) + 2, 16) == 0) { + memcmp(hsh + 2, file_get_data(ef_pin) + 2, 32) == 0) { 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) { uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin)); memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin)); @@ -570,8 +618,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) { mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); } - uint8_t pin_data[18]; - memcpy(pin_data, file_get_data(ef_pin), 18); + uint8_t pin_data[34]; + memcpy(pin_data, file_get_data(ef_pin), 34); pin_data[0] -= 1; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); @@ -582,7 +630,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) { mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); } - if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) { + uint8_t dhash[32]; + double_hash_pin(paddedNewPin, 16, dhash); + if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) { regenerate(); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); if (retries == 0) { @@ -596,9 +646,19 @@ int cbor_client_pin(const uint8_t *data, size_t len) { 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; new_pin_mismatches = 0; 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(); 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) { diff --git a/src/fido/fido.c b/src/fido/fido.c index 6ef148f..7566989 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -16,6 +16,7 @@ */ #include "fido.h" +#include "kek.h" #include "pico_keys.h" #include "apdu.h" #include "ctap.h" @@ -46,6 +47,7 @@ pinUvAuthToken_t paut = { 0 }; uint8_t keydev_dec[32]; bool has_keydev_dec = false; +uint8_t session_pin[32] = { 0 }; const uint8_t fido_aid[] = { 8, @@ -188,12 +190,15 @@ int load_keydev(uint8_t *key) { } else { 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) { return PICOKEY_EXEC_ERROR; } } - //return mkek_decrypt(key, file_get_size(ef_keydev)); return PICOKEY_OK; } @@ -284,6 +289,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur int scan_files() { 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_mkek = search_by_fid(EF_MKEK, NULL, SPECIFY_EF); if (ef_keydev) { if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) { printf("KEY DEVICE is empty. Generating SECP256R1 curve..."); @@ -354,6 +360,13 @@ int scan_files() { printf("FATAL ERROR: Global counter not found in memory!\r\n"); } 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); if (ef_authtoken) { if (!file_has_data(ef_authtoken)) { @@ -371,6 +384,22 @@ int scan_files() { 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); } + + 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"); + } low_flash_available(); return PICOKEY_OK; } diff --git a/src/fido/fido.h b/src/fido/fido.h index a27f2b0..4666fda 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -130,4 +130,6 @@ extern uint32_t user_present_time_limit; 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 uint8_t session_pin[32]; + #endif //_FIDO_H diff --git a/src/fido/files.c b/src/fido/files.c index 11573c5..bf403bd 100644 --- a/src/fido/files.c +++ b/src/fido/files.c @@ -18,39 +18,20 @@ #include "files.h" file_t file_entries[] = { - { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, - .ef_structure = 0, .acl = { 0 } }, // MF - { .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, - .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key - { .fid = EF_KEY_DEV_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_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, - .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device - { .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, - .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, - .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate - { .fid = EF_COUNTER, .parent = 0, .name = NULL, - .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, - .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter - { .fid = EF_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 + { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = { 0 } }, // MF + { .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key + { .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc + { .fid = EF_MKEK, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MKEK + { .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device + { .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate + { .fid = EF_COUNTER, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter + { .fid = EF_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]; @@ -62,3 +43,4 @@ file_t *ef_pin = NULL; file_t *ef_authtoken = NULL; file_t *ef_keydev_enc = NULL; file_t *ef_largeblob = NULL; +file_t *ef_mkek = NULL; diff --git a/src/fido/files.h b/src/fido/files.h index 328eb13..93ceec9 100644 --- a/src/fido/files.h +++ b/src/fido/files.h @@ -22,6 +22,7 @@ #define EF_KEY_DEV 0xCC00 #define EF_KEY_DEV_ENC 0xCC01 +#define EF_MKEK 0xCC0F #define EF_EE_DEV 0xCE00 #define EF_EE_DEV_EA 0xCE01 #define EF_COUNTER 0xC000 @@ -46,5 +47,6 @@ extern file_t *ef_pin; extern file_t *ef_authtoken; extern file_t *ef_keydev_enc; extern file_t *ef_largeblob; +extern file_t *ef_mkek; #endif //_FILES_H_ diff --git a/src/fido/kek.c b/src/fido/kek.c new file mode 100644 index 0000000..69a9edc --- /dev/null +++ b/src/fido/kek.c @@ -0,0 +1,138 @@ +/* + * 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 . + */ + +#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]; + } + } +} +#include +int load_mkek(uint8_t *mkek) { + if (paut.in_use == false) { + return PICOKEY_NO_LOGIN; + } + file_t *tf = search_file(EF_MKEK); + printf("file_size = %d\n", file_get_size(tf)); + 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); + } + *(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; +} diff --git a/src/fido/kek.h b/src/fido/kek.h new file mode 100644 index 0000000..4cb1e11 --- /dev/null +++ b/src/fido/kek.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 . + */ + +#ifndef _KEK_H_ +#define _KEK_H_ + +#include "crypto_utils.h" +#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM) +#include +#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 From 77dd1c4b982bab0175649b739af676b05487c519 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 8 Jan 2025 17:25:04 +0100 Subject: [PATCH 24/25] Fix OTP/MKEK secure system. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- src/fido/fido.c | 39 ++++++++++++++++++++++----------------- src/fido/kek.c | 15 +++++++-------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 68a8168..3d91287 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 68a816895efb56a917520935f2f341960dc8db2c +Subproject commit 3d912878f1627719a006291eef5d60142a2f474f diff --git a/src/fido/fido.c b/src/fido/fido.c index 7566989..b7d39ef 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -322,13 +322,33 @@ int scan_files() { else { 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); if (ef_certdev) { if (!file_has_data(ef_certdev)) { - uint8_t cert[2048]; + uint8_t cert[2048], outk[32]; + memset(outk, 0, sizeof(outk)); + int ret = 0; + if ((ret = load_keydev(outk)) != 0) { + return ret; + } mbedtls_ecdsa_context key; mbedtls_ecdsa_init(&key); - int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), file_get_size(ef_keydev)); + ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, outk, sizeof(outk)); if (ret != 0) { mbedtls_ecdsa_free(&key); return ret; @@ -385,21 +405,6 @@ int scan_files() { 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); } - 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"); - } low_flash_available(); return PICOKEY_OK; } diff --git a/src/fido/kek.c b/src/fido/kek.c index 69a9edc..8608151 100644 --- a/src/fido/kek.c +++ b/src/fido/kek.c @@ -56,13 +56,9 @@ void mkek_masked(uint8_t *mkek, const uint8_t *mask) { } } } -#include + int load_mkek(uint8_t *mkek) { - if (paut.in_use == false) { - return PICOKEY_NO_LOGIN; - } file_t *tf = search_file(EF_MKEK); - printf("file_size = %d\n", file_get_size(tf)); if (file_has_data(tf)) { memcpy(mkek, file_get_data(tf), MKEK_SIZE); } @@ -78,9 +74,9 @@ int load_mkek(uint8_t *mkek) { 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); + if (otp_key_1) { + mkek_masked(mkek, otp_key_1); + } } return PICOKEY_OK; } @@ -98,6 +94,9 @@ int store_mkek(const uint8_t *mkek) { 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); From 8db06bf3ac4863ae85421c0229684ee36ac1b0d6 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 15 Jan 2025 15:12:28 +0100 Subject: [PATCH 25/25] Add rollback version to 1. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ce3d40..ba22291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,7 @@ endif() set(USB_ITF_HID 1) 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) project(pico_fido) endif()