From c0298ece7de1e432137e6b083d192809e3756bbf Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 26 Jan 2026 15:40:08 +0100 Subject: [PATCH 1/5] Remove PHY and MEMORY vendor commands as they are available through rescue applet. Signed-off-by: Pol Henarejos --- src/fido/cbor_config.c | 30 ------------------------------ src/fido/cbor_vendor.c | 35 ----------------------------------- 2 files changed, 65 deletions(-) diff --git a/src/fido/cbor_config.c b/src/fido/cbor_config.c index f00cf83..20a2a84 100644 --- a/src/fido/cbor_config.c +++ b/src/fido/cbor_config.c @@ -144,12 +144,6 @@ int cbor_config(const uint8_t *data, size_t len) { } if (subcommand == 0xFF) { -#ifndef ENABLE_EMULATION - const bool is_phy = (vendorCommandId == CTAP_CONFIG_PHY_VIDPID || - vendorCommandId == CTAP_CONFIG_PHY_LED_GPIO || - vendorCommandId == CTAP_CONFIG_PHY_LED_BTNESS || - vendorCommandId == CTAP_CONFIG_PHY_OPTS); -#endif if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE){ if (!file_has_data(ef_keydev_enc)) { CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); @@ -192,25 +186,6 @@ int cbor_config(const uint8_t *data, size_t len) { file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes low_flash_available(); } - -#ifndef ENABLE_EMULATION - else if (vendorCommandId == CTAP_CONFIG_PHY_VIDPID) { - phy_data.vid = (vendorParamInt >> 16) & 0xFFFF; - phy_data.pid = vendorParamInt & 0xFFFF; - phy_data.vidpid_present = true; - } - else if (vendorCommandId == CTAP_CONFIG_PHY_LED_GPIO) { - phy_data.led_gpio = (uint8_t)vendorParamInt; - phy_data.led_gpio_present = true; - } - else if (vendorCommandId == CTAP_CONFIG_PHY_LED_BTNESS) { - phy_data.led_brightness = (uint8_t)vendorParamInt; - phy_data.led_brightness_present = true; - } - else if (vendorCommandId == CTAP_CONFIG_PHY_OPTS) { - phy_data.opts = (uint16_t)vendorParamInt; - } -#endif else if (vendorCommandId == CTAP_CONFIG_EA_UPLOAD) { if (vendorParamByteString.present == false) { CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); @@ -239,11 +214,6 @@ int cbor_config(const uint8_t *data, size_t len) { else { CBOR_ERROR(CTAP2_ERR_INVALID_SUBCOMMAND); } -#ifndef ENABLE_EMULATION - if (is_phy && phy_save() != PICOKEY_OK) { - CBOR_ERROR(CTAP2_ERR_PROCESSING); - } -#endif goto err; } else if (subcommand == 0x03) { diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c index b59abb3..658c52e 100644 --- a/src/fido/cbor_vendor.c +++ b/src/fido/cbor_vendor.c @@ -243,41 +243,6 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, buffer + sizeof(buffer) - ret, ret)); } } -#ifndef ENABLE_EMULATION - else if (cmd == CTAP_VENDOR_PHY_OPTS) { - if (vendorCmd == 0x01) { - uint16_t opts = 0; - if (file_has_data(ef_phy)) { - uint8_t *pdata = file_get_data(ef_phy); - opts = get_uint16_t_be(pdata + PHY_OPTS); - } - CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); - CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); - CBOR_CHECK(cbor_encode_uint(&mapEncoder, opts)); - } - else { - CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); - } - } - #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); } From 9fb8d475b3e73e704a639d5321cabc34d7c90fe5 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 26 Jan 2026 15:54:59 +0100 Subject: [PATCH 2/5] Old files. Not used anymore. Signed-off-by: Pol Henarejos --- tools/secure_key/macos.py | 61 ------------------------------------- tools/secure_key/windows.py | 44 -------------------------- 2 files changed, 105 deletions(-) delete mode 100644 tools/secure_key/macos.py delete mode 100644 tools/secure_key/windows.py diff --git a/tools/secure_key/macos.py b/tools/secure_key/macos.py deleted file mode 100644 index 1ccc1a4..0000000 --- a/tools/secure_key/macos.py +++ /dev/null @@ -1,61 +0,0 @@ -import sys -import keyring - -DOMAIN = "PicoKeys.com" -USERNAME = "Pico-Fido" - -try: - import keyring - from keyrings.osx_keychain_keys.backend import OSXKeychainKeysBackend, OSXKeychainKeyType, OSXKeyChainKeyClassType -except: - print('ERROR: keyring module not found! Install keyring package.\nTry with `pip install keyrings.osx-keychain-keys`') - sys.exit(-1) - -try: - from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption -except: - print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`') - sys.exit(-1) - - -def get_backend(use_secure_enclave=False): - backend = OSXKeychainKeysBackend( - key_type=OSXKeychainKeyType.EC, # Key type, e.g. RSA, RC, DSA, ... - key_class_type=OSXKeyChainKeyClassType.Private, # Private key, Public key, Symmetric-key - key_size_in_bits=256, - is_permanent=True, # If set, saves the key in keychain; else, returns a transient key - use_secure_enclave=use_secure_enclave, # Saves the key in the T2 (TPM) chip, requires a code-signed interpreter - access_group=None, # Limits key management and retrieval to set group, requires a code-signed interpreter - is_extractable=True # If set, private key is extractable; else, it can't be retrieved, but only operated against - ) - return backend - -def generate_secure_key(use_secure_enclave=False): - backend = get_backend(use_secure_enclave) - backend.set_password(DOMAIN, USERNAME, password=None) - return backend.get_password(DOMAIN, USERNAME) - -def get_d(key): - return key.private_numbers().private_value.to_bytes(32, 'big') - -def set_secure_key(pk): - backend = get_backend(False) - try: - backend.delete_password(DOMAIN, USERNAME) - except: - pass - backend.set_password(DOMAIN, USERNAME, pk.private_bytes(Encoding.PEM, PrivateFormat.TraditionalOpenSSL, NoEncryption())) - -def get_secure_key(): - key = None - try: - backend = get_backend(False) - key = backend.get_password(DOMAIN, USERNAME)[0] - if (key is None): - raise TypeError - except (keyring.errors.KeyringError, TypeError): - try: - key = generate_secure_key(False)[0] # It should be True, but secure enclave causes python segfault - except keyring.errors.PasswordSetError: - key = generate_secure_key(False)[0] - return get_d(key) diff --git a/tools/secure_key/windows.py b/tools/secure_key/windows.py deleted file mode 100644 index 844190a..0000000 --- a/tools/secure_key/windows.py +++ /dev/null @@ -1,44 +0,0 @@ -import sys - -DOMAIN = "PicoKeys.com" -USERNAME = "Pico-Fido" - -try: - import keyring -except: - print('ERROR: keyring module not found! Install keyring package.\nTry with `pip install keyring`') - sys.exit(-1) - -try: - from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, load_pem_private_key - from cryptography.hazmat.primitives.asymmetric import ec -except: - print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`') - sys.exit(-1) - - - -def generate_secure_key(): - pkey = ec.generate_private_key(ec.SECP256R1()) - set_secure_key(pkey) - return keyring.get_password(DOMAIN, USERNAME) - -def get_d(key): - return load_pem_private_key(key, password=None).private_numbers().private_value.to_bytes(32, 'big') - -def set_secure_key(pk): - try: - keyring.delete_password(DOMAIN, USERNAME) - except: - pass - keyring.set_password(DOMAIN, USERNAME, pk.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()).decode()) - -def get_secure_key(): - key = None - try: - key = keyring.get_password(DOMAIN, USERNAME) - if (key is None): - raise TypeError - except (keyring.errors.KeyringError, TypeError): - key = generate_secure_key() - return get_d(key.encode()) From 31a6315721cd9badd4b0b50776d3c5993f35f6f0 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 26 Jan 2026 17:22:00 +0100 Subject: [PATCH 3/5] Transmit CBOR errors in SW x64 with CCID. Signed-off-by: Pol Henarejos --- src/fido/fido.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fido/fido.c b/src/fido/fido.c index af4f790..4bc4324 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -549,7 +549,7 @@ int cmd_vendor() { int ret = cbor_vendor(apdu.data, apdu.nc); res_APDU = old_buf; if (ret != 0) { - return SW_EXEC_ERROR(); + return set_res_sw(0x64, ret); } res_APDU_size += 1; memcpy(res_APDU, ctap_resp->init.data, res_APDU_size); @@ -562,7 +562,7 @@ int cmd_cbor() { int ret = cbor_parse(0x90, apdu.data, apdu.nc); res_APDU = old_buf; if (ret != 0) { - return SW_EXEC_ERROR(); + return set_res_sw(0x64, ret); } res_APDU_size += 1; memcpy(res_APDU, ctap_resp->init.data, res_APDU_size); From 524deea038b8d429732fefce19dbd54b36a5c5d8 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 28 Jan 2026 00:57:38 +0100 Subject: [PATCH 4/5] Upgrade Pico Keys SDK 8.4 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 668b1ac..8075611 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 668b1ac1dd2fdd0934ae1f92bea8e266e8319f4f +Subproject commit 8075611f1565a12de6326e18afbc212d3d3c8548 From 370be2cd47f2e424d1e0d59b25ca76826ba4316d Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 28 Jan 2026 00:57:51 +0100 Subject: [PATCH 5/5] Upgrade to v7.4 Signed-off-by: Pol Henarejos --- CMakeLists.txt | 2 +- build_pico_fido.sh | 2 +- src/fido/version.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd9fd12..9ef3dba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ set(SOURCES ${SOURCES} ) endif() -SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/fido/version.h" 2) +SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/fido/version.h" 3) if(ESP_PLATFORM) project(pico_fido) endif() diff --git a/build_pico_fido.sh b/build_pico_fido.sh index 497d70d..d120690 100755 --- a/build_pico_fido.sh +++ b/build_pico_fido.sh @@ -1,7 +1,7 @@ #!/bin/bash VERSION_MAJOR="7" -VERSION_MINOR="2" +VERSION_MINOR="4" SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}" #if ! [[ -z "${GITHUB_SHA}" ]]; then # SUFFIX="${SUFFIX}.${GITHUB_SHA}" diff --git a/src/fido/version.h b/src/fido/version.h index f8625ce..dbf1962 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 0x0702 +#define PICO_FIDO_VERSION 0x0704 #define PICO_FIDO_VERSION_MAJOR ((PICO_FIDO_VERSION >> 8) & 0xff) #define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff)