Compare commits
55 Commits
v5.8
...
v5.8-eddsa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21765a6f10 | ||
|
|
eb2c92bc5c | ||
|
|
20a8ef08f0 | ||
|
|
e757ad2945 | ||
|
|
1ce0d98c34 | ||
|
|
96de6efed6 | ||
|
|
195096ad52 | ||
|
|
1ee86f8634 | ||
|
|
ffb3beb84a | ||
|
|
d78d9d10aa | ||
|
|
f8d4f1d02e | ||
|
|
b493a81ddc | ||
|
|
5c20909b03 | ||
|
|
27b9e3954a | ||
|
|
440ec5c854 | ||
|
|
cb2744cab3 | ||
|
|
5db1014850 | ||
|
|
421bea6421 | ||
|
|
65039c0959 | ||
|
|
8e36b4c379 | ||
|
|
3652368542 | ||
|
|
e5d1ef29a4 | ||
|
|
0fd36806cc | ||
|
|
7bf26b28fc | ||
|
|
da94a82487 | ||
|
|
c24be5a631 | ||
|
|
46ce9390bf | ||
|
|
c1fd5736f9 | ||
|
|
b1c4ff877e | ||
|
|
6c85d57412 | ||
|
|
233c5a7c7d | ||
|
|
3b4ac12d0f | ||
|
|
7c5bab8b05 | ||
|
|
21035d649d | ||
|
|
abe91823c0 | ||
|
|
91e049b997 | ||
|
|
8836902dc1 | ||
|
|
a019b54d69 | ||
|
|
3adb1a8422 | ||
|
|
95a9fe4214 | ||
|
|
8af7cac57a | ||
|
|
7997eefdc8 | ||
|
|
e18f841a34 | ||
|
|
73b51cabfc | ||
|
|
ad3b2bbe4b | ||
|
|
b9ad8f4745 | ||
|
|
8242dc8d80 | ||
|
|
2f6e4d5568 | ||
|
|
911dab031e | ||
|
|
3a71275bc8 | ||
|
|
9f1e879efe | ||
|
|
57bf97196d | ||
|
|
e8c8ce4d15 | ||
|
|
69d618cc6b | ||
|
|
e057f17180 |
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -13,10 +13,10 @@ name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "development" ]
|
||||
branches: [ "main", "development", "eddsa" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "main", "development" ]
|
||||
branches: [ "main", "development", "eddsa" ]
|
||||
schedule:
|
||||
- cron: '23 5 * * 4'
|
||||
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -13,10 +13,10 @@ name: "Emulation and test"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "development" ]
|
||||
branches: [ "main", "development", "eddsa" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "main", "development" ]
|
||||
branches: [ "main", "development", "eddsa" ]
|
||||
schedule:
|
||||
- cron: '23 5 * * 4'
|
||||
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "pico-hsm-sdk"]
|
||||
path = pico-hsm-sdk
|
||||
url = ../pico-hsm-sdk
|
||||
[submodule "pico-keys-sdk"]
|
||||
path = pico-keys-sdk
|
||||
url = https://github.com/polhenarejos/pico-keys-sdk
|
||||
|
||||
@@ -109,7 +109,7 @@ set(SOURCES ${SOURCES}
|
||||
endif()
|
||||
|
||||
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}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido
|
||||
@@ -147,5 +147,5 @@ target_compile_options(pico_fido PUBLIC
|
||||
endif (APPLE)
|
||||
else()
|
||||
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()
|
||||
|
||||
@@ -13,8 +13,8 @@ Pico FIDO has implemented the following features:
|
||||
- User Verification with PIN
|
||||
- Discoverable credentials
|
||||
- Credential management
|
||||
- ECDSA authentication
|
||||
- Authentication with SECP256R1, SECP384R1, SECP521R1 and SECP256K1 curves.
|
||||
- ECDSA and EDDSA authentication
|
||||
- Authentication with SECP256R1, SECP384R1, SECP521R1, SECP256K1 and Ed25519 curves
|
||||
- App registration and login
|
||||
- Device selection
|
||||
- Support for vendor Config
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION_MAJOR="5"
|
||||
VERSION_MINOR="6"
|
||||
VERSION_MINOR="8-eddsa1"
|
||||
|
||||
rm -rf release/*
|
||||
cd build_release
|
||||
|
||||
Submodule pico-hsm-sdk deleted from a36a89cc95
1
pico-keys-sdk
Submodule
1
pico-keys-sdk
Submodule
Submodule pico-keys-sdk added at e5e2169a47
@@ -25,6 +25,7 @@
|
||||
#include "apdu.h"
|
||||
#include "management.h"
|
||||
#include "ctap2_cbor.h"
|
||||
#include "version.h"
|
||||
|
||||
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_large_blobs(const uint8_t *data, size_t len);
|
||||
|
||||
extern int cmd_read_config();
|
||||
|
||||
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")
|
||||
|
||||
@@ -91,6 +94,12 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
|
||||
else if (cmd == CTAP_VENDOR_CBOR) {
|
||||
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;
|
||||
}
|
||||
@@ -199,6 +208,9 @@ CborError COSE_key(mbedtls_ecp_keypair *key, CborEncoder *mapEncoderParent,
|
||||
else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
|
||||
alg = FIDO2_ALG_ECDH_ES_HKDF_256;
|
||||
}
|
||||
else if (key->grp.id == MBEDTLS_ECP_DP_ED25519) {
|
||||
alg = FIDO2_ALG_EDDSA;
|
||||
}
|
||||
return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder);
|
||||
}
|
||||
CborError COSE_key_shared(mbedtls_ecdh_context *key,
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "files.h"
|
||||
#include "random.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
|
||||
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) {
|
||||
if (protocol == 1) {
|
||||
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) {
|
||||
random_gen(NULL, out, IV_SIZE);
|
||||
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;
|
||||
@@ -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) {
|
||||
if (protocol == 1) {
|
||||
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) {
|
||||
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;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "files.h"
|
||||
#include "apdu.h"
|
||||
#include "credential.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "random.h"
|
||||
#include "mbedtls/ecdh.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);
|
||||
CBOR_PARSE_MAP_START(_f1, 2)
|
||||
{
|
||||
if (subcommand == 0xff) {
|
||||
if (subcommand == 0x7f) {
|
||||
CBOR_FIELD_GET_UINT(subpara, 2);
|
||||
if (subpara == 0x01) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (subcommand == 0xff) {
|
||||
if (subcommand == 0x7f) {
|
||||
if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE) {
|
||||
if (!file_has_data(ef_keydev_enc)) {
|
||||
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "files.h"
|
||||
#include "apdu.h"
|
||||
#include "credential.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
|
||||
uint8_t rp_counter = 1;
|
||||
uint8_t rp_total = 0;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "fido.h"
|
||||
#include "files.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "cbor_make_credential.h"
|
||||
#include "credential.h"
|
||||
@@ -406,12 +406,12 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
|
||||
flags = flagsx;
|
||||
selcred = &credsx[credentialCounter];
|
||||
}
|
||||
mbedtls_ecdsa_context ekey;
|
||||
mbedtls_ecdsa_init(&ekey);
|
||||
mbedtls_ecp_keypair ekey;
|
||||
mbedtls_ecp_keypair_init(&ekey);
|
||||
int ret = fido_load_key(selcred->curve, selcred->id.data, &ekey);
|
||||
if (ret != 0) {
|
||||
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
CBOR_ERROR(CTAP1_ERR_OTHER);
|
||||
}
|
||||
}
|
||||
@@ -559,21 +559,42 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
|
||||
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
|
||||
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||
}
|
||||
ret = mbedtls_md(md,
|
||||
aut_data,
|
||||
aut_data_len + clientDataHash.len,
|
||||
hash);
|
||||
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
|
||||
md = NULL;
|
||||
}
|
||||
size_t olen = 0;
|
||||
ret = mbedtls_ecdsa_write_signature(&ekey,
|
||||
mbedtls_md_get_type(md),
|
||||
hash,
|
||||
mbedtls_md_get_size(md),
|
||||
sig,
|
||||
sizeof(sig),
|
||||
&olen,
|
||||
random_gen,
|
||||
NULL);
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
if (md != NULL) {
|
||||
ret = mbedtls_md(md,
|
||||
aut_data,
|
||||
aut_data_len + clientDataHash.len,
|
||||
hash);
|
||||
ret = mbedtls_ecdsa_write_signature(&ekey,
|
||||
mbedtls_md_get_type(md),
|
||||
hash,
|
||||
mbedtls_md_get_size(md),
|
||||
sig,
|
||||
sizeof(sig),
|
||||
&olen,
|
||||
random_gen,
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
ret = mbedtls_eddsa_write_signature(&ekey,
|
||||
aut_data,
|
||||
aut_data_len + clientDataHash.len,
|
||||
sig,
|
||||
sizeof(sig),
|
||||
&olen,
|
||||
MBEDTLS_EDDSA_PURE,
|
||||
NULL,
|
||||
0,
|
||||
random_gen,
|
||||
NULL);
|
||||
}
|
||||
if (ret != 0) {
|
||||
CBOR_ERROR(CTAP2_ERR_PROCESSING);
|
||||
}
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
|
||||
uint8_t lfields = 3;
|
||||
if (selcred->opts.present == true && selcred->opts.rk == ptrue) {
|
||||
|
||||
@@ -90,11 +90,14 @@ int cbor_get_info() {
|
||||
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH
|
||||
|
||||
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A));
|
||||
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 4));
|
||||
|
||||
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 5));
|
||||
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2));
|
||||
CBOR_CHECK(COSE_public_key(FIDO2_ALG_EDDSA, &arrayEncoder, &mapEncoder2));
|
||||
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES384, &arrayEncoder, &mapEncoder2));
|
||||
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2));
|
||||
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2));
|
||||
|
||||
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
|
||||
|
||||
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "hid/ctap_hid.h"
|
||||
#include "files.h"
|
||||
#include "apdu.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
static uint64_t expectedLength = 0, expectedNextOffset = 0;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "credential.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "random.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
|
||||
int cbor_make_credential(const uint8_t *data, size_t len) {
|
||||
CborParser parser;
|
||||
@@ -221,6 +221,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
|
||||
if (curve <= 0) {
|
||||
curve = FIDO2_CURVE_P256K1;
|
||||
}
|
||||
}
|
||||
else if (pubKeyCredParams[i].alg == FIDO2_ALG_EDDSA) {
|
||||
if (curve <= 0) {
|
||||
curve = FIDO2_CURVE_ED25519;
|
||||
}
|
||||
}
|
||||
else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
|
||||
// pass
|
||||
@@ -386,16 +391,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
|
||||
ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
|
||||
flags |= FIDO2_AUT_FLAG_ED;
|
||||
}
|
||||
mbedtls_ecdsa_context ekey;
|
||||
mbedtls_ecdsa_init(&ekey);
|
||||
mbedtls_ecp_keypair ekey;
|
||||
mbedtls_ecp_keypair_init(&ekey);
|
||||
int ret = fido_load_key(curve, cred_id, &ekey);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
CBOR_ERROR(CTAP1_ERR_OTHER);
|
||||
}
|
||||
const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id);
|
||||
if (cinfo == NULL) {
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
CBOR_ERROR(CTAP1_ERR_OTHER);
|
||||
}
|
||||
size_t olen = 0;
|
||||
@@ -421,7 +426,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
|
||||
memcpy(pa, cbor_buf, rs); pa += rs;
|
||||
memcpy(pa, ext, ext_len); pa += ext_len;
|
||||
if (pa - aut_data != aut_data_len) {
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
CBOR_ERROR(CTAP1_ERR_OTHER);
|
||||
}
|
||||
|
||||
@@ -434,29 +439,51 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
|
||||
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
|
||||
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||
}
|
||||
ret = mbedtls_md(md,
|
||||
aut_data,
|
||||
aut_data_len + clientDataHash.len,
|
||||
hash);
|
||||
|
||||
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
|
||||
md = NULL;
|
||||
}
|
||||
if (md != NULL) {
|
||||
ret = mbedtls_md(md,
|
||||
aut_data,
|
||||
aut_data_len + clientDataHash.len,
|
||||
hash);
|
||||
}
|
||||
bool self_attestation = true;
|
||||
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
mbedtls_ecdsa_init(&ekey);
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
mbedtls_ecp_keypair_init(&ekey);
|
||||
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), 32);
|
||||
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
self_attestation = false;
|
||||
}
|
||||
ret = mbedtls_ecdsa_write_signature(&ekey,
|
||||
mbedtls_md_get_type(md),
|
||||
hash,
|
||||
mbedtls_md_get_size(md),
|
||||
sig,
|
||||
sizeof(sig),
|
||||
&olen,
|
||||
random_gen,
|
||||
NULL);
|
||||
mbedtls_ecdsa_free(&ekey);
|
||||
if (md != NULL) {
|
||||
ret = mbedtls_ecdsa_write_signature(&ekey,
|
||||
mbedtls_md_get_type(md),
|
||||
hash,
|
||||
mbedtls_md_get_size(md),
|
||||
sig,
|
||||
sizeof(sig),
|
||||
&olen,
|
||||
random_gen,
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
ret = mbedtls_eddsa_write_signature(&ekey,
|
||||
aut_data,
|
||||
aut_data_len + clientDataHash.len,
|
||||
sig,
|
||||
sizeof(sig),
|
||||
&olen,
|
||||
MBEDTLS_EDDSA_PURE,
|
||||
NULL,
|
||||
0,
|
||||
random_gen,
|
||||
NULL);
|
||||
}
|
||||
if (ret != 0) {
|
||||
CBOR_ERROR(CTAP2_ERR_PROCESSING);
|
||||
}
|
||||
mbedtls_ecp_keypair_free(&ekey);
|
||||
|
||||
uint8_t largeBlobKey[32];
|
||||
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "hid/ctap_hid.h"
|
||||
#include "files.h"
|
||||
#include "apdu.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "random.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
#include "mbedtls/chachapoly.h"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "ctap.h"
|
||||
#include "random.h"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "ctap.h"
|
||||
#include "random.h"
|
||||
@@ -32,18 +32,17 @@ const uint8_t u2f_aid[] = {
|
||||
int u2f_unload();
|
||||
int u2f_process_apdu();
|
||||
|
||||
app_t *u2f_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
|
||||
if (!memcmp(aid, u2f_aid + 1, MIN(aid_len, u2f_aid[0])) && cap_supported(CAP_U2F)) {
|
||||
a->aid = u2f_aid;
|
||||
int u2f_select(app_t *a) {
|
||||
if (cap_supported(CAP_U2F)) {
|
||||
a->process_apdu = u2f_process_apdu;
|
||||
a->unload = u2f_unload;
|
||||
return a;
|
||||
return CCID_OK;
|
||||
}
|
||||
return NULL;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) u2f_ctor() {
|
||||
register_app(u2f_select);
|
||||
register_app(u2f_select, u2f_aid);
|
||||
}
|
||||
|
||||
int u2f_unload() {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "apdu.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
|
||||
int cmd_version() {
|
||||
memcpy(res_APDU, "U2F_V2", strlen("U2F_V2"));
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "ctap.h"
|
||||
#include "random.h"
|
||||
#include "files.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
|
||||
int credential_derive_chacha_key(uint8_t *outk);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "ctap.h"
|
||||
#include "files.h"
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <math.h>
|
||||
#include "management.h"
|
||||
#include "ctap_hid.h"
|
||||
#include "version.h"
|
||||
|
||||
int fido_process_apdu();
|
||||
int fido_unload();
|
||||
@@ -42,7 +43,7 @@ pinUvAuthToken_t paut = { 0 };
|
||||
uint8_t keydev_dec[32];
|
||||
bool has_keydev_dec = false;
|
||||
|
||||
const uint8_t fido_aid[] = {
|
||||
const uint8_t _fido_aid[] = {
|
||||
8,
|
||||
0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01
|
||||
};
|
||||
@@ -53,21 +54,44 @@ const uint8_t atr_fido[] = {
|
||||
0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40
|
||||
};
|
||||
|
||||
app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
|
||||
if (!memcmp(aid, fido_aid + 1, MIN(aid_len, fido_aid[0])) && cap_supported(CAP_FIDO2)) {
|
||||
a->aid = fido_aid;
|
||||
uint8_t fido_get_version_major() {
|
||||
return PICO_FIDO_VERSION_MAJOR;
|
||||
}
|
||||
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->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() {
|
||||
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
|
||||
ccid_atr = atr_fido;
|
||||
#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() {
|
||||
@@ -93,6 +117,12 @@ mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
|
||||
else if (curve == FIDO2_CURVE_X448) {
|
||||
return MBEDTLS_ECP_DP_CURVE448;
|
||||
}
|
||||
else if (curve == FIDO2_CURVE_ED25519) {
|
||||
return MBEDTLS_ECP_DP_ED25519;
|
||||
}
|
||||
else if (curve == FIDO2_CURVE_ED448) {
|
||||
return MBEDTLS_ECP_DP_ED448;
|
||||
}
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
|
||||
@@ -114,10 +144,16 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
|
||||
else if (id == MBEDTLS_ECP_DP_CURVE448) {
|
||||
return FIDO2_CURVE_X448;
|
||||
}
|
||||
else if (id == MBEDTLS_ECP_DP_ED25519) {
|
||||
return FIDO2_CURVE_ED25519;
|
||||
}
|
||||
else if (id == MBEDTLS_ECP_DP_ED448) {
|
||||
return FIDO2_CURVE_ED448;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) {
|
||||
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key) {
|
||||
mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve);
|
||||
if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) {
|
||||
return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
|
||||
@@ -174,7 +210,7 @@ int load_keydev(uint8_t *key) {
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) {
|
||||
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) {
|
||||
for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
|
||||
uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
|
||||
if (!(k & 0x80000000)) {
|
||||
@@ -216,7 +252,7 @@ int derive_key(const uint8_t *app_id,
|
||||
bool new_key,
|
||||
uint8_t *key_handle,
|
||||
int curve,
|
||||
mbedtls_ecdsa_context *key) {
|
||||
mbedtls_ecp_keypair *key) {
|
||||
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length
|
||||
int r = 0;
|
||||
memset(outk, 0, sizeof(outk));
|
||||
@@ -270,6 +306,9 @@ int derive_key(const uint8_t *app_id,
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
if (curve == MBEDTLS_ECP_DP_ED25519) {
|
||||
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
|
||||
}
|
||||
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
|
||||
}
|
||||
mbedtls_platform_zeroize(outk, sizeof(outk));
|
||||
@@ -374,8 +413,10 @@ void scan_all() {
|
||||
scan_files();
|
||||
}
|
||||
|
||||
extern void init_otp();
|
||||
void init_fido() {
|
||||
scan_all();
|
||||
init_otp();
|
||||
}
|
||||
|
||||
bool wait_button_pressed() {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#endif
|
||||
#include "common.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/eddsa.h"
|
||||
#ifndef ENABLE_EMULATION
|
||||
#include "ctap_hid.h"
|
||||
#else
|
||||
@@ -40,13 +41,13 @@ extern int derive_key(const uint8_t *app_id,
|
||||
bool new_key,
|
||||
uint8_t *key_handle,
|
||||
int,
|
||||
mbedtls_ecdsa_context *key);
|
||||
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *);
|
||||
mbedtls_ecp_keypair *key);
|
||||
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
|
||||
extern bool wait_button_pressed();
|
||||
extern void init_fido();
|
||||
extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve);
|
||||
extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id);
|
||||
extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key);
|
||||
extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key);
|
||||
extern int load_keydev(uint8_t *key);
|
||||
extern int encrypt(uint8_t protocol,
|
||||
const uint8_t *key,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "version.h"
|
||||
#include "files.h"
|
||||
@@ -31,22 +31,20 @@ const uint8_t man_aid[] = {
|
||||
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
|
||||
};
|
||||
extern void scan_all();
|
||||
app_t *man_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
|
||||
if (!memcmp(aid, man_aid + 1, MIN(aid_len, man_aid[0]))) {
|
||||
a->aid = man_aid;
|
||||
a->process_apdu = man_process_apdu;
|
||||
a->unload = man_unload;
|
||||
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
|
||||
res_APDU_size = strlen((char *) res_APDU);
|
||||
apdu.ne = res_APDU_size;
|
||||
scan_all();
|
||||
return a;
|
||||
}
|
||||
return NULL;
|
||||
extern void init_otp();
|
||||
int man_select(app_t *a) {
|
||||
a->process_apdu = man_process_apdu;
|
||||
a->unload = man_unload;
|
||||
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
|
||||
res_APDU_size = strlen((char *) res_APDU);
|
||||
apdu.ne = res_APDU_size;
|
||||
scan_all();
|
||||
init_otp();
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) man_ctor() {
|
||||
register_app(man_select);
|
||||
register_app(man_select, man_aid);
|
||||
}
|
||||
|
||||
int man_unload() {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "files.h"
|
||||
#include "random.h"
|
||||
@@ -68,9 +68,8 @@ const uint8_t oath_aid[] = {
|
||||
0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01
|
||||
};
|
||||
|
||||
app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
|
||||
if (!memcmp(aid, oath_aid + 1, MIN(aid_len, oath_aid[0])) && cap_supported(CAP_OATH)) {
|
||||
a->aid = oath_aid;
|
||||
int oath_select(app_t *a) {
|
||||
if (cap_supported(CAP_OATH)) {
|
||||
a->process_apdu = oath_process_apdu;
|
||||
a->unload = oath_unload;
|
||||
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++] = 8;
|
||||
#ifndef ENABLE_EMULATION
|
||||
pico_get_unique_board_id((pico_unique_board_id_t *) (res_APDU + res_APDU_size));
|
||||
res_APDU_size += 8;
|
||||
pico_get_unique_board_id((pico_unique_board_id_t *) (res_APDU + res_APDU_size));
|
||||
res_APDU_size += 8;
|
||||
#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
|
||||
if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) {
|
||||
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++] = ALG_HMAC_SHA1;
|
||||
apdu.ne = res_APDU_size;
|
||||
return a;
|
||||
return CCID_OK;
|
||||
}
|
||||
return NULL;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) oath_ctor() {
|
||||
register_app(oath_select);
|
||||
register_app(oath_select, oath_aid);
|
||||
}
|
||||
|
||||
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) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
res_APDU_size = 0;
|
||||
for (int i = 0; i < MAX_OATH_CRED; i++) {
|
||||
file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
|
||||
if (file_has_data(ef)) {
|
||||
|
||||
154
src/fido/otp.c
154
src/fido/otp.c
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "hsm.h"
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "files.h"
|
||||
#include "random.h"
|
||||
@@ -111,14 +111,20 @@ uint16_t otp_status();
|
||||
int otp_process_apdu();
|
||||
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[] = {
|
||||
7,
|
||||
0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01
|
||||
};
|
||||
|
||||
app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
|
||||
if (!memcmp(aid, otp_aid + 1, MIN(aid_len, otp_aid[0])) && cap_supported(CAP_OTP)) {
|
||||
a->aid = otp_aid;
|
||||
int otp_select(app_t *a) {
|
||||
if (cap_supported(CAP_OTP)) {
|
||||
a->process_apdu = otp_process_apdu;
|
||||
a->unload = otp_unload;
|
||||
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);
|
||||
res_APDU_size = 6;
|
||||
apdu.ne = res_APDU_size;
|
||||
return a;
|
||||
return CCID_OK;
|
||||
}
|
||||
return NULL;
|
||||
return CCID_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
uint8_t modhex_tab[] =
|
||||
@@ -176,6 +182,22 @@ extern int calculate_oath(uint8_t truncate,
|
||||
size_t key_len,
|
||||
const uint8_t *chal,
|
||||
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
|
||||
static uint8_t session_counter[2] = { 0 };
|
||||
#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) {
|
||||
if (otp_config->cfg_flags & SHORT_TICKET) {
|
||||
otp_config->fixed_size /= 2;
|
||||
uint8_t fixed_size = FIXED_SIZE + UID_SIZE + KEY_SIZE;
|
||||
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) {
|
||||
append_keyboard_buffer((const uint8_t *) "\x28", 1);
|
||||
}
|
||||
@@ -308,8 +331,12 @@ int otp_button_pressed(uint8_t slot) {
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) otp_ctor() {
|
||||
register_app(otp_select);
|
||||
register_app(otp_select, otp_aid);
|
||||
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() {
|
||||
@@ -489,3 +516,110 @@ int otp_process_apdu() {
|
||||
}
|
||||
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
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __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_MINOR (PICO_FIDO_VERSION & 0xff)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
from fido2.client import CtapError
|
||||
from fido2.cose import ES256, ES384, ES512
|
||||
from fido2.cose import ES256, ES384, ES512, EdDSA
|
||||
from utils import ES256K
|
||||
import pytest
|
||||
|
||||
@@ -122,7 +122,7 @@ def test_bad_type_pubKeyCredParams(device):
|
||||
device.doMC(key_params=["wrong"])
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM]
|
||||
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
|
||||
)
|
||||
def test_algorithms(device, info, alg):
|
||||
if ({'alg': alg, 'type': 'public-key'} in info.algorithms):
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
from fido2.client import CtapError
|
||||
from fido2.cose import ES256, ES384, ES512
|
||||
from fido2.cose import ES256, ES384, ES512, EdDSA
|
||||
from utils import verify, ES256K
|
||||
import pytest
|
||||
|
||||
@@ -49,7 +49,7 @@ def test_empty_allowList(device):
|
||||
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM]
|
||||
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
|
||||
)
|
||||
def test_algorithms(device, info, alg):
|
||||
if ({'alg': alg, 'type': 'public-key'} in info.algorithms):
|
||||
|
||||
@@ -23,7 +23,6 @@ import sys
|
||||
import argparse
|
||||
import platform
|
||||
from binascii import hexlify
|
||||
from words import words
|
||||
from threading import Event
|
||||
from typing import Mapping, Any, Optional, Callable
|
||||
import struct
|
||||
@@ -33,7 +32,7 @@ from enum import IntEnum, unique
|
||||
|
||||
try:
|
||||
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.utils import bytes2int, int2bytes
|
||||
from fido2 import cbor
|
||||
@@ -58,14 +57,6 @@ except:
|
||||
from enum import IntEnum
|
||||
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'):
|
||||
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; '
|
||||
'rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
|
||||
@@ -90,6 +81,7 @@ class VendorConfig(Config):
|
||||
class CMD(IntEnum):
|
||||
CONFIG_AUT_ENABLE = 0x03e43f56b34285e2
|
||||
CONFIG_AUT_DISABLE = 0x1831a40f04a25ed9
|
||||
CONFIG_VENDOR_PROTOTYPE = 0x7f
|
||||
|
||||
class RESP(IntEnum):
|
||||
KEY_AGREEMENT = 0x01
|
||||
@@ -99,7 +91,7 @@ class VendorConfig(Config):
|
||||
|
||||
def enable_device_aut(self, ct):
|
||||
self._call(
|
||||
Config.CMD.VENDOR_PROTOTYPE,
|
||||
VendorConfig.CMD.CONFIG_VENDOR_PROTOTYPE,
|
||||
{
|
||||
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_ENABLE,
|
||||
VendorConfig.PARAM.VENDOR_AUT_CT: ct
|
||||
@@ -108,7 +100,7 @@ class VendorConfig(Config):
|
||||
|
||||
def disable_device_aut(self):
|
||||
self._call(
|
||||
Config.CMD.VENDOR_PROTOTYPE,
|
||||
VendorConfig.CMD.CONFIG_VENDOR_PROTOTYPE,
|
||||
{
|
||||
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_DISABLE
|
||||
},
|
||||
@@ -230,7 +222,7 @@ class Vendor:
|
||||
self.__key_enc = 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):
|
||||
if params:
|
||||
@@ -252,6 +244,14 @@ class Vendor:
|
||||
return self.ctap.vendor(cmd, sub_cmd, params, pin_uv_protocol, pin_uv_param)
|
||||
|
||||
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(
|
||||
Vendor.CMD.VENDOR_BACKUP,
|
||||
Vendor.SUBCMD.ENABLE,
|
||||
@@ -270,6 +270,14 @@ class Vendor:
|
||||
print(f'{(c+1):02d} - {words[coef]}')
|
||||
|
||||
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
|
||||
if (d == 0):
|
||||
for c in range(24):
|
||||
@@ -349,6 +357,13 @@ class Vendor:
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
def get_skey(self):
|
||||
@@ -381,6 +396,7 @@ class Vendor:
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
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.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))
|
||||
|
||||
def main(args):
|
||||
print('Pico Fido Tool v1.4')
|
||||
print('Pico Fido Tool v1.6')
|
||||
print('Author: Pol Henarejos')
|
||||
print('Report bugs to https://github.com/polhenarejos/pico-fido/issues')
|
||||
print('')
|
||||
print('')
|
||||
|
||||
dev = next(CtapHidDevice.list_devices(), None)
|
||||
|
||||
vdr = Vendor(Ctap2Vendor(dev))
|
||||
ctap = 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'):
|
||||
secure(vdr, args)
|
||||
|
||||
@@ -51,7 +51,9 @@ def get_secure_key():
|
||||
try:
|
||||
backend = get_backend(False)
|
||||
key = backend.get_password(DOMAIN, USERNAME)[0]
|
||||
except keyring.errors.KeyringError:
|
||||
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:
|
||||
|
||||
44
tools/secure_key/windows.py
Normal file
44
tools/secure_key/windows.py
Normal 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())
|
||||
Reference in New Issue
Block a user