49 Commits

Author SHA1 Message Date
Pol Henarejos
bb20a75ef4 Fix secure boot enable.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 16:29:53 +01:00
Pol Henarejos
8d709cf745 Add support for HIGH/LOW ESP32 LED
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-04 23:46:41 +01:00
Pol Henarejos
bbbbcadf4c Upgrade to v7.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-01 20:37:29 +01:00
Pol Henarejos
fbbf1feb49 Fix phy marker write.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-01 20:37:17 +01:00
Pol Henarejos
22de41bfe0 Upgrade to Pico Keys SDK 8.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 16:22:25 +01:00
Pol Henarejos
31a6315721 Transmit CBOR errors in SW x64 with CCID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 17:22:00 +01:00
Pol Henarejos
9fb8d475b3 Old files. Not used anymore.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 15:54:59 +01:00
Pol Henarejos
c0298ece7d Remove PHY and MEMORY vendor commands as they are available through rescue applet.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 15:40:08 +01:00
Pol Henarejos
bea7706d63 Fix emulation build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 01:27:12 +01:00
Pol Henarejos
cfd22c2d2c Fix ccid max packet length & interface naming.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 01:20:22 +01:00
Pol Henarejos
8ea118fe91 Fix OATH in iOS Authenticator. Fixes #248.
For strange reason, iOS app doesn't follow strictly YKOATH spec. When there are remaining bytes after serial, it assumes there's challenge (and thus, access code), but algorithm 7B is there. Apparently algorithm 7B is only returned when challenge is present but I could not see where it is used.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 01:18:51 +01:00
Pol Henarejos
8e6f571b48 Move rtc
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-24 01:15:23 +01:00
Pol Henarejos
3c20800839 Add rtc to credential.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-24 01:14:46 +01:00
Pol Henarejos
f2eef5b839 Use new VID:PID allocated to Pico Fido.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:33:08 +01:00
Pol Henarejos
bc6ebdd069 Upgrade to new layout
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:09:42 +01:00
Pol Henarejos
3f890757ac Not present
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 01:00:18 +01:00
Pol Henarejos
18d68d7e05 Fix needs power cycle logic.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 00:57:31 +01:00
Pol Henarejos
c8d62de621 Add vendor commands via CCID
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 00:26:51 +01:00
Pol Henarejos
60165c21ca Fix vendor keydev loading
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 00:26:27 +01:00
Pol Henarejos
55a60f8875 Fix power_cycle behavior
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 00:26:13 +01:00
Pol Henarejos
7ed90007ef Add support for slots 3 & 4 in OTP.
Both slots are activated by clicking three or four times the BOOTSEL button.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-19 16:37:19 +01:00
Pol Henarejos
c23cc9ffe1 Add set/get RTC.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-19 16:36:49 +01:00
Pol Henarejos
dc4565a8fb Fix LED default parameters in Pimoroni boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-15 01:17:18 +01:00
Pol Henarejos
804ee68e86 Remove non-standard MAKE CREDENTIAL step.
It may collide with other userName and the purpose is achieved cleaner via Rescue interface.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-08 10:46:51 +01:00
Pol Henarejos
fe49149d86 Update README with up-to-date info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-06 21:20:04 +01:00
Pol Henarejos
81d97f1a18 Upgrade to v7.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:56:09 +01:00
Pol Henarejos
d16016cf1e Upgrade Pico Keys SDK to v8.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:51:11 +01:00
Pol Henarejos
2e0333677b Fix button logic.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:39:46 +01:00
Pol Henarejos
becdc94339 Disable button press by default since LED may not be properly configured until it is commissioned.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:37:30 +01:00
Pol Henarejos
bd499ae1d4 Remove print
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:37:27 +01:00
Pol Henarejos
5fc84d7097 Reset internal state of GA to avoid phantom requests on GNA.
When a previous GA had more than 1 credential, it stored the full list in the internal state. Later, if a GA had only 1 credential, subsequent GNA returned older state of previous non-related GA.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 12:36:44 +01:00
Pol Henarejos
ac7e34522a Fixed resident credential storage when two userId have the same prefix.
Added a specific test for this case.

