33 Commits
v5.6 ... v5.8

Author SHA1 Message Date
Pol Henarejos
7e2ecdbc56 Upgrade to version 5.8
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
e54df525c4 Removing SHORT_TICKET limitation.
It is not used to return the half of ticket, but to combine with static to produce hex scancodes.

Fixes #29.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
1d9107d4bb OTP callbacks must be initialized on ctor.
Fixes #30.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
a9be759da3 OTP static passwords are 38 bytes length.
A static password uses fixed, uid and key fields (sum 38). However, Yubikey sets short_ticket flag which implies the half of the password is sent.

Fixes #29.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
34bfc3b2ef otp must be initialized when selection fido or management applets.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
d985cf6301 Moving Pico Keys SDK pointer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
0b00e01187 Fix build in emulation mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
bef1922c8f Use new names and defines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
107e5c34db Use new pico-keys-sdk submodule name.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
6157a91fdf Rename old pico-hsm-sdk to the new pico-keys-sdk.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
779db90713 Move some functions from HID to fido callbacks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
a0f1d2334d Use get_version_major and get_version_minor as pointers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
5c6f87ab8f Update SDK to new otp.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
cf152c1692 Move some OTP functions from HID to OTP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
04238509ee Generate a secure key if it is not found.
Should fix #23.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
85298062cd python-fido2 has a bug which does not allow to use 0xff as ConfigVendorPrototype.
It encodes an uint8_t to int8_t and thus, the command must be <= 0x7f.

Fixes #22.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
0464ad8964 Fixed AUT permission.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
19197e54a8 Added support for --pin flag.
It loads Vendor/Ctap2Vendor with uv_token based on provided --pin.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
01a6c9f77f Added Windows & Linux backend for backup/restore.
Fixes #21

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
ba57cc4527 Fixed OTP read packet through HID interfaces.
Fixes #19.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
68b5614fb9 Fixed potential crash.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
4fd4d75e21 Fixed potential memory leak.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
599fd706ce Fix AID selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:31 +01:00
Pol Henarejos
28e979939a Adapted to new selection AID method.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:30 +01:00
Pol Henarejos
849221fd95 Added backfall compatibility.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:30 +01:00
Pol Henarejos
011429a982 Update to latest HSM SDK changes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:30 +01:00
Pol Henarejos
b99181a00c Fix pico_w build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:30 +01:00
Pol Henarejos
041bb788f9 Added support for LED in Pico W.
Fixed #17.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:02:30 +01:00
Pol Henarejos
2b9a5829e5 Merge pull request #26 from sylvainpelissier/patch-1
Update pico-fido-patch-vidpid.sh
2023-11-08 14:17:49 +01:00
Sylvain Pelissier
8056e64cab Update pico-fido-patch-vidpid.sh
Match any previous VID:PID in the image and replace with the new ones.
2023-11-08 13:56:37 +01:00
Pol Henarejos
2e5b8f4c71 Upgrade to version 5.6 2023-09-18 09:01:14 +02:00
Pol Henarejos
cfcfb941e0 Merge 5.6 changes. 2023-09-17 19:13:43 +02:00
Pol Henarejos
cda97259b3 Create FUNDING.yml 2023-05-17 10:22:35 +02:00
27 changed files with 325 additions and 91 deletions

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: polhenarejos
custom: ["https://www.paypal.me/polhenarejos"]

6
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "pico-hsm-sdk"] [submodule "pico-keys-sdk"]
path = pico-hsm-sdk path = pico-keys-sdk
url = ../pico-hsm-sdk url = https://github.com/polhenarejos/pico-keys-sdk

View File

