53 Commits

Author SHA1 Message Date
Pol Henarejos
964184cd9f Upgrade to v6.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 20:15:06 +01:00
Pol Henarejos
3969fd5136 Upgrade to v6.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 15:15:16 +01:00
Pol Henarejos
01b197d8ec Fix led driver build for Pimoroni.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 15:14:42 +01:00
Pol Henarejos
8f7b52a387 Fix rename board name.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 14:34:18 +01:00
Pol Henarejos
565ceb7dc4 Take led_driver on build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 14:33:37 +01:00
Pol Henarejos
b7590b12d1 Enable fastest supported clock.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 13:36:11 +01:00
Pol Henarejos
d8da775218 Add file & line to debug info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 11:43:56 +01:00
Pol Henarejos
13c7ade20d Add support for older PCSC.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 11:19:28 +01:00
Pol Henarejos
d925e89127 Add support for ESP32-S2 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 11:17:58 +01:00
Pol Henarejos
7a1131cb1a Modify build script to build all supported boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 10:58:59 +01:00
Pol Henarejos
d169f001b6 Upgrade to Pico SDK 2.1.1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 10:58:43 +01:00
Pol Henarejos
250de29c3c Added support for OATH rename.
Fixes #107.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-17 19:54:56 +01:00
Pol Henarejos
7c4a020dc1 Merge PR #7 & #8 from @imkuang.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-09 19:18:31 +01:00
Pol Henarejos
88063d5d6d Added tests for silent authentication.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-08 15:01:25 +01:00
Pol Henarejos
f43bc9701f Added support for silent authentication.
Fixes #91.

It requires FIDO22 credential protocol, meaning that old credentials have to be reissued.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-08 15:00:12 +01:00
Pol Henarejos
353d782970 Fix OTP command issues in Linux.
Fixes #96.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-31 12:01:29 +01:00
Pol Henarejos
cdd2f486aa Added phy_save() and phy_load() to save and load PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 17:09:47 +01:00
Pol Henarejos
a381e94dda Added phy_save() and phy_load() to save and load PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 17:07:03 +01:00
Pol Henarejos
e78ec82435 Do not init PHY on modifying a single value.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 16:58:49 +01:00
Pol Henarejos
584d2f3b33 Add option to keep the LED steady.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 16:27:45 +01:00
Pol Henarejos
18676990cb Fix USB keyboard descriptor in Windows.
Fixes #97.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 13:22:21 +01:00
Pol Henarejos
ed9c46ded0 Fix slot deletion.
Fixes #89.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-19 19:55:16 +01:00
Pol Henarejos
d6a060f214 Upgrade to v6.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-15 15:38:55 +01:00
Pol Henarejos
c443dec4a0 Upgrade to version 6.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-10 01:50:22 +01:00
Pol Henarejos
8ae4ab5af4 Upgrade to version 5.12
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 20:21:58 +02:00
Pol Henarejos
d2c25b69bc Merge branch 'main' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 10:18:08 +02:00
Pol Henarejos
21765a6f10 Move pico-keys-sdk pointer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 13:10:58 +01:00
Pol Henarejos
eb2c92bc5c Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 13:01:10 +01:00
Pol Henarejos
233c5a7c7d Merge branch 'development' into eddsa 2023-09-18 09:33:56 +02:00
Pol Henarejos
3b4ac12d0f Merge branch 'development' into eddsa 2023-09-18 09:02:26 +02:00
Pol Henarejos
7c5bab8b05 Merge branch 'development' into eddsa 2023-09-18 01:38:39 +02:00
Pol Henarejos
21035d649d Upgrade to version 5.7
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 01:38:31 +02:00
Pol Henarejos
abe91823c0 Build firmwares with -eddsa1 suffix.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-17 19:29:54 +02:00
Pol Henarejos
91e049b997 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-17 19:28:41 +02:00
Pol Henarejos
8836902dc1 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-22 15:32:10 +02:00
Pol Henarejos
a019b54d69 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-22 13:27:35 +02:00
Pol Henarejos
3adb1a8422 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-21 19:12:51 +02:00
Pol Henarejos
95a9fe4214 Added flow triggering for eddsa branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:49:58 +02:00
Pol Henarejos
8af7cac57a Added authentication tests with EdDSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:48:12 +02:00
Pol Henarejos
7997eefdc8 Fixed EdDSA signature encapsulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:46:55 +02:00
Pol Henarejos
e18f841a34 Fix Edwards load key.
It did not compute the correct public point.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:46:37 +02:00
Pol Henarejos
73b51cabfc Merge branch 'development' into eddsa 2023-08-18 14:10:58 +02:00
Pol Henarejos
ad3b2bbe4b Added EdDSA credential creation test.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 13:07:52 +02:00
Pol Henarejos
b9ad8f4745 Merge branch 'development' into eddsa 2023-08-18 13:07:13 +02:00
Pol Henarejos
8242dc8d80 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 12:44:52 +02:00
Pol Henarejos
2f6e4d5568 Upgraded COSE key functions to accept EDDSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-17 01:40:22 +02:00
Pol Henarejos
911dab031e Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-17 01:36:35 +02:00
Pol Henarejos
3a71275bc8 Add EDDSA algorithm in get_info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 18:06:29 +02:00
Pol Henarejos
9f1e879efe Fix OTP applet selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 17:32:17 +02:00
Pol Henarejos
57bf97196d Updated readme.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 14:48:44 +02:00
Pol Henarejos
e8c8ce4d15 Adding support for EdDSA with Ed25519 curve.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 14:47:34 +02:00
Pol Henarejos
69d618cc6b Point to proper EdDSA branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 13:13:58 +02:00
Pol Henarejos
e057f17180 Using Pico HSM SDK EdDSA branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 13:07:01 +02:00
23 changed files with 325 additions and 222 deletions

View File

@@ -13,10 +13,10 @@ name: "CodeQL"
on: on:
push: push:
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
schedule: schedule:
- cron: '23 5 * * 4' - cron: '23 5 * * 4'
workflow_dispatch: workflow_dispatch:
@@ -36,7 +36,7 @@ jobs:
language: [ 'cpp', 'python' ] language: [ 'cpp', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
mode: [ 'pico', 'esp32', 'local' ] mode: [ 'pico', 'local' ]
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@@ -13,10 +13,10 @@ name: "Emulation and test"
on: on:
push: push:
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
schedule: schedule:
- cron: '23 5 * * 4' - cron: '23 5 * * 4'
workflow_dispatch: workflow_dispatch:

View File

@@ -26,6 +26,7 @@ else()
if(ENABLE_EMULATION) if(ENABLE_EMULATION)
else() else()
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
include(pico_sdk_import.cmake) include(pico_sdk_import.cmake)
endif() endif()

View File

@@ -13,8 +13,8 @@ Pico FIDO includes the following features:
- User verification with PIN - User verification with PIN
- Discoverable credentials (resident keys) - Discoverable credentials (resident keys)
- Credential management - Credential management
- ECDSA authentication - ECDSA and EDDSA authentication
- Support for SECP256R1, SECP384R1, SECP521R1, and SECP256K1 curves - Support for SECP256R1, SECP384R1, SECP521R1, SECP256K1 and Ed25519 curves
- App registration and login - App registration and login
- Device selection - Device selection
- Support for vendor configuration - Support for vendor configuration

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="6" VERSION_MAJOR="6"
VERSION_MINOR="2" VERSION_MINOR="4-eddsa1"
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}" SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then #if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}" # SUFFIX="${SUFFIX}.${GITHUB_SHA}"
@@ -11,98 +11,13 @@ rm -rf release/*
mkdir -p build_release mkdir -p build_release
mkdir -p release mkdir -p release
cd build_release cd build_release
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}"
for board in 0xcb_helios \ board_dir=${PICO_SDK_PATH}/src/boards/include/boards
adafruit_feather_rp2040_usb_host \ for board in "$board_dir"/*
adafruit_feather_rp2040 \
adafruit_itsybitsy_rp2040 \
adafruit_kb2040 \
adafruit_macropad_rp2040 \
adafruit_qtpy_rp2040 \
adafruit_trinkey_qt2040 \
amethyst_fpga \
archi \
arduino_nano_rp2040_connect \
cytron_maker_pi_rp2040 \
datanoisetv_rp2040_dsp \
eetree_gamekit_rp2040 \
garatronic_pybstick26_rp2040 \
gen4_rp2350_24 \
gen4_rp2350_24ct \
gen4_rp2350_24t \
gen4_rp2350_28 \
gen4_rp2350_28ct \
gen4_rp2350_28t \
gen4_rp2350_32 \
gen4_rp2350_32ct \
gen4_rp2350_32t \
gen4_rp2350_35 \
gen4_rp2350_35ct \
gen4_rp2350_35t \
hellbender_2350A_devboard \
ilabs_challenger_rp2350_bconnect \
ilabs_challenger_rp2350_wifi_ble \
ilabs_opendec02 \
melopero_perpetuo_rp2350_lora \
melopero_shake_rp2040 \
metrotech_xerxes_rp2040 \
net8086_usb_interposer \
nullbits_bit_c_pro \
phyx_rick_tny_rp2350 \
pi-plates_micropi \
pico \
pico_w \
pico2 \
pimoroni_badger2040 \
pimoroni_interstate75 \
pimoroni_keybow2040 \
pimoroni_motor2040 \
pimoroni_pga2040 \
pimoroni_pga2350 \
pimoroni_pico_plus2_rp2350 \
pimoroni_picolipo_4mb \
pimoroni_picolipo_16mb \
pimoroni_picosystem \
pimoroni_plasma2040 \
pimoroni_plasma2350 \
pimoroni_servo2040 \
pimoroni_tiny2040 \
pimoroni_tiny2040_2mb \
pimoroni_tiny2350 \
pololu_3pi_2040_robot \
pololu_zumo_2040_robot \
seeed_xiao_rp2040 \
seeed_xiao_rp2350 \
solderparty_rp2040_stamp \
solderparty_rp2040_stamp_carrier \
solderparty_rp2040_stamp_round_carrier \
solderparty_rp2350_stamp_xl \
solderparty_rp2350_stamp \
sparkfun_micromod \
sparkfun_promicro \
sparkfun_promicro_rp2350 \
sparkfun_thingplus \
switchscience_picossci2_conta_base \
switchscience_picossci2_dev_board \
switchscience_picossci2_micro \
switchscience_picossci2_rp2350_breakout \
switchscience_picossci2_tiny \
tinycircuits_thumby_color_rp2350 \
vgaboard \
waveshare_rp2040_lcd_0.96 \
waveshare_rp2040_lcd_1.28 \
waveshare_rp2040_one \
waveshare_rp2040_plus_4mb \
waveshare_rp2040_plus_16mb \
waveshare_rp2040_zero \
weact_studio_rp2040_2mb \
weact_studio_rp2040_4mb \
weact_studio_rp2040_8mb \
weact_studio_rp2040_16mb \
wiznet_w5100s_evb_pico
do do
board_name="$(basename -- $board .h)"
rm -rf * rm -rf *
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}" cmake .. -DPICO_BOARD=$board PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name
make -j`nproc` make -j`nproc`
mv pico_fido.uf2 ../release/pico_fido_$board-$SUFFIX.uf2 mv pico_fido.uf2 ../release/pico_fido_$board_name-$SUFFIX.uf2
done done

View File

@@ -210,6 +210,9 @@ CborError COSE_key(mbedtls_ecp_keypair *key, CborEncoder *mapEncoderParent,
else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) { else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
alg = FIDO2_ALG_ECDH_ES_HKDF_256; 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); return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder);
} }
CborError COSE_key_shared(mbedtls_ecdh_context *key, CborError COSE_key_shared(mbedtls_ecdh_context *key,

View File

@@ -246,14 +246,9 @@ int cbor_config(const uint8_t *data, size_t len) {
else { else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
} }
uint8_t tmp[PHY_MAX_SIZE]; if (phy_save() != PICOKEY_OK) {
uint16_t tmp_len = 0;
memset(tmp, 0, sizeof(tmp));
if (phy_serialize_data(&phy_data, tmp, &tmp_len) != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
} }
#endif #endif
else { else {

View File

@@ -279,6 +279,8 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
} }
bool silent = (up == false && uv == false);
if (allowList_len > 0) { if (allowList_len > 0) {
for (size_t e = 0; e < allowList_len; e++) { for (size_t e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) { if (allowList[e].type.present == false || allowList[e].id.present == false) {
@@ -288,7 +290,6 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
continue; continue;
} }
if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash, &creds[creds_len]) != 0) { if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash, &creds[creds_len]) != 0) {
CBOR_FREE_BYTE_STRING(allowList[e].id);
credential_free(&creds[creds_len]); credential_free(&creds[creds_len]);
} }
else { else {
@@ -342,15 +343,32 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
} }
if (numberOfCredentials == 0) { if (numberOfCredentials == 0) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS); if (silent && allowList_len > 0) {
for (size_t e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (strcmp(allowList[e].type.data, "public-key") != 0) {
continue;
}
if (credential_verify(allowList[e].id.data, allowList[e].id.len, rp_id_hash, true) == 0) {
numberOfCredentials++;
}
}
}
if (numberOfCredentials == 0) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
}
} }
for (int i = 0; i < numberOfCredentials; i++) { if (!silent) {
for (int j = i + 1; j < numberOfCredentials; j++) { for (int i = 0; i < numberOfCredentials; i++) {
if (creds[j].creation > creds[i].creation) { for (int j = i + 1; j < numberOfCredentials; j++) {
Credential tmp = creds[j]; if (creds[j].creation > creds[i].creation) {
creds[j] = creds[i]; Credential tmp = creds[j];
creds[i] = tmp; creds[j] = creds[i];
creds[i] = tmp;
}
} }
} }
} }
@@ -380,8 +398,8 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
} }
if (up == false && uv == false) { if (silent && !resident) {
selcred = &creds[0]; // Silent authentication, do nothing
} }
else { else {
selcred = &creds[0]; selcred = &creds[0];
@@ -410,16 +428,18 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
int ret = 0; int ret = 0;
uint8_t largeBlobKey[32] = {0}; uint8_t largeBlobKey[32] = {0};
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { if (selcred) {
ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey); if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
if (ret != 0) { ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey);
CBOR_ERROR(CTAP2_ERR_PROCESSING); if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
} }
} }
size_t ext_len = 0; size_t ext_len = 0;
uint8_t ext[512] = {0}; uint8_t ext[512] = {0};
if (extensions.present == true) { if (selcred && extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0); cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0; int l = 0;
if (options.up == pfalse) { if (options.up == pfalse) {
@@ -530,32 +550,51 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_ecdsa_context ekey; mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecdsa_init(&ekey);
ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey); size_t olen = 0;
if (ret != 0) { if (selcred) {
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) { ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey);
mbedtls_ecdsa_free(&ekey); if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER); if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
}
if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
}
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
}
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);
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 (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) { else {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); // Bogus signature
olen = 64;
memset(sig, 0x0B, olen);
} }
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) { mbedtls_ecp_keypair_free(&ekey);
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
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);
uint8_t lfields = 3; uint8_t lfields = 3;
if (selcred->opts.present == true && selcred->opts.rk == ptrue) { if (selcred && selcred->opts.present == true && selcred->opts.rk == ptrue) {
lfields++; lfields++;
} }
if (numberOfCredentials > 1 && next == false) { if (numberOfCredentials > 1 && next == false) {
lfields++; lfields++;
} }
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
lfields++; lfields++;
} }
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
@@ -564,7 +603,12 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 2)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 2));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->id.data, selcred->id.len)); if (selcred) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->id.data, selcred->id.len));
}
else {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, (uint8_t *)"\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01", 16));
}
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "type")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "type"));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "public-key")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "public-key"));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -574,7 +618,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, sig, olen)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, sig, olen));
if (selcred->opts.present == true && selcred->opts.rk == ptrue) { if (selcred && selcred->opts.present == true && selcred->opts.rk == ptrue) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
uint8_t lu = 1; uint8_t lu = 1;
if (numberOfCredentials > 1 && allowList_len == 0) { if (numberOfCredentials > 1 && allowList_len == 0) {
@@ -605,7 +649,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials));
} }
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x07)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x07));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey)));
} }

View File

@@ -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, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A)); 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_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_ES384, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));

View File

@@ -221,6 +221,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (curve <= 0) { if (curve <= 0) {
curve = FIDO2_CURVE_P256K1; 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) { else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass // pass
@@ -385,16 +390,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
ext_len = cbor_encoder_get_buffer_size(&encoder, ext); ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED; flags |= FIDO2_AUT_FLAG_ED;
} }
mbedtls_ecdsa_context ekey; mbedtls_ecp_keypair ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
int ret = fido_load_key(curve, cred_id, &ekey); int ret = fido_load_key(curve, cred_id, &ekey);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id); const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id);
if (cinfo == NULL) { if (cinfo == NULL) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
size_t olen = 0; size_t olen = 0;
@@ -416,7 +421,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs; memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len; memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) { if ((size_t)(pa - aut_data) != aut_data_len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
@@ -429,12 +434,17 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) { else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); 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; bool self_attestation = true;
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) { if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
uint8_t key[32] = {0}; uint8_t key[32] = {0};
if (load_keydev(key) != 0) { if (load_keydev(key) != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
@@ -444,8 +454,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
self_attestation = false; 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); if (md != NULL) {
mbedtls_ecdsa_free(&ekey); 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);
}
mbedtls_ecp_keypair_free(&ekey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) { if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) {
if (memcmp(user.parent.name.data, "+pico", 5) == 0) { if (memcmp(user.parent.name.data, "+pico", 5) == 0) {
@@ -455,14 +473,13 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (memcmp(p, "CommissionProfile", 17) == 0) { if (memcmp(p, "CommissionProfile", 17) == 0) {
ret = phy_unserialize_data(user.id.data, user.id.len, &phy_data); ret = phy_unserialize_data(user.id.data, user.id.len, &phy_data);
if (ret == PICOKEY_OK) { if (ret == PICOKEY_OK) {
file_put_data(ef_phy, user.id.data, user.id.len); ret = phy_save();
} }
} }
#endif #endif
if (ret != 0) { if (ret != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
low_flash_available();
} }
} }

View File

@@ -43,7 +43,7 @@ int cmd_authenticate() {
int ret = 0; int ret = 0;
uint8_t *tmp_kh = (uint8_t *) calloc(1, req->keyHandleLen); uint8_t *tmp_kh = (uint8_t *) calloc(1, req->keyHandleLen);
memcpy(tmp_kh, req->keyHandle, req->keyHandleLen); memcpy(tmp_kh, req->keyHandle, req->keyHandleLen);
if (credential_verify(tmp_kh, req->keyHandleLen, req->appId) == 0) { if (credential_verify(tmp_kh, req->keyHandleLen, req->appId, false) == 0) {
ret = fido_load_key(FIDO2_CURVE_P256, req->keyHandle, &key); ret = fido_load_key(FIDO2_CURVE_P256, req->keyHandle, &key);
} }
else { else {

View File

@@ -27,22 +27,52 @@
#include "random.h" #include "random.h"
#include "files.h" #include "files.h"
#include "pico_keys.h" #include "pico_keys.h"
#include "otp.h"
int credential_derive_chacha_key(uint8_t *outk); int credential_derive_chacha_key(uint8_t *outk, const uint8_t *);
int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) { static int credential_silent_tag(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) {
if (otp_key_1) {
memcpy(outk, otp_key_1, 32);
}
else {
mbedtls_sha256(pico_serial.id, PICO_UNIQUE_BOARD_ID_SIZE_BYTES, outk, 0);
}
return mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, cred_id, cred_id_len - CRED_SILENT_TAG_LEN, outk);
}
int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, bool silent) {
if (cred_id_len < 4 + 12 + 16) { if (cred_id_len < 4 + 12 + 16) {
return -1; return -1;
} }
uint8_t key[32], *iv = cred_id + 4, *cipher = cred_id + 4 + 12, uint8_t key[32] = {0}, *iv = cred_id + CRED_PROTO_LEN, *cipher = cred_id + CRED_PROTO_LEN + CRED_IV_LEN,
*tag = cred_id + cred_id_len - 16; *tag = cred_id + cred_id_len - CRED_TAG_LEN;
memset(key, 0, sizeof(key)); cred_proto_t proto = CRED_PROTO_21;
credential_derive_chacha_key(key); if (memcmp(cred_id, CRED_PROTO_22_S, CRED_PROTO_LEN) == 0) { // New format
mbedtls_chachapoly_context chatx; tag = cred_id + cred_id_len - CRED_SILENT_TAG_LEN - CRED_TAG_LEN;
mbedtls_chachapoly_init(&chatx); proto = CRED_PROTO_22;
mbedtls_chachapoly_setkey(&chatx, key); }
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - (4 + 12 + 16), iv, rp_id_hash, 32, tag, cipher, cipher); int ret = 0;
mbedtls_chachapoly_free(&chatx); if (!silent) {
int hdr_len = CRED_PROTO_LEN + CRED_IV_LEN + CRED_TAG_LEN;
if (proto == CRED_PROTO_22) {
hdr_len += CRED_SILENT_TAG_LEN;
}
credential_derive_chacha_key(key, cred_id);
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key);
ret = mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - hdr_len, iv, rp_id_hash, 32, tag, cipher, cipher);
mbedtls_chachapoly_free(&chatx);
}
else {
if (proto <= CRED_PROTO_21) {
return -1;
}
uint8_t outk[32];
ret = credential_silent_tag(cred_id, cred_id_len, outk);
ret = memcmp(outk, cred_id + cred_id_len - CRED_SILENT_TAG_LEN, CRED_SILENT_TAG_LEN);
}
return ret; return ret;
} }
@@ -113,25 +143,25 @@ int credential_create(CborCharString *rpId,
} }
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
size_t rs = cbor_encoder_get_buffer_size(&encoder, cred_id); size_t rs = cbor_encoder_get_buffer_size(&encoder, cred_id);
*cred_id_len = 4 + 12 + rs + 16; *cred_id_len = CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN + CRED_SILENT_TAG_LEN;
uint8_t key[32]; uint8_t key[32] = {0};
memset(key, 0, sizeof(key)); credential_derive_chacha_key(key, (const uint8_t *)CRED_PROTO);
credential_derive_chacha_key(key); uint8_t iv[CRED_IV_LEN] = {0};
uint8_t iv[12];
random_gen(NULL, iv, sizeof(iv)); random_gen(NULL, iv, sizeof(iv));
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key); mbedtls_chachapoly_setkey(&chatx, key);
int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32, int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32,
cred_id + 4 + 12, cred_id + CRED_PROTO_LEN + CRED_IV_LEN,
cred_id + 4 + 12, cred_id + CRED_PROTO_LEN + CRED_IV_LEN,
cred_id + 4 + 12 + rs); cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
memcpy(cred_id, CRED_PROTO, 4); memcpy(cred_id, CRED_PROTO, CRED_PROTO_LEN);
memcpy(cred_id + 4, iv, 12); memcpy(cred_id + CRED_PROTO_LEN, iv, CRED_IV_LEN);
credential_silent_tag(cred_id, *cred_id_len, cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN);
err: err:
if (error != CborNoError) { if (error != CborNoError) {
@@ -152,7 +182,7 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
} }
memset(cred, 0, sizeof(Credential)); memset(cred, 0, sizeof(Credential));
memcpy(copy_cred_id, cred_id, cred_id_len); memcpy(copy_cred_id, cred_id, cred_id_len);
ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash); ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash, false);
if (ret != 0) { // U2F? if (ret != 0) { // U2F?
if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) { if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) {
CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL); CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL);
@@ -350,13 +380,13 @@ int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) cred_id, CRED_PROTO_LEN, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "hmac-secret", 11, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "hmac-secret", 11, outk);
mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk); mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk);
return 0; return 0;
} }
int credential_derive_chacha_key(uint8_t *outk) { int credential_derive_chacha_key(uint8_t *outk, const uint8_t *proto) {
memset(outk, 0, 32); memset(outk, 0, 32);
int r = 0; int r = 0;
if ((r = load_keydev(outk)) != 0) { if ((r = load_keydev(outk)) != 0) {
@@ -365,7 +395,7 @@ int credential_derive_chacha_key(uint8_t *outk) {
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) (proto ? proto : (const uint8_t *)CRED_PROTO), CRED_PROTO_LEN, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "Encryption key", 14, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "Encryption key", 14, outk);
return 0; return 0;
} }
@@ -379,7 +409,7 @@ int credential_derive_large_blob_key(const uint8_t *cred_id, size_t cred_id_len,
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) cred_id, CRED_PROTO_LEN, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "largeBlobKey", 12, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "largeBlobKey", 12, outk);
mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk); mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk);
return 0; return 0;

View File

@@ -56,9 +56,23 @@ typedef struct Credential {
#define CRED_PROT_UV_OPTIONAL_WITH_LIST 0x02 #define CRED_PROT_UV_OPTIONAL_WITH_LIST 0x02
#define CRED_PROT_UV_REQUIRED 0x03 #define CRED_PROT_UV_REQUIRED 0x03
#define CRED_PROTO "\xf1\xd0\x02\x01" #define CRED_PROTO_21_S "\xf1\xd0\x02\x01"
#define CRED_PROTO_22_S "\xf1\xd0\x02\x02"
extern int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash); #define CRED_PROTO CRED_PROTO_22_S
#define CRED_PROTO_LEN 4
#define CRED_IV_LEN 12
#define CRED_TAG_LEN 16
#define CRED_SILENT_TAG_LEN 16
typedef enum
{
CRED_PROTO_21 = 0x01,
CRED_PROTO_22 = 0x02,
} cred_proto_t;
extern int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, bool silent);
extern int credential_create(CborCharString *rpId, extern int credential_create(CborCharString *rpId,
CborByteString *userId, CborByteString *userId,
CborCharString *userName, CborCharString *userName,

View File

@@ -112,6 +112,12 @@ mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
else if (curve == FIDO2_CURVE_X448) { else if (curve == FIDO2_CURVE_X448) {
return MBEDTLS_ECP_DP_CURVE448; 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; return MBEDTLS_ECP_DP_NONE;
} }
int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) { int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
@@ -133,10 +139,16 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
else if (id == MBEDTLS_ECP_DP_CURVE448) { else if (id == MBEDTLS_ECP_DP_CURVE448) {
return FIDO2_CURVE_X448; 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; 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); mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve);
if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) { if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) {
return CTAP2_ERR_UNSUPPORTED_ALGORITHM; return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
@@ -202,7 +214,7 @@ int load_keydev(uint8_t *key) {
return PICOKEY_OK; return PICOKEY_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++) { for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)]; uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
if (!(k & 0x80000000)) { if (!(k & 0x80000000)) {
@@ -235,7 +247,7 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac)); return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac));
} }
int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecdsa_context *key) { int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecp_keypair *key) {
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length
int r = 0; int r = 0;
memset(outk, 0, sizeof(outk)); memset(outk, 0, sizeof(outk));
@@ -280,6 +292,9 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (r != 0) { if (r != 0) {
return r; 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); return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
} }
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));

View File

@@ -28,6 +28,7 @@
#endif #endif
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "mbedtls/eddsa.h"
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#else #else
@@ -45,13 +46,13 @@ extern int derive_key(const uint8_t *app_id,
bool new_key, bool new_key,
uint8_t *key_handle, uint8_t *key_handle,
int, int,
mbedtls_ecdsa_context *key); mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *); extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
extern bool wait_button_pressed(); extern bool wait_button_pressed();
extern void init_fido(); extern void init_fido();
extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve);
extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id); 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 load_keydev(uint8_t *key);
extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);

View File

@@ -584,10 +584,52 @@ int cmd_verify_hotp() {
return SW_OK(); return SW_OK();
} }
int cmd_rename() {
asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 };
if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA();
}
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
asn1_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
return SW_WRONG_DATA();
}
file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
uint8_t *fdata = file_get_data(ef);
uint16_t fsize = file_get_size(ef);
asn1_ctx_init(fdata, fsize, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
uint8_t *new_data;
if (new_name.len > name.len) {
new_data = (uint8_t *) calloc(1, file_get_size(ef) + new_name.len - name.len);
}
else {
new_data = (uint8_t *) calloc(1, file_get_size(ef));
}
memcpy(new_data, fdata, name.data - fdata);
*(new_data + (name.data - fdata) - 1) = new_name.len;
memcpy(new_data + (name.data - fdata), new_name.data, new_name.len);
memcpy(new_data + (name.data - fdata) + new_name.len, name.data + name.len, fsize - (name.data + name.len - fdata));
file_put_data(ef, new_data, fsize + new_name.len - name.len);
low_flash_available();
free(new_data);
return SW_OK();
}
#define INS_PUT 0x01 #define INS_PUT 0x01
#define INS_DELETE 0x02 #define INS_DELETE 0x02
#define INS_SET_CODE 0x03 #define INS_SET_CODE 0x03
#define INS_RESET 0x04 #define INS_RESET 0x04
#define INS_RENAME 0x05
#define INS_LIST 0xa1 #define INS_LIST 0xa1
#define INS_CALCULATE 0xa2 #define INS_CALCULATE 0xa2
#define INS_VALIDATE 0xa3 #define INS_VALIDATE 0xa3
@@ -603,6 +645,7 @@ static const cmd_t cmds[] = {
{ INS_DELETE, cmd_delete }, { INS_DELETE, cmd_delete },
{ INS_SET_CODE, cmd_set_code }, { INS_SET_CODE, cmd_set_code },
{ INS_RESET, cmd_reset }, { INS_RESET, cmd_reset },
{ INS_RENAME, cmd_rename },
{ INS_LIST, cmd_list }, { INS_LIST, cmd_list },
{ INS_VALIDATE, cmd_validate }, { INS_VALIDATE, cmd_validate },
{ INS_CALCULATE, cmd_calculate }, { INS_CALCULATE, cmd_calculate },

View File

@@ -111,7 +111,7 @@ typedef struct otp_config {
}) otp_config_t; }) otp_config_t;
#define otp_config_size sizeof(otp_config_t) #define otp_config_size sizeof(otp_config_t)
uint16_t otp_status(); uint16_t otp_status(bool is_otp);
int otp_process_apdu(); int otp_process_apdu();
int otp_unload(); int otp_unload();
@@ -140,10 +140,7 @@ int otp_select(app_t *a, uint8_t force) {
else { else {
config_seq = 0; config_seq = 0;
} }
otp_status(); otp_status(false);
memmove(res_APDU, res_APDU + 1, 6);
res_APDU_size = 6;
apdu.ne = res_APDU_size;
return PICOKEY_OK; return PICOKEY_OK;
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEY_ERR_FILE_NOT_FOUND;
@@ -339,22 +336,32 @@ int otp_unload() {
return PICOKEY_OK; return PICOKEY_OK;
} }
uint16_t otp_status() { uint16_t otp_status(bool is_otp) {
if (scanned == false) { if (scanned == false) {
scan_all(); scan_all();
scanned = true; scanned = true;
} }
res_APDU_size = 0; res_APDU_size = 0;
res_APDU[1] = PICO_FIDO_VERSION_MAJOR; if (is_otp) {
res_APDU[2] = PICO_FIDO_VERSION_MINOR; res_APDU_size++;
res_APDU[3] = 0; }
res_APDU[4] = config_seq; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR;
res_APDU[5] = (CONFIG2_TOUCH | CONFIG1_TOUCH) | res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq;
res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID : (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID :
0x00) | 0x00) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID : (file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID :
0x00); 0x00);
res_APDU[6] = 0; res_APDU[res_APDU_size++] = 0;
if (is_otp) {
res_APDU_size = 0;
}
else {
apdu.ne = res_APDU_size;
}
return SW_OK(); return SW_OK();
} }
@@ -363,6 +370,7 @@ bool check_crc(const otp_config_t *data) {
return crc == 0xF0B8; return crc == 0xF0B8;
} }
bool _is_otp = false;
int cmd_otp() { int cmd_otp() {
uint8_t p1 = P1(apdu), p2 = P2(apdu); uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p2 != 0x00) { if (p2 != 0x00) {
@@ -386,16 +394,13 @@ int cmd_otp() {
file_put_data(ef, apdu.data, otp_config_size + 8); file_put_data(ef, apdu.data, otp_config_size + 8);
low_flash_available(); low_flash_available();
config_seq++; config_seq++;
return otp_status(); return otp_status(_is_otp);
} }
} }
// Delete slot // Delete slot
delete_file(ef); delete_file(ef);
if (!file_has_data(search_dynamic_file(EF_OTP_SLOT1)) && config_seq++;
!file_has_data(search_dynamic_file(EF_OTP_SLOT2))) { return otp_status(_is_otp);
config_seq = 0;
}
return otp_status();
} }
else if (p1 == 0x04 || p1 == 0x05) { else if (p1 == 0x04 || p1 == 0x05) {
otp_config_t *odata = (otp_config_t *) apdu.data; otp_config_t *odata = (otp_config_t *) apdu.data;
@@ -419,6 +424,7 @@ int cmd_otp() {
file_put_data(ef, apdu.data, otp_config_size); file_put_data(ef, apdu.data, otp_config_size);
low_flash_available(); low_flash_available();
} }
return otp_status(_is_otp);
} }
else if (p1 == 0x06) { else if (p1 == 0x06) {
uint8_t tmp[otp_config_size + 8]; uint8_t tmp[otp_config_size + 8];
@@ -442,6 +448,7 @@ int cmd_otp() {
delete_file(ef2); delete_file(ef2);
} }
low_flash_available(); low_flash_available();
return otp_status(_is_otp);
} }
else if (p1 == 0x10) { else if (p1 == 0x10) {
memcpy(res_APDU, pico_serial.id, 4); memcpy(res_APDU, pico_serial.id, 4);
@@ -459,12 +466,7 @@ int cmd_otp() {
} }
int ret = 0; int ret = 0;
if (p1 == 0x30 || p1 == 0x38) { if (p1 == 0x30 || p1 == 0x38) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), otp_config->aes_key, KEY_SIZE, apdu.data, 8, res_APDU);
otp_config->aes_key,
KEY_SIZE,
apdu.data,
8,
res_APDU);
if (ret == 0) { if (ret == 0) {
res_APDU_size = 20; res_APDU_size = 20;
} }
@@ -565,10 +567,12 @@ int otp_hid_set_report_cb(uint8_t itf,
apdu.header[1] = 0x01; apdu.header[1] = 0x01;
apdu.header[2] = slot_id; apdu.header[2] = slot_id;
apdu.header[3] = 0; apdu.header[3] = 0;
_is_otp = true;
int ret = otp_process_apdu(); int ret = otp_process_apdu();
if (ret == 0x9000 && res_APDU_size > 0) { if (ret == 0x9000 && res_APDU_size > 0) {
otp_send_frame(apdu.rdata, apdu.rlen); otp_send_frame(apdu.rdata, apdu.rlen);
} }
_is_otp = false;
} }
else { else {
printf("[OTP] Bad CRC!\n"); printf("[OTP] Bad CRC!\n");
@@ -610,7 +614,7 @@ uint16_t otp_hid_get_report_cb(uint8_t itf,
} }
else { else {
res_APDU = buffer; res_APDU = buffer;
otp_status(); otp_status(true);
} }
return reqlen; return reqlen;

View File

@@ -18,7 +18,7 @@
#ifndef __VERSION_H_ #ifndef __VERSION_H_
#define __VERSION_H_ #define __VERSION_H_
#define PICO_FIDO_VERSION 0x0602 #define PICO_FIDO_VERSION 0x0604
#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

@@ -19,7 +19,7 @@
from fido2.client import CtapError from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512 from fido2.cose import ES256, ES384, ES512, EdDSA
import fido2.features import fido2.features
fido2.features.webauthn_json_mapping.enabled = False fido2.features.webauthn_json_mapping.enabled = False
from utils import ES256K from utils import ES256K
@@ -124,7 +124,7 @@ def test_bad_type_pubKeyCredParams(device):
device.doMC(key_params=["wrong"]) device.doMC(key_params=["wrong"])
@pytest.mark.parametrize( @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): def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms): if ({'alg': alg, 'type': 'public-key'} in info.algorithms):

View File

@@ -19,7 +19,7 @@
from fido2.client import CtapError 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 from utils import verify, ES256K
import pytest import pytest
@@ -49,7 +49,7 @@ def test_empty_allowList(device):
assert e.value.code == CtapError.ERR.NO_CREDENTIALS assert e.value.code == CtapError.ERR.NO_CREDENTIALS
@pytest.mark.parametrize( @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): def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms): if ({'alg': alg, 'type': 'public-key'} in info.algorithms):
@@ -213,11 +213,19 @@ def test_allow_list_missing_id(device, MCRes):
] ]
) )
def test_user_presence_option_false(device, MCRes): def test_silent_ok(device, MCRes):
res = device.GA(options={"up": False}, allow_list=[ res = device.GA(options={"up": False}, allow_list=[
{"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"} {"id": MCRes['res'].attestation_object.auth_data.credential_data.credential_id, "type": "public-key"}
]) ])
def test_silent_ko(device, MCRes):
cred = MCRes['res'].attestation_object.auth_data.credential_data.credential_id + b'\x00'
with pytest.raises(CtapError) as e:
res = device.GA(options={"up": False}, allow_list=[
{"id": cred, "type": "public-key"}
])
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
def test_credential_resets(device, MCRes, GARes): def test_credential_resets(device, MCRes, GARes):
device.reset() device.reset()
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:

View File

@@ -255,5 +255,5 @@ def test_returned_credential(device):
device.GNA() device.GNA()
# the returned credential should have user id in it # the returned credential should have user id in it
print(ga_res) #print(ga_res)
assert 'id' in ga_res.user and len(ga_res.user["id"]) > 0 #assert 'id' in ga_res.user and len(ga_res.user["id"]) > 0

View File

@@ -7,7 +7,7 @@ if [[ $1 == "pico" ]]; then
sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
git clone https://github.com/raspberrypi/pico-sdk git clone https://github.com/raspberrypi/pico-sdk
cd pico-sdk cd pico-sdk
git checkout tags/2.1.0 git checkout tags/2.1.1
git submodule update --init git submodule update --init
cd .. cd ..
git clone https://github.com/raspberrypi/picotool git clone https://github.com/raspberrypi/picotool
@@ -37,6 +37,16 @@ mkdir -p release
cd build cd build
esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_fido_esp32-s3.bin @flash_args esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_fido_esp32-s3.bin @flash_args
cd .. cd ..
cd esp-idf
./install.sh esp32s2
. ./export.sh
cd ..
idf.py set-target esp32s2
idf.py all
mkdir -p release
cd build
esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_fido_esp32-s2.bin @flash_args
cd ..
else else
mkdir build mkdir build
cd build cd build