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/CMakeLists.txt b/CMakeLists.txt
index c89573a..ba22291 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()
@@ -39,14 +41,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)
@@ -85,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
@@ -116,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()
@@ -161,5 +157,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/build_pico_fido.sh b/build_pico_fido.sh
index a70a50f..66f0491 100755
--- a/build_pico_fido.sh
+++ b/build_pico_fido.sh
@@ -1,7 +1,7 @@
#!/bin/bash
VERSION_MAJOR="6"
-VERSION_MINOR="0-eddsa1"
+VERSION_MINOR="2-eddsa1"
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}"
diff --git a/pico-keys-sdk b/pico-keys-sdk
index 1d86efa..edc2b3a 160000
--- a/pico-keys-sdk
+++ b/pico-keys-sdk
@@ -1 +1 @@
-Subproject commit 1d86efa33bf1b3c118947eac14280f9953a49bc9
+Subproject commit edc2b3a4985a8cc95880e1d2b42b5aec9d793bbf
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"
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/cbor_get_assertion.c b/src/fido/cbor_get_assertion.c
index 5270421..a7990d4 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;
+ 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_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 f6dc63a..bd7a5d1 100644
--- a/src/fido/cbor_make_credential.c
+++ b/src/fido/cbor_make_credential.c
@@ -291,7 +291,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 ||
@@ -414,13 +414,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;
- *pa++ = (ctr >> 24) & 0xFF;
- *pa++ = (ctr >> 16) & 0xFF;
- *pa++ = (ctr >> 8) & 0xFF;
- *pa++ = ctr & 0xFF;
+ 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_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
diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c
index 501a22e..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));
@@ -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/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/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) {
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/src/fido/fido.c b/src/fido/fido.c
index 9d30b27..9e11385 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,
@@ -200,12 +202,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;
}
@@ -299,6 +304,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...");
@@ -331,13 +337,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;
@@ -369,6 +395,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)) {
@@ -386,6 +419,7 @@ 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);
}
+
low_flash_available();
return PICOKEY_OK;
}
@@ -404,12 +438,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;
}
@@ -417,21 +449,18 @@ 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;
}
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/fido.h b/src/fido/fido.h
index 5ade08b..f29b953 100644
--- a/src/fido/fido.h
+++ b/src/fido/fido.h
@@ -131,4 +131,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..8608151
--- /dev/null
+++ b/src/fido/kek.c
@@ -0,0 +1,137 @@
+/*
+ * 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];
+ }
+ }
+}
+
+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;
+}
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
diff --git a/src/fido/management.c b/src/fido/management.c
index 8c25a9c..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;
}
@@ -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));
diff --git a/src/fido/oath.c b/src/fido/oath.c
index 8e396d1..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);
@@ -411,14 +403,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);
@@ -577,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 2970aeb..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,25 +227,18 @@ 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] =
- { 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) {
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) {
@@ -258,9 +250,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));
@@ -284,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;
@@ -294,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;
@@ -304,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);
@@ -326,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();
}
@@ -532,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) {
@@ -567,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];
diff --git a/src/fido/version.h b/src/fido/version.h
index 97c8be1..2c9d978 100644
--- a/src/fido/version.h
+++ b/src/fido/version.h
@@ -18,7 +18,7 @@
#ifndef __VERSION_H_
#define __VERSION_H_
-#define PICO_FIDO_VERSION 0x0600
+#define PICO_FIDO_VERSION 0x0602
#define PICO_FIDO_VERSION_MAJOR ((PICO_FIDO_VERSION >> 8) & 0xff)
#define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff)
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()
diff --git a/workflows/autobuild.sh b/workflows/autobuild.sh
index d90e1a4..d38a31d 100755
--- a/workflows/autobuild.sh
+++ b/workflows/autobuild.sh
@@ -7,6 +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.1.0
git submodule update --init
cd ..
git clone https://github.com/raspberrypi/picotool
@@ -22,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
@@ -31,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/pico_fido_esp32-s3.bin @flash_args
+cd ..
else
mkdir build
cd build