@@ -109,7 +109,7 @@ set(SOURCES ${SOURCES}
endif() endif()
set(USB_ITF_HID 1) set(USB_ITF_HID 1)
include(pico-hsm-sdk/pico_hsm_sdk_import.cmake) include(pico-keys-sdk/pico_keys_sdk_import.cmake)
set(INCLUDES ${INCLUDES} set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/fido ${CMAKE_CURRENT_LIST_DIR}/src/fido
@@ -147,5 +147,5 @@ target_compile_options(pico_fido PUBLIC
endif (APPLE) endif (APPLE)
else() else()
pico_add_extra_outputs(pico_fido) pico_add_extra_outputs(pico_fido)
target_link_libraries(pico_fido PRIVATE pico_hsm_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board) target_link_libraries(pico_fido PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)
endif() endif()

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="5" VERSION_MAJOR="5"
VERSION_MINOR="6" VERSION_MINOR="8"
rm -rf release/* rm -rf release/*
cd build_release cd build_release

View File

@@ -87,7 +87,7 @@ fi
LITTLE_VID="\x${VID:2:2}\x${VID:0:2}" LITTLE_VID="\x${VID:2:2}\x${VID:0:2}"
LITTLE_PID="\x${PID:2:2}\x${PID:0:2}" LITTLE_PID="\x${PID:2:2}\x${PID:0:2}"
perl -pi -e "s/\xfe\xca\x31\x42\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01/$LITTLE_VID$LITTLE_PID\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01/" $UF2_FILE_OF perl -pi -e "s/[\x00-\xff]{4}\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01\x00\x00/$LITTLE_VID$LITTLE_PID\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01\x00\x00/" $UF2_FILE_OF
echo "Done!" echo "Done!"
echo "" echo ""

Submodule pico-hsm-sdk deleted from a36a89cc95

1
pico-keys-sdk Submodule

Submodule pico-keys-sdk added at f0687c1ef3

View File

@@ -25,6 +25,7 @@
#include "apdu.h" #include "apdu.h"
#include "management.h" #include "management.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "version.h"
const bool _btrue = true, _bfalse = false; const bool _btrue = true, _bfalse = false;
@@ -40,6 +41,8 @@ int cbor_config(const uint8_t *data, size_t len);
int cbor_vendor(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); int cbor_large_blobs(const uint8_t *data, size_t len);
extern int cmd_read_config();
const uint8_t aaguid[16] = const uint8_t aaguid[16] =
{ 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2") { 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2")
@@ -91,6 +94,12 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
else if (cmd == CTAP_VENDOR_CBOR) { else if (cmd == CTAP_VENDOR_CBOR) {
return cbor_vendor(data, len); return cbor_vendor(data, len);
} }
else if (cmd == 0xC2) {
if (cmd_read_config() == 0x9000) {
res_APDU_size -= 1;
return 0;
}
}
} }
return CTAP1_ERR_INVALID_CMD; return CTAP1_ERR_INVALID_CMD;
} }

View File

@@ -31,7 +31,7 @@
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
uint32_t usage_timer = 0, initial_usage_time_limit = 0; uint32_t usage_timer = 0, initial_usage_time_limit = 0;
@@ -181,12 +181,12 @@ int resetPinUvAuthToken() {
int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) { int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) {
if (protocol == 1) { if (protocol == 1) {
memcpy(out, in, in_len); memcpy(out, in, in_len);
return aes_encrypt(key, NULL, 32 * 8, HSM_AES_MODE_CBC, out, in_len); return aes_encrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
} }
else if (protocol == 2) { else if (protocol == 2) {
random_gen(NULL, out, IV_SIZE); random_gen(NULL, out, IV_SIZE);
memcpy(out + IV_SIZE, in, in_len); memcpy(out + IV_SIZE, in, in_len);
return aes_encrypt(key + 32, out, 32 * 8, HSM_AES_MODE_CBC, out + IV_SIZE, in_len); return aes_encrypt(key + 32, out, 32 * 8, PICO_KEYS_AES_MODE_CBC, out + IV_SIZE, in_len);
} }
return -1; return -1;
@@ -195,11 +195,11 @@ int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_l
int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) { int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) {
if (protocol == 1) { if (protocol == 1) {
memcpy(out, in, in_len); memcpy(out, in, in_len);
return aes_decrypt(key, NULL, 32 * 8, HSM_AES_MODE_CBC, out, in_len); return aes_decrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
} }
else if (protocol == 2) { else if (protocol == 2) {
memcpy(out, in + IV_SIZE, in_len); memcpy(out, in + IV_SIZE, in_len);
return aes_decrypt(key + 32, in, 32 * 8, HSM_AES_MODE_CBC, out, in_len - IV_SIZE); return aes_decrypt(key + 32, in, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len - IV_SIZE);
} }
return -1; return -1;

View File

@@ -22,7 +22,7 @@
#include "files.h" #include "files.h"
#include "apdu.h" #include "apdu.h"
#include "credential.h" #include "credential.h"
#include "hsm.h" #include "pico_keys.h"
#include "random.h" #include "random.h"
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/chachapoly.h" #include "mbedtls/chachapoly.h"
@@ -64,7 +64,7 @@ int cbor_config(const uint8_t *data, size_t len) {
raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1); raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1);
CBOR_PARSE_MAP_START(_f1, 2) CBOR_PARSE_MAP_START(_f1, 2)
{ {
if (subcommand == 0xff) { if (subcommand == 0x7f) {
CBOR_FIELD_GET_UINT(subpara, 2); CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) { if (subpara == 0x01) {
CBOR_FIELD_GET_UINT(vendorCommandId, 2); CBOR_FIELD_GET_UINT(vendorCommandId, 2);
@@ -134,7 +134,7 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
if (subcommand == 0xff) { if (subcommand == 0x7f) {
if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE) { if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE) {
if (!file_has_data(ef_keydev_enc)) { if (!file_has_data(ef_keydev_enc)) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);

View File

@@ -22,7 +22,7 @@
#include "files.h" #include "files.h"
#include "apdu.h" #include "apdu.h"
#include "credential.h" #include "credential.h"
#include "hsm.h" #include "pico_keys.h"
uint8_t rp_counter = 1; uint8_t rp_counter = 1;
uint8_t rp_total = 0; uint8_t rp_total = 0;

View File

@@ -24,7 +24,7 @@
#include "fido.h" #include "fido.h"
#include "files.h" #include "files.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "cbor_make_credential.h" #include "cbor_make_credential.h"
#include "credential.h" #include "credential.h"

View File

@@ -21,7 +21,7 @@
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "files.h" #include "files.h"
#include "apdu.h" #include "apdu.h"
#include "hsm.h" #include "pico_keys.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
static uint64_t expectedLength = 0, expectedNextOffset = 0; static uint64_t expectedLength = 0, expectedNextOffset = 0;

View File

@@ -25,7 +25,7 @@
#include "credential.h" #include "credential.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "random.h" #include "random.h"
#include "hsm.h" #include "pico_keys.h"
int cbor_make_credential(const uint8_t *data, size_t len) { int cbor_make_credential(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;

View File

@@ -21,7 +21,7 @@
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "files.h" #include "files.h"
#include "apdu.h" #include "apdu.h"
#include "hsm.h" #include "pico_keys.h"
#include "random.h" #include "random.h"
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/chachapoly.h" #include "mbedtls/chachapoly.h"

View File

@@ -16,7 +16,7 @@
*/ */
#include "fido.h" #include "fido.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
#include "random.h" #include "random.h"

View File

@@ -16,7 +16,7 @@
*/ */
#include "fido.h" #include "fido.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
#include "random.h" #include "random.h"
@@ -32,18 +32,17 @@ const uint8_t u2f_aid[] = {
int u2f_unload(); int u2f_unload();
int u2f_process_apdu(); int u2f_process_apdu();
app_t *u2f_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { int u2f_select(app_t *a) {
if (!memcmp(aid, u2f_aid + 1, MIN(aid_len, u2f_aid[0])) && cap_supported(CAP_U2F)) { if (cap_supported(CAP_U2F)) {
a->aid = u2f_aid;
a->process_apdu = u2f_process_apdu; a->process_apdu = u2f_process_apdu;
a->unload = u2f_unload; a->unload = u2f_unload;
return a; return CCID_OK;
} }
return NULL; return CCID_ERR_FILE_NOT_FOUND;
} }
void __attribute__((constructor)) u2f_ctor() { void __attribute__((constructor)) u2f_ctor() {
register_app(u2f_select); register_app(u2f_select, u2f_aid);
} }
int u2f_unload() { int u2f_unload() {

View File

@@ -16,7 +16,7 @@
*/ */
#include "apdu.h" #include "apdu.h"
#include "hsm.h" #include "pico_keys.h"
int cmd_version() { int cmd_version() {
memcpy(res_APDU, "U2F_V2", strlen("U2F_V2")); memcpy(res_APDU, "U2F_V2", strlen("U2F_V2"));

View File

@@ -26,7 +26,7 @@
#include "ctap.h" #include "ctap.h"
#include "random.h" #include "random.h"
#include "files.h" #include "files.h"
#include "hsm.h" #include "pico_keys.h"
int credential_derive_chacha_key(uint8_t *outk); int credential_derive_chacha_key(uint8_t *outk);

View File

@@ -16,7 +16,7 @@
*/ */
#include "fido.h" #include "fido.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
#include "files.h" #include "files.h"
@@ -33,6 +33,7 @@
#include <math.h> #include <math.h>
#include "management.h" #include "management.h"
#include "ctap_hid.h" #include "ctap_hid.h"
#include "version.h"
int fido_process_apdu(); int fido_process_apdu();
int fido_unload(); int fido_unload();
@@ -42,7 +43,7 @@ pinUvAuthToken_t paut = { 0 };
uint8_t keydev_dec[32]; uint8_t keydev_dec[32];
bool has_keydev_dec = false; bool has_keydev_dec = false;
const uint8_t fido_aid[] = { const uint8_t _fido_aid[] = {
8, 8,
0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01 0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01
}; };
@@ -53,21 +54,44 @@ const uint8_t atr_fido[] = {
0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40 0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40
}; };
app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { uint8_t fido_get_version_major() {
if (!memcmp(aid, fido_aid + 1, MIN(aid_len, fido_aid[0])) && cap_supported(CAP_FIDO2)) { return PICO_FIDO_VERSION_MAJOR;
a->aid = fido_aid; }
uint8_t fido_get_version_minor() {
return PICO_FIDO_VERSION_MINOR;
}
int fido_select(app_t *a) {
if (cap_supported(CAP_FIDO2)) {
a->process_apdu = fido_process_apdu; a->process_apdu = fido_process_apdu;
a->unload = fido_unload; a->unload = fido_unload;
return a; return CCID_OK;
} }
return NULL; return CCID_ERR_FILE_NOT_FOUND;
} }
extern uint8_t (*get_version_major)();
extern uint8_t (*get_version_minor)();
extern const uint8_t *fido_aid;
extern void (*init_fido_cb)();
extern void (*cbor_thread_func)();
extern int (*cbor_process_cb)(uint8_t, const uint8_t *, size_t);
extern void cbor_thread();
extern int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len);
void __attribute__((constructor)) fido_ctor() { void __attribute__((constructor)) fido_ctor() {
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) #if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
ccid_atr = atr_fido; ccid_atr = atr_fido;
#endif #endif
register_app(fido_select); get_version_major = fido_get_version_major;
get_version_minor = fido_get_version_minor;
fido_aid = _fido_aid;
init_fido_cb = init_fido;
#ifndef ENABLE_EMULATION
cbor_thread_func = cbor_thread;
#endif
cbor_process_cb = cbor_process;
register_app(fido_select, fido_aid);
} }
int fido_unload() { int fido_unload() {
@@ -374,8 +398,10 @@ void scan_all() {
scan_files(); scan_files();
} }
extern void init_otp();
void init_fido() { void init_fido() {
scan_all(); scan_all();
init_otp();
} }
bool wait_button_pressed() { bool wait_button_pressed() {

View File

@@ -16,7 +16,7 @@
*/ */
#include "fido.h" #include "fido.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "version.h" #include "version.h"
#include "files.h" #include "files.h"
@@ -31,22 +31,20 @@ const uint8_t man_aid[] = {
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
}; };
extern void scan_all(); extern void scan_all();
app_t *man_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { extern void init_otp();
if (!memcmp(aid, man_aid + 1, MIN(aid_len, man_aid[0]))) { int man_select(app_t *a) {
a->aid = man_aid; a->process_apdu = man_process_apdu;
a->process_apdu = man_process_apdu; a->unload = man_unload;
a->unload = man_unload; sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR); res_APDU_size = strlen((char *) res_APDU);
res_APDU_size = strlen((char *) res_APDU); apdu.ne = res_APDU_size;
apdu.ne = res_APDU_size; scan_all();
scan_all(); init_otp();
return a; return CCID_OK;
}
return NULL;
} }
void __attribute__((constructor)) man_ctor() { void __attribute__((constructor)) man_ctor() {
register_app(man_select); register_app(man_select, man_aid);
} }
int man_unload() { int man_unload() {

View File

@@ -16,7 +16,7 @@
*/ */
#include "fido.h" #include "fido.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
@@ -68,9 +68,8 @@ const uint8_t oath_aid[] = {
0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01 0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01
}; };
app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { int oath_select(app_t *a) {
if (!memcmp(aid, oath_aid + 1, MIN(aid_len, oath_aid[0])) && cap_supported(CAP_OATH)) { if (cap_supported(CAP_OATH)) {
a->aid = oath_aid;
a->process_apdu = oath_process_apdu; a->process_apdu = oath_process_apdu;
a->unload = oath_unload; a->unload = oath_unload;
res_APDU_size = 0; res_APDU_size = 0;
@@ -82,10 +81,10 @@ app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = 8; res_APDU[res_APDU_size++] = 8;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
pico_get_unique_board_id((pico_unique_board_id_t *) (res_APDU + res_APDU_size)); pico_get_unique_board_id((pico_unique_board_id_t *) (res_APDU + res_APDU_size));
res_APDU_size += 8; res_APDU_size += 8;
#else #else
memset(res_APDU + res_APDU_size, 0, 8); res_APDU_size += 8; memset(res_APDU + res_APDU_size, 0, 8); res_APDU_size += 8;
#endif #endif
if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) { if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) {
random_gen(NULL, challenge, sizeof(challenge)); random_gen(NULL, challenge, sizeof(challenge));
@@ -105,13 +104,13 @@ app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = ALG_HMAC_SHA1; res_APDU[res_APDU_size++] = ALG_HMAC_SHA1;
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return a; return CCID_OK;
} }
return NULL; return CCID_ERR_FILE_NOT_FOUND;
} }
void __attribute__((constructor)) oath_ctor() { void __attribute__((constructor)) oath_ctor() {
register_app(oath_select); register_app(oath_select, oath_aid);
} }
int oath_unload() { int oath_unload() {
@@ -455,6 +454,7 @@ int cmd_calculate_all() {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) { if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
res_APDU_size = 0;
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file(EF_OATH_CRED + i); file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef)) { if (file_has_data(ef)) {

View File

@@ -16,7 +16,7 @@
*/ */
#include "fido.h" #include "fido.h"
#include "hsm.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
@@ -111,14 +111,20 @@ uint16_t otp_status();
int otp_process_apdu(); int otp_process_apdu();
int otp_unload(); int otp_unload();
#ifndef ENABLE_EMULATION
extern int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t);
extern uint16_t (*hid_get_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t);
int otp_hid_set_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t);
uint16_t otp_hid_get_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t);
#endif
const uint8_t otp_aid[] = { const uint8_t otp_aid[] = {
7, 7,
0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01
}; };
app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { int otp_select(app_t *a) {
if (!memcmp(aid, otp_aid + 1, MIN(aid_len, otp_aid[0])) && cap_supported(CAP_OTP)) { if (cap_supported(CAP_OTP)) {
a->aid = otp_aid;
a->process_apdu = otp_process_apdu; a->process_apdu = otp_process_apdu;
a->unload = otp_unload; a->unload = otp_unload;
if (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) || if (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ||
@@ -132,9 +138,9 @@ app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
memmove(res_APDU, res_APDU + 1, 6); memmove(res_APDU, res_APDU + 1, 6);
res_APDU_size = 6; res_APDU_size = 6;
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return a; return CCID_OK;
} }
return NULL; return CCID_ERR_FILE_NOT_FOUND;
} }
uint8_t modhex_tab[] = uint8_t modhex_tab[] =
@@ -176,6 +182,22 @@ extern int calculate_oath(uint8_t truncate,
size_t key_len, size_t key_len,
const uint8_t *chal, const uint8_t *chal,
size_t chal_len); size_t chal_len);
uint16_t calculate_crc(const uint8_t *data, size_t data_len) {
uint16_t crc = 0xFFFF;
for (size_t idx = 0; idx < data_len; idx++) {
crc ^= data[idx];
for (uint8_t i = 0; i < 8; i++) {
uint16_t j = crc & 0x1;
crc >>= 1;
if (j == 1) {
crc ^= 0x8408;
}
}
}
return crc & 0xFFFF;
}
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
static uint8_t session_counter[2] = { 0 }; static uint8_t session_counter[2] = { 0 };
#endif #endif
@@ -244,10 +266,11 @@ int otp_button_pressed(uint8_t slot) {
} }
} }
else if (otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET) { else if (otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET) {
if (otp_config->cfg_flags & SHORT_TICKET) { uint8_t fixed_size = FIXED_SIZE + UID_SIZE + KEY_SIZE;
otp_config->fixed_size /= 2; if (otp_config->cfg_flags & SHORT_TICKET) { // Not clear which is the purpose of SHORT_TICKET
//fixed_size /= 2;
} }
add_keyboard_buffer(otp_config->fixed_data, otp_config->fixed_size, false); add_keyboard_buffer(otp_config->fixed_data, fixed_size, false);
if (otp_config->tkt_flags & APPEND_CR) { if (otp_config->tkt_flags & APPEND_CR) {
append_keyboard_buffer((const uint8_t *) "\x28", 1); append_keyboard_buffer((const uint8_t *) "\x28", 1);
} }
@@ -308,8 +331,12 @@ int otp_button_pressed(uint8_t slot) {
} }
void __attribute__((constructor)) otp_ctor() { void __attribute__((constructor)) otp_ctor() {
register_app(otp_select); register_app(otp_select, otp_aid);
button_pressed_cb = otp_button_pressed; button_pressed_cb = otp_button_pressed;
#ifndef ENABLE_EMULATION
hid_set_report_cb = otp_hid_set_report_cb;
hid_get_report_cb = otp_hid_get_report_cb;
#endif
} }
int otp_unload() { int otp_unload() {
@@ -489,3 +516,110 @@ int otp_process_apdu() {
} }
return SW_INS_NOT_SUPPORTED(); return SW_INS_NOT_SUPPORTED();
} }
#ifndef ENABLE_EMULATION
uint8_t otp_frame_rx[70] = {0};
uint8_t otp_frame_tx[70] = {0};
uint8_t otp_exp_seq = 0, otp_curr_seq = 0;
uint8_t otp_header[4] = {0};
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;
*get_send_buffer_size(ITF_KEYBOARD) = frame_len;
otp_exp_seq = (frame_len / 7);
if (frame_len % 7) {
otp_exp_seq++;
}
otp_curr_seq = 0;
return 0;
}
int otp_hid_set_report_cb(uint8_t itf,
uint8_t report_id,
hid_report_type_t report_type,
uint8_t const *buffer,
uint16_t bufsize)
{
if (report_type == 3) {
DEBUG_PAYLOAD(buffer, bufsize);
if (itf == ITF_KEYBOARD && buffer[7] == 0xFF) { // reset
*get_send_buffer_size(ITF_KEYBOARD) = 0;
otp_curr_seq = otp_exp_seq = 0;
memset(otp_frame_tx, 0, sizeof(otp_frame_tx));
}
else if (buffer[7] & 0x80) { // a frame
uint8_t rseq = buffer[7] & 0x1F;
if (rseq < 10) {
if (rseq == 0) {
memset(otp_frame_rx, 0, sizeof(otp_frame_rx));
}
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]);
uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) {
apdu.data = otp_frame_rx;
apdu.nc = 64;
apdu.rdata = otp_frame_tx;
apdu.header[0] = 0;
apdu.header[1] = 0x01;
apdu.header[2] = slot_id;
apdu.header[3] = 0;
int ret = otp_process_apdu();
if (ret == 0x9000 && res_APDU_size > 0) {
otp_send_frame(apdu.rdata, apdu.rlen);
}
}
else {
printf("[OTP] Bad CRC!\n");
}
}
}
}
return 1;
}
return 0;
}
uint16_t otp_hid_get_report_cb(uint8_t itf,
uint8_t report_id,
hid_report_type_t report_type,
uint8_t *buffer,
uint16_t reqlen) {
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
uint16_t send_buffer_size = *get_send_buffer_size(ITF_KEYBOARD);
if (send_buffer_size > 0) {
uint8_t seq = otp_curr_seq++;
memset(buffer, 0, 8);
memcpy(buffer, otp_frame_tx + 7 * seq, MIN(7, send_buffer_size));
buffer[7] = 0x40 | seq;
DEBUG_DATA(buffer, 8);
*get_send_buffer_size(ITF_KEYBOARD) -= MIN(7, send_buffer_size);
}
else if (otp_curr_seq == otp_exp_seq && otp_exp_seq > 0) {
memset(buffer, 0, 7);
buffer[7] = 0x40;
DEBUG_DATA(buffer,8);
otp_curr_seq = otp_exp_seq = 0;
}
else {
otp_status();
memcpy(buffer, res_APDU, 7);
}
return reqlen;
}
#endif