Fixes #241.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 12:34:04 +01:00
Pol Henarejos
70dec5596a Fix build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-29 20:36:37 +01:00
Pol Henarejos
2331dcb3ec Blink led three times to acknowledge proper commissioning.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-29 20:16:22 +01:00
Pol Henarejos
42b8b0af5f Fix pimoroni led
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-27 22:04:03 +01:00
Pol Henarejos
ceb54d9a08 Move pointer
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-27 16:03:07 +01:00
Pol Henarejos
527943fbba Releaser is available up to 6.7.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-26 19:53:46 +01:00
Pol Henarejos
7dddfd971e Build only necessary boards
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-11 20:01:08 +01:00
Pol Henarejos
29f942dab9 Update pointer
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-11 15:42:47 +01:00
Pol Henarejos
aa9df892d3 Revert "Move EDDSA to another branch."
This reverts commit 1867f0330f.
2025-12-11 15:41:47 +01:00
Pol Henarejos
7ac2ce30f0 Revert "Move other curves to another branch."
This reverts commit 46720fb387.
2025-12-11 15:40:16 +01:00
Pol Henarejos
e86862033c Revert "Move enterprise attestation to another branch."
This reverts commit 1d21d93b74.
2025-12-11 15:40:10 +01:00
Pol Henarejos
ae36143498 Revert "Move Secure Boot to another branch."
This reverts commit d90dbb6c5f.
2025-12-11 15:39:57 +01:00
Pol Henarejos
d90dbb6c5f Move Secure Boot to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 21:39:14 +01:00
Pol Henarejos
1d21d93b74 Move enterprise attestation to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 21:39:10 +01:00
Pol Henarejos
8b9be258de Fix applet cmp
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 19:15:35 +01:00
Pol Henarejos
46720fb387 Move other curves to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 18:52:13 +01:00
Pol Henarejos
1867f0330f Move EDDSA to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 15:56:31 +01:00
Pol Henarejos
bb542e3b83 Add is_gpg flag for fido2.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-07 20:34:42 +01:00
26 changed files with 202 additions and 284 deletions

View File

@@ -34,7 +34,7 @@ jobs:
- name: Delete private key
run: rm private.pem
- name: Update nightly release
uses: pyTooling/Actions/releaser@main
uses: pyTooling/Actions/releaser@v6.7.0
with:
tag: nightly-${{ matrix.refs }}
rm: true

View File

@@ -17,9 +17,12 @@
cmake_minimum_required(VERSION 3.13)
set(USB_VID 0x2E8A)
set(USB_PID 0x10FE)
if(ESP_PLATFORM)
set(DENABLE_POWER_ON_RESET 0)
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
set(EXTRA_COMPONENT_DIRS pico-keys-sdk/config/esp32/components src/fido)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else()
@@ -112,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()
@@ -161,7 +164,7 @@ if(ENABLE_EMULATION)
-Wl,--gc-sections
)
endif (APPLE)
target_link_libraries(pico_fido PRIVATE pthread m)
target_link_libraries(pico_fido PRIVATE pico_keys_sdk mbedtls pthread m)
else()
target_link_libraries(pico_fido PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id pico_aon_timer tinyusb_device tinyusb_board)
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})

View File

@@ -1,7 +1,7 @@
# Pico FIDO
This project transforms your Raspberry Pi Pico or ESP32 microcontroller into an integrated FIDO Passkey, functioning like a standard USB Passkey for authentication.
If you are looking for a Fido + OpenPGP, see: https://github.com/polhenarejos/pico-fido2
If you are looking for a OpenPGP + Fido, see: https://github.com/polhenarejos/pico-fido2. Available through [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App").
## Features
Pico FIDO includes the following features:
@@ -36,12 +36,13 @@ Pico FIDO includes the following features:
- Challenge-response generation
- Emulated keyboard interface
- Button press generates an OTP that is directly typed
- Yubico Authenticator app compatible
- Yubico YKMAN compatible
- Nitrokey nitropy and nitroapp compatible
- Secure Boot and Secure Lock in RP2350 and ESP32-S3 MCUs
- One Time Programming to store the master key that encrypts all resident keys and seeds.
- Rescue interface to allow recovery of the device if it becomes unresponsive or undetectable.
- LED customization with Pico Commissioner.
- LED customization with PicoKey App.
All features comply with the specifications. If you encounter unexpected behavior or deviations from the specifications, please open an issue.
@@ -55,11 +56,11 @@ Microcontrollers RP2350 and ESP32-S3 are designed to support secure environments
If you own a Raspberry Pico (RP2040 or RP2350), go to [Download page](https://www.picokeys.com/getting-started/), select your vendor and model and download the proper firmware; or go to [Release page](https://www.github.com/polhenarejos/pico-fido/releases/) and download the UF2 file for your board.
Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with other proprietary tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner").
UF2 files are shiped with a VID/PID granted by RaspberryPi (2E8A:10FE). If you plan to use it with OpenSC or similar tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App").
You can use whatever VID/PID (i.e., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
You can use whatever VID/PID for internal purposes, but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
Note that the pure-browser option [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") is the most recommended.
Note that the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App") is the most recommended.
## Build for Raspberry Pico
Before building, ensure you have installed the toolchain for the Pico and that the Pico SDK is properly located on your drive.

View File

@@ -1,48 +1,25 @@
#!/bin/bash
VERSION_MAJOR="7"
VERSION_MINOR="0"
NO_EDDSA=0
VERSION_MINOR="4"
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}"
#fi
if [[ $1 == "--no-eddsa" ]]; then
NO_EDDSA=1
echo "Skipping EDDSA build"
fi
mkdir -p build_release
mkdir -p release
mkdir -p release_eddsa
rm -rf -- release/*
if [[ $NO_EDDSA -eq 0 ]]; then
rm -rf -- release_eddsa/*
fi
cd build_release
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}"
SECURE_BOOT_PKEY="${SECURE_BOOT_PKEY:-../../ec_private_key.pem}"
board_dir=${PICO_SDK_PATH}/src/boards/include/boards
for board in "$board_dir"/*
boards=("pico" "pico2")
for board_name in "${boards[@]}"
do
board_name="$(basename -- "$board" .h)"
rm -rf -- ./*
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY}
make -j`nproc`
mv pico_fido.uf2 ../release/pico_fido_$board_name-$SUFFIX.uf2
done
# Build with EDDSA
if [[ $NO_EDDSA -eq 0 ]]; then
for board in "$board_dir"/*
do
board_name="$(basename -- "$board" .h)"
rm -rf -- ./*
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY} -DENABLE_EDDSA=1
make -j`nproc`
mv pico_fido.uf2 ../release_eddsa/pico_fido_$board_name-$SUFFIX-eddsa1.uf2
done
fi

View File

@@ -1,6 +1,6 @@
idf_component_register(
SRCS ${SOURCES}
INCLUDE_DIRS . ../../pico-keys-sdk/src ../../pico-keys-sdk/src/fs ../../pico-keys-sdk/src/rng ../../pico-keys-sdk/src/usb ../../pico-keys-sdk/tinycbor/src
REQUIRES esp_tinyusb mbedtls efuse
INCLUDE_DIRS .
REQUIRES esp_tinyusb mbedtls efuse pico-keys-sdk
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@@ -41,6 +41,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len);
int cbor_config(const uint8_t *data, size_t len);
int cbor_vendor(const uint8_t *data, size_t len);
int cbor_large_blobs(const uint8_t *data, size_t len);
extern void reset_gna_state();
extern int cmd_read_config();
@@ -59,6 +60,9 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
}
if (cap_supported(CAP_FIDO2)) {
if (cmd == CTAPHID_CBOR) {
if (data[0] != CTAP_GET_NEXT_ASSERTION) {
reset_gna_state();
}
if (data[0] == CTAP_MAKE_CREDENTIAL) {
return cbor_make_credential(data + 1, len - 1);
}

View File

@@ -419,6 +419,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
hsh[1] = pin_len;
hsh[2] = 1; // New format indicator
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash);
mbedtls_platform_zeroize(paddedNewPin, sizeof(paddedNewPin));
pin_derive_verifier(dhash, 16, hsh + 3);
file_put_data(ef_pin, hsh, sizeof(hsh));
low_flash_available();
@@ -430,6 +431,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
}
mbedtls_platform_zeroize(hsh, sizeof(hsh));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
needs_power_cycle = false;
goto err; //No return
}
else if (subcommand == 0x4) { //changePIN
@@ -458,6 +461,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.Y, kay.data, kay.len) != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (needs_power_cycle) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_BLOCKED);
}
uint8_t sharedSecret[64];
int ret = ecdh((uint8_t)pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
if (ret != 0) {
@@ -587,6 +593,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
low_flash_available();
resetPinUvAuthToken();
resetPersistentPinUvAuthToken();
needs_power_cycle = false;
goto err; // No return
}
else if (subcommand == 0x9 || subcommand == 0x5) { //getPinUvAuthTokenUsingPinWithPermissions
@@ -623,6 +630,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.Y, kay.data, kay.len) != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (needs_power_cycle) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_BLOCKED);
}
uint8_t sharedSecret[64];
int ret = ecdh((uint8_t)pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
if (ret != 0) {
@@ -720,6 +730,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, pinUvAuthToken_enc, 32 + poff));
needs_power_cycle = false;
}
else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);

View File

@@ -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) {

View File

@@ -42,6 +42,22 @@ uint32_t timerx = 0;
uint8_t *datax = NULL;
size_t lenx = 0;
void reset_gna_state() {
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credential_free(&credsx[i]);
}
if (datax) {
free(datax);
datax = NULL;
}
lenx = 0;
residentx = false;
timerx = 0;
flagsx = 0;
credentialCounter = 0;
numberOfCredentialsx = 0;
}
int cbor_get_next_assertion(const uint8_t *data, size_t len) {
(void) data;
(void) len;
@@ -57,19 +73,7 @@ int cbor_get_next_assertion(const uint8_t *data, size_t len) {
credentialCounter++;
err:
if (error != CborNoError || credentialCounter == numberOfCredentialsx) {
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credential_free(&credsx[i]);
}
if (datax) {
free(datax);
datax = NULL;
}
lenx = 0;
residentx = false;
timerx = 0;
flagsx = 0;
credentialCounter = 0;
numberOfCredentialsx = 0;
reset_gna_state();
if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
@@ -424,7 +428,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (!silent) {
for (int i = 0; i < numberOfCredentials; i++) {
for (int j = i + 1; j < numberOfCredentials; j++) {
if (creds[j].creation > creds[i].creation) {
if (creds[j].board_creation > creds[i].board_creation) {
Credential tmp = creds[j];
creds[j] = creds[i];
creds[i] = tmp;

View File

@@ -613,24 +613,6 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) {
if (memcmp(user.parent.name.data, "+pico", 5) == 0) {
options.rk = pfalse;
#ifndef ENABLE_EMULATION
uint8_t *p = (uint8_t *)user.parent.name.data + 5;
if (memcmp(p, "CommissionProfile", 17) == 0) {
ret = phy_unserialize_data(user.id.data, (uint16_t)user.id.len, &phy_data);
if (ret == PICOKEY_OK) {
ret = phy_save();
}
}
#endif
if (ret != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
}
}
uint8_t largeBlobKey[32] = {0};
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
ret = credential_derive_large_blob_key(cred_id, cred_id_len, largeBlobKey);

View File

@@ -206,7 +206,12 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint8_t buffer[1024];
mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), file_get_size(ef_keydev));
uint8_t keydev[32] = {0};
if (load_keydev(keydev) != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER);
}
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, keydev, 32);
mbedtls_platform_zeroize(keydev, sizeof(keydev));
if (ret != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING);
@@ -238,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);
}

View File

@@ -29,6 +29,7 @@
#include "files.h"
#include "otp.h"
extern bool has_set_rtc();
int credential_derive_chacha_key(uint8_t *outk, const uint8_t *);
static int credential_silent_tag(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, uint8_t *outk) {
@@ -148,6 +149,10 @@ int credential_create(CborCharString *rpId,
}
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
}
if (has_set_rtc()) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, (uint64_t) get_rtc_time()));
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
size_t rs = cbor_encoder_get_buffer_size(&encoder, cred_id);
*cred_id_len = CRED_PROTO_LEN + CRED_IV_LEN + (uint16_t)rs + CRED_TAG_LEN + CRED_SILENT_TAG_LEN;
@@ -220,7 +225,7 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
CBOR_FIELD_GET_TEXT(cred->userDisplayName, 1);
}
else if (val_u == 0x06) {
CBOR_FIELD_GET_UINT(cred->creation, 1);
CBOR_FIELD_GET_UINT(cred->board_creation, 1);
}
else if (val_u == 0x07) {
cred->extensions.present = true;
@@ -255,6 +260,9 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
}
CBOR_PARSE_MAP_END(_f1, 2);
}
else if (val_u == 0x0C) {
CBOR_FIELD_GET_UINT(cred->rtc_creation, 1);
}
else {
CBOR_ADVANCE(1);
}
@@ -319,7 +327,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
credential_free(&rcred);
continue;
}
if (memcmp(rcred.userId.data, cred.userId.data, MIN(rcred.userId.len, cred.userId.len)) == 0) {
if (rcred.userId.len == cred.userId.len && memcmp(rcred.userId.data, cred.userId.data, rcred.userId.len) == 0) {
sloti = i;
credential_free(&rcred);
new_record = false;

View File

@@ -43,7 +43,7 @@ typedef struct Credential {
CborByteString userId;
CborCharString userName;
CborCharString userDisplayName;
uint64_t creation;
uint64_t board_creation;
CredExtensions extensions;
const bool *use_sign_count;
int64_t alg;
@@ -51,6 +51,7 @@ typedef struct Credential {
CborByteString id;
CredOptions opts;
bool present;
uint64_t rtc_creation;
} Credential;
#define CRED_PROT_UV_OPTIONAL 0x01

View File

@@ -53,6 +53,11 @@ const uint8_t fido_aid[] = {
0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01
};
const uint8_t fido_aid_backup[] = {
8,
0xB0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01
};
const uint8_t atr_fido[] = {
23,
0x3b, 0xfd, 0x13, 0x00, 0x00, 0x81, 0x31, 0xfe, 0x15, 0x80, 0x73, 0xc0, 0x21, 0xc0, 0x57, 0x59,
@@ -86,6 +91,7 @@ INITIALIZER ( fido_ctor ) {
get_version_major = fido_get_version_major;
get_version_minor = fido_get_version_minor;
register_app(fido_select, fido_aid);
register_app(fido_select, fido_aid_backup);
}
int fido_unload() {
@@ -477,11 +483,13 @@ void scan_all() {
}
extern void init_otp();
extern bool needs_power_cycle;
void init_fido() {
scan_all();
#ifdef ENABLE_OTP_APP
init_otp();
#endif
needs_power_cycle = false;
}
bool wait_button_pressed() {
@@ -530,18 +538,32 @@ extern int cmd_register();
extern int cmd_authenticate();
extern int cmd_version();
extern int cbor_parse(int, uint8_t *, size_t);
extern int cbor_vendor(const uint8_t *data, size_t len);
extern void driver_init_hid();
#define CTAP_CBOR 0x10
int cmd_vendor() {
uint8_t *old_buf = res_APDU;
driver_init_hid();
int ret = cbor_vendor(apdu.data, apdu.nc);
res_APDU = old_buf;
if (ret != 0) {
return set_res_sw(0x64, ret);
}
res_APDU_size += 1;
memcpy(res_APDU, ctap_resp->init.data, res_APDU_size);
return SW_OK();
}
int cmd_cbor() {
uint8_t *old_buf = res_APDU;
driver_init_hid();
int ret = cbor_parse(0x90, apdu.data, apdu.nc);
if (ret != 0) {
return SW_EXEC_ERROR();
}
res_APDU = old_buf;
if (ret != 0) {
return set_res_sw(0x64, ret);
}
res_APDU_size += 1;
memcpy(res_APDU, ctap_resp->init.data, res_APDU_size);
return SW_OK();
@@ -552,6 +574,7 @@ static const cmd_t cmds[] = {
{ CTAP_AUTHENTICATE, cmd_authenticate },
{ CTAP_VERSION, cmd_version },
{ CTAP_CBOR, cmd_cbor },
{ 0x41, cmd_vendor },
{ 0x00, 0x0 }
};

View File

@@ -40,6 +40,8 @@
#define EF_OATH_CODE 0xBAFF
#define EF_OTP_SLOT1 0xBB00
#define EF_OTP_SLOT2 0xBB01
#define EF_OTP_SLOT3 0xBB02
#define EF_OTP_SLOT4 0xBB03
#define EF_OTP_PIN 0x10A0 // Nitrokey OTP PIN
extern file_t *ef_keydev;

View File

@@ -36,19 +36,6 @@ 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++) {

View File

@@ -23,6 +23,8 @@
#include "asn1.h"
#include "management.h"
bool is_gpg = true;
int man_process_apdu();
int man_unload();
@@ -44,6 +46,7 @@ int man_select(app_t *a, uint8_t force) {
init_otp();
#endif
}
is_gpg = false;
return PICOKEY_OK;
}

View File

@@ -94,22 +94,22 @@ int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = sizeof(challenge);
memcpy(res_APDU + res_APDU_size, challenge, sizeof(challenge));
res_APDU_size += sizeof(challenge);
}
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) {
const uint8_t *pin_data = file_get_data(ef_otp_pin);
res_APDU[res_APDU_size++] = TAG_PIN_COUNTER;
res_APDU[res_APDU_size++] = TAG_ALGO;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = *pin_data;
res_APDU[res_APDU_size++] = ALG_HMAC_SHA1;
}
res_APDU[res_APDU_size++] = TAG_ALGO;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = ALG_HMAC_SHA1;
if (is_nk) {
res_APDU[res_APDU_size++] = TAG_SERIAL_NUMBER;
res_APDU[res_APDU_size++] = 8;
memcpy(res_APDU + res_APDU_size, pico_serial_str, 8);
res_APDU_size += 8;
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) {
const uint8_t *pin_data = file_get_data(ef_otp_pin);
res_APDU[res_APDU_size++] = TAG_PIN_COUNTER;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = *pin_data;
}
}
apdu.ne = res_APDU_size;
return PICOKEY_OK;

View File

@@ -49,6 +49,11 @@ void append_keyboard_buffer(const uint8_t *buf, size_t len) {}
#define CONFIG_LED_INV 0x10
#define CONFIG_STATUS_MASK 0x1f
#define CONFIG3_VALID 0x01
#define CONFIG4_VALID 0x02
#define CONFIG3_TOUCH 0x04
#define CONFIG4_TOUCH 0x08
/* EXT Flags */
#define SERIAL_BTN_VISIBLE 0x01 // Serial number visible at startup (button press)
#define SERIAL_USB_VISIBLE 0x02 // Serial number visible in USB iSerial field
@@ -161,7 +166,7 @@ extern void scan_all();
void init_otp() {
if (scanned == false) {
scan_all();
for (uint8_t i = 0; i < 2; i++) {
for (uint8_t i = 0; i < 4; i++) {
file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data;
@@ -207,7 +212,8 @@ int otp_button_pressed(uint8_t slot) {
if (!cap_supported(CAP_OTP)) {
return 3;
}
file_t *ef = search_dynamic_file(slot == 1 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
uint16_t slot_ef = EF_OTP_SLOT1 + slot - 1;
file_t *ef = search_dynamic_file(slot_ef);
const uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data;
if (file_has_data(ef) == false) {
@@ -333,6 +339,39 @@ int otp_unload() {
}
uint8_t status_byte = 0x0;
uint16_t otp_status_ext() {
for (int i = 0; i < 4; i++) {
file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
if (file_has_data(ef)) {
res_APDU[res_APDU_size++] = 0xB0 + i;
res_APDU[res_APDU_size++] = 0; // Filled later
uint8_t *p = res_APDU + res_APDU_size;
otp_config_t *otp_config = (otp_config_t *)file_get_data(ef);
*p++ = 0xA0;
*p++ = 2;
*p++ = otp_config->tkt_flags;
*p++ = otp_config->cfg_flags;
if (otp_config->cfg_flags & CHAL_YUBICO && otp_config->tkt_flags & CHAL_RESP) {
}
else if (otp_config->tkt_flags & OATH_HOTP) {
}
else if (otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET) {
}
else {
*p++ = 0xC0;
*p++ = 6;
memcpy(p, otp_config->fixed_data, 6);
p += 6;
}
uint8_t len = p - (res_APDU + res_APDU_size);
res_APDU[res_APDU_size - 1] = len;
res_APDU_size += len;
}
}
return SW_OK();
}
uint16_t otp_status(bool is_otp) {
if (scanned == false) {
scan_all();
@@ -384,12 +423,13 @@ bool check_crc(const otp_config_t *data) {
bool _is_otp = false;
int cmd_otp() {
uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p2 != 0x00) {
return SW_INCORRECT_P1P2();
}
if (p1 == 0x01 || p1 == 0x03) { // Configure slot
otp_config_t *odata = (otp_config_t *) apdu.data;
file_t *ef = file_new(p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
if (p1 == 0x03 && p2 != 0x0) {
return SW_INCORRECT_P1P2();
}
uint16_t slot = (p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2;
file_t *ef = file_new(slot);
if (file_has_data(ef)) {
otp_config_t *otpc = (otp_config_t *) file_get_data(ef);
if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) {
@@ -415,10 +455,14 @@ int cmd_otp() {
}
else if (p1 == 0x04 || p1 == 0x05) { // Update slot
otp_config_t *odata = (otp_config_t *) apdu.data;
if (p1 == 0x05 && p2 != 0x0) {
return SW_INCORRECT_P1P2();
}
uint16_t slot = (p1 == 0x04 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2;
if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) {
return SW_WRONG_DATA();
}
file_t *ef = search_dynamic_file(p1 == 0x04 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
file_t *ef = search_dynamic_file(slot);
if (file_has_data(ef)) {
otp_config_t *otpc = (otp_config_t *) file_get_data(ef);
if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) {
@@ -446,8 +490,16 @@ int cmd_otp() {
else if (p1 == 0x06) { // Swap slots
uint8_t tmp[otp_config_size + 8];
bool ef1_data = false;
file_t *ef1 = file_new(EF_OTP_SLOT1);
file_t *ef2 = file_new(EF_OTP_SLOT2);
uint16_t slot1 = EF_OTP_SLOT1, slot2 = EF_OTP_SLOT2;
if (apdu.ne > 0) {
if (apdu.ne != 2) {
return SW_WRONG_LENGTH();
}
slot1 += apdu.data[0];
slot2 += apdu.data[1];
}
file_t *ef1 = file_new(slot1);
file_t *ef2 = file_new(slot2);
if (file_has_data(ef1)) {
memcpy(tmp, file_get_data(ef1), file_get_size(ef1));
ef1_data = true;
@@ -458,7 +510,7 @@ int cmd_otp() {
else {
delete_file(ef1);
// When a dynamic file is deleted, existing referenes are invalidated
ef2 = file_new(EF_OTP_SLOT2);
ef2 = file_new(slot2);
}
if (ef1_data) {
file_put_data(ef2, tmp, sizeof(tmp));
@@ -478,8 +530,15 @@ int cmd_otp() {
else if (p1 == 0x13) { // Get config
man_get_config();
}
else if (p1 == 0x14) {
otp_status_ext();
}
else if (p1 == 0x30 || p1 == 0x38 || p1 == 0x20 || p1 == 0x28) { // Calculate OTP
file_t *ef = search_dynamic_file(p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
if ((p1 == 0x38 || p1 == 0x28) && p2 != 0x0) {
return SW_INCORRECT_P1P2();
}
uint16_t slot = (p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2;
file_t *ef = search_dynamic_file(slot);
if (file_has_data(ef)) {
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
if (!(otp_config->tkt_flags & CHAL_RESP)) {

View File

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

View File

@@ -51,7 +51,7 @@ def test_lockout(device, resetdevice, client_pin):
res = client_pin.get_pin_retries()
assert res[0] == attempts
if err == CtapError.ERR.PIN_AUTH_BLOCKED:
if e.value.code == CtapError.ERR.PIN_AUTH_BLOCKED:
device.reboot()
client_pin = ClientPin(resetdevice.client()._backend.ctap2)

View File

@@ -202,10 +202,29 @@ def test_rk_with_allowlist_of_different_rp(resetdevice):
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_same_prefix_userId(device):
"""
A make credential request with two different UserIds that share the same prefix should NOT overwrite.
"""
rp = {"id": "sameprefix.org", "name": "Example"}
user1 = {"id": b"user_12", "name": "A fixed name", "displayName": "A fixed display name"}
user2 = {"id": b"user_123", "name": "A fixed name", "displayName": "A fixed display name"}
mc_res1 = device.MC(rp = rp, options={"rk":True}, user = user1)
# Should not overwrite the first credential.
mc_res2 = device.MC(rp = rp, options={"rk":True}, user = user2)
ga_res = device.GA(rp_id=rp['id'])['res']
assert ga_res.number_of_credentials == 2
def test_same_userId_overwrites_rk(resetdevice):
"""
A make credential request with a UserId & Rp that is the same as an existing one should overwrite.
"""
resetdevice.reset()
rp = {"id": "overwrite.org", "name": "Example"}
user = generate_random_user()

View File

@@ -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)

View File

@@ -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())

File diff suppressed because one or more lines are too long