View File

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

View File

@@ -23,7 +23,6 @@ import sys
import argparse import argparse
import platform import platform
from binascii import hexlify from binascii import hexlify
from words import words
from threading import Event from threading import Event
from typing import Mapping, Any, Optional, Callable from typing import Mapping, Any, Optional, Callable
import struct import struct
@@ -33,7 +32,7 @@ from enum import IntEnum, unique
try: try:
from fido2.ctap2.config import Config from fido2.ctap2.config import Config
from fido2.ctap2 import Ctap2 from fido2.ctap2 import Ctap2, ClientPin, PinProtocolV2
from fido2.hid import CtapHidDevice, CTAPHID from fido2.hid import CtapHidDevice, CTAPHID
from fido2.utils import bytes2int, int2bytes from fido2.utils import bytes2int, int2bytes
from fido2 import cbor from fido2 import cbor
@@ -58,14 +57,6 @@ except:
from enum import IntEnum from enum import IntEnum
from binascii import hexlify from binascii import hexlify
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
def get_pki_data(url, data=None, method='GET'): def get_pki_data(url, data=None, method='GET'):
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; ' user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; '
'rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7' 'rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
@@ -90,6 +81,7 @@ class VendorConfig(Config):
class CMD(IntEnum): class CMD(IntEnum):
CONFIG_AUT_ENABLE = 0x03e43f56b34285e2 CONFIG_AUT_ENABLE = 0x03e43f56b34285e2
CONFIG_AUT_DISABLE = 0x1831a40f04a25ed9 CONFIG_AUT_DISABLE = 0x1831a40f04a25ed9
CONFIG_VENDOR_PROTOTYPE = 0x7f
class RESP(IntEnum): class RESP(IntEnum):
KEY_AGREEMENT = 0x01 KEY_AGREEMENT = 0x01
@@ -99,7 +91,7 @@ class VendorConfig(Config):
def enable_device_aut(self, ct): def enable_device_aut(self, ct):
self._call( self._call(
Config.CMD.VENDOR_PROTOTYPE, VendorConfig.CMD.CONFIG_VENDOR_PROTOTYPE,
{ {
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_ENABLE, VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_ENABLE,
VendorConfig.PARAM.VENDOR_AUT_CT: ct VendorConfig.PARAM.VENDOR_AUT_CT: ct
@@ -108,7 +100,7 @@ class VendorConfig(Config):
def disable_device_aut(self): def disable_device_aut(self):
self._call( self._call(
Config.CMD.VENDOR_PROTOTYPE, VendorConfig.CMD.CONFIG_VENDOR_PROTOTYPE,
{ {
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_DISABLE VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_DISABLE
}, },
@@ -230,7 +222,7 @@ class Vendor:
self.__key_enc = None self.__key_enc = None
self.__iv = None self.__iv = None
self.vcfg = VendorConfig(ctap) self.vcfg = VendorConfig(ctap, pin_uv_protocol=pin_uv_protocol, pin_uv_token=pin_uv_token)
def _call(self, cmd, sub_cmd, params=None): def _call(self, cmd, sub_cmd, params=None):
if params: if params:
@@ -252,6 +244,14 @@ class Vendor:
return self.ctap.vendor(cmd, sub_cmd, params, pin_uv_protocol, pin_uv_param) return self.ctap.vendor(cmd, sub_cmd, params, pin_uv_protocol, pin_uv_param)
def backup_save(self, filename): def backup_save(self, filename):
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
from words import words
ret = self._call( ret = self._call(
Vendor.CMD.VENDOR_BACKUP, Vendor.CMD.VENDOR_BACKUP,
Vendor.SUBCMD.ENABLE, Vendor.SUBCMD.ENABLE,
@@ -270,6 +270,14 @@ class Vendor:
print(f'{(c+1):02d} - {words[coef]}') print(f'{(c+1):02d} - {words[coef]}')
def backup_load(self, filename): def backup_load(self, filename):
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
from words import words
d = 0 d = 0
if (d == 0): if (d == 0):
for c in range(24): for c in range(24):
@@ -349,6 +357,13 @@ class Vendor:
) )
def _get_key_device(self): def _get_key_device(self):
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
return skey.get_secure_key() return skey.get_secure_key()
def get_skey(self): def get_skey(self):
@@ -381,6 +396,7 @@ class Vendor:
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
subparser = parser.add_subparsers(title="commands", dest="command") subparser = parser.add_subparsers(title="commands", dest="command")
parser.add_argument('-p','--pin', help='Specify the PIN of the device.', required=True)
parser_secure = subparser.add_parser('secure', help='Manages security of Pico Fido.') parser_secure = subparser.add_parser('secure', help='Manages security of Pico Fido.')
parser_secure.add_argument('subcommand', choices=['enable', 'disable', 'unlock'], help='Enables, disables or unlocks the security.') parser_secure.add_argument('subcommand', choices=['enable', 'disable', 'unlock'], help='Enables, disables or unlocks the security.')
@@ -426,15 +442,17 @@ def attestation(vdr, args):
vdr.upload_ea(cert.public_bytes(Encoding.DER)) vdr.upload_ea(cert.public_bytes(Encoding.DER))
def main(args): def main(args):
print('Pico Fido Tool v1.4') print('Pico Fido Tool v1.6')
print('Author: Pol Henarejos') print('Author: Pol Henarejos')
print('Report bugs to https://github.com/polhenarejos/pico-fido/issues') print('Report bugs to https://github.com/polhenarejos/pico-fido/issues')
print('') print('')
print('') print('')
dev = next(CtapHidDevice.list_devices(), None) dev = next(CtapHidDevice.list_devices(), None)
ctap = Ctap2Vendor(dev)
vdr = Vendor(Ctap2Vendor(dev)) client_pin = ClientPin(ctap)
token = client_pin.get_pin_token(args.pin, permissions=ClientPin.PERMISSION.AUTHENTICATOR_CFG)
vdr = Vendor(ctap, pin_uv_protocol=PinProtocolV2(), pin_uv_token=token)
if (args.command == 'secure'): if (args.command == 'secure'):
secure(vdr, args) secure(vdr, args)

View File

@@ -51,7 +51,9 @@ def get_secure_key():
try: try:
backend = get_backend(False) backend = get_backend(False)
key = backend.get_password(DOMAIN, USERNAME)[0] key = backend.get_password(DOMAIN, USERNAME)[0]
except keyring.errors.KeyringError: if (key is None):
raise TypeError
except (keyring.errors.KeyringError, TypeError):
try: try:
key = generate_secure_key(False)[0] # It should be True, but secure enclave causes python segfault key = generate_secure_key(False)[0] # It should be True, but secure enclave causes python segfault
except keyring.errors.PasswordSetError: except keyring.errors.PasswordSetError:

View File

@@ -0,0 +1,44 @@
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())