95 Commits
v6.2 ... v6.6

Author SHA1 Message Date
Pol Henarejos
cfe1321d62 Upgrade to v6.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-10 18:37:48 +02:00
Pol Henarejos
2cbea57c86 Update build script to automatize EdDSA builds.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-10 18:37:09 +02:00
Pol Henarejos
b6bf2e6c66 Do not update CFG_FLAGS if slot is ChalResp.
Fixes #142

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-10 16:23:20 +02:00
Pol Henarejos
3212f95915 Fixes update OTP when LT_CHAL is enabled.
Fixes #141.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-08 18:59:50 +02:00
Pol Henarejos
21b12a7bff Define MCU for emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-08 18:58:49 +02:00
Pol Henarejos
c8dbc213a0 Fix EPNUM counting for ESP32. It fixes the problem of not sending KB.
Fixes #130 #138.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-06 18:32:33 +02:00
Pol Henarejos
0a2ee6523f Build all boards with secure boot pkey.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-31 00:53:44 +02:00
Pol Henarejos
c3ea413592 Do not return extensions if they are not requested OR are false.
Fixes #136

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-30 19:32:25 +02:00
Pol Henarejos
64f371e6e5 Despite it is described in the spec 2.1, do not return epAtt if is false, return only when it's true. It fixes a bug with Firefox and Linux that blocked the possibility to make credentials.
Fixes #129.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-30 18:13:58 +02:00
Pol Henarejos
fdd4afb993 CTAP_RESP should be 0ed before sending.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-30 18:12:18 +02:00
Pol Henarejos
fef46dc1c5 OATH Rename requires security validation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-23 23:55:50 +01:00
Pol Henarejos
23a45ac297 Rename returns error if new credential name is equal to previous.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-23 23:51:21 +01:00
Pol Henarejos
b152ff15a8 Fix challenge length calculation for LT64.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-23 23:27:52 +01:00
Pol Henarejos
751fcf0538 Fix HMAC-SHA1 calculation.
Fixes #127.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-23 23:13:21 +01:00
Pol Henarejos
4e4c28a479 Fix CONFIG_TOUCH status report.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-23 22:44:35 +01:00
Pol Henarejos
23b60beb2e When OTP interface is disabled, it also disables KEYBOARD interface to avoid incompatibilities with smart phones.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-22 23:26:19 +01:00
Pol Henarejos
37d7d7faeb OTP can flow through FIDO interface as a report type 3.
Fixes #123.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 19:05:06 +01:00
Pol Henarejos
49c0179ccf Fix swap files.
When a dynamic file is deleted, all scoped references to other dynamic files are invalidated.

Fixes #124

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 13:33:35 +01:00
Pol Henarejos
eacb8a040c Increase config_seq on swap and update.
Fixes #124.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 11:07:02 +01:00
Pol Henarejos
cb99b8f401 Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 01:28:07 +01:00
Pol Henarejos
94f8d5f65f Add support for Require Touch in ChalResp OTP slots.
Fixes #123 #104

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 01:22:14 +01:00
Pol Henarejos
38d332f450 Restore led mode when finishing button press.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 01:19:24 +01:00
Pol Henarejos
c67f5e3a1f Fix Pico Commissioner when new fields are added. It breaks backward compatibility but ensures forward.
Fixes #118.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-17 11:39:27 +01:00
Pol Henarejos
bfb8a4cb20 Only send secp256k1 if explicitly enabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-11 19:28:22 +01:00
Pol Henarejos
0f5a24c9b6 Fix encoding get info with variable curves.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-11 19:19:28 +01:00
Pol Henarejos
dd207bd031 Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-11 19:11:49 +01:00
Pol Henarejos
6069cf949b ES256K1 is disabled by default for compatibility. It can be enabled via Pico Commissioner.
Fixes #109.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-11 19:05:28 +01:00
Pol Henarejos
297c34914b Do not report EDDSA on get info if not supported.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-11 15:19:49 +01:00
Pol Henarejos
529a12e7a3 Only pin to core in ESP32-S3 since it is multicore.
Fixes #100

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-07 19:37:06 +01:00
Pol Henarejos
bdbdd92be8 Enable alwaysUv if pin is set and alwaysUv is a device options or there's current Uv in memory. It will force the prompt of a PIN.
Fixes #113.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-24 12:02:03 +01:00
Pol Henarejos
3807e23914 Fix silent authentication with resident keys.
It requires a new silent format, so silent credentials must be reissued.

Related with #113.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-23 22:03:06 +01:00
Pol Henarejos
ce7d3ea72f Silent credential shall be mixed with RP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-23 20:22:47 +01:00
Pol Henarejos
eb857df3e1 Fix build name.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-23 00:56:27 +01:00
Pol Henarejos
2842944d90 Fix commissioned values for LED.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-23 00:49:56 +01:00
Pol Henarejos
7be92f5331 Fix autobuild.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 19:57:08 +01:00
Pol Henarejos
403b26b60a Build EDDSA tests by default.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 19:07:10 +01:00
Pol Henarejos
b91ece8ec3 Add EDDSA support as a conditional build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 19:00:44 +01:00
Pol Henarejos
d54bc1b0f3 Fix ESP32 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 18:59:44 +01:00
Pol Henarejos
e2dbbe2cc3 Merge branch 'eddsa' into development 2025-02-21 18:11:43 +01:00
Pol Henarejos
8aa9d1c5a3 Fix cyw43 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 17:28:39 +01:00
Pol Henarejos
2d2814cefc Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 17:08:37 +01:00
Pol Henarejos
89a9d013f0 Build cyw43 driver with RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 17:02:26 +01:00
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
28 changed files with 700 additions and 406 deletions

View File

@@ -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'
workflow_dispatch:
@@ -36,7 +36,7 @@ jobs:
language: [ 'cpp', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
mode: [ 'pico', 'esp32', 'local' ]
mode: [ 'pico', 'local' ]
steps:
- name: Checkout repository

View File

@@ -24,7 +24,7 @@ jobs:
PICO_SDK_PATH: ../pico-sdk
run: |
./workflows/autobuild.sh pico
./build_pico_fido.sh
./build_pico_fido.sh --no-eddsa
./workflows/autobuild.sh esp32
- name: Update nightly release
uses: pyTooling/Actions/releaser@main

View File

@@ -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'
workflow_dispatch:

View File

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

View File

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

View File

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

View File

@@ -117,7 +117,7 @@ void cbor_thread(void) {
}
apdu.sw = cbor_parse(cbor_cmd, cbor_data, cbor_len);
if (apdu.sw == 0) {
DEBUG_DATA(res_APDU + 1, res_APDU_size);
DEBUG_DATA(res_APDU, res_APDU_size);
}
else {
if (apdu.sw >= CTAP1_ERR_INVALID_CHANNEL) {
@@ -210,6 +210,11 @@ 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;
}
#ifdef MBEDTLS_EDDSA_C
else if (key->grp.id == MBEDTLS_ECP_DP_ED25519) {
alg = FIDO2_ALG_EDDSA;
}
#endif
return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder);
}
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 {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
uint8_t tmp[PHY_MAX_SIZE];
uint16_t tmp_len = 0;
memset(tmp, 0, sizeof(tmp));
if (phy_serialize_data(&phy_data, tmp, &tmp_len) != PICOKEY_OK) {
if (phy_save() != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
}
#endif
else {

View File

@@ -243,11 +243,11 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key);
mbedtls_ecp_keypair key;
mbedtls_ecp_keypair_init(&key);
if (fido_load_key((int)cred.curve, cred.id.data, &key) != 0) {
credential_free(&cred);
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
@@ -335,7 +335,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, false));
}
credential_free(&cred);
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
}
else if (subcommand == 0x06) {
if (credentialId.id.present == false) {

View File

@@ -93,7 +93,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
Credential creds[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
size_t allowList_len = 0, creds_len = 0;
uint8_t *aut_data = NULL;
bool asserted = false, up = true, uv = false;
bool asserted = false, up = false, uv = false;
int64_t kty = 2, alg = 0, crv = 0;
CborByteString kax = { 0 }, kay = { 0 }, salt_enc = { 0 }, salt_auth = { 0 };
const bool *credBlob = NULL;
@@ -235,6 +235,12 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (options.uv == ptrue) { //4.3
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
}
if (options.uv == NULL || pinUvAuthParam.present == true) {
uv = false;
}
else {
uv = *options.uv;
}
//if (options.up != NULL) { //4.5
// CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
//}
@@ -243,12 +249,12 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
//else if (options.up == NULL) //5.7
//rup = ptrue;
if (options.uv != NULL) {
uv = *options.uv;
}
if (options.up != NULL) {
up = *options.up;
}
else {
up = true;
}
}
if (pinUvAuthParam.present == true) { //6.1
@@ -279,6 +285,8 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
}
bool silent = (up == false && uv == false);
if (allowList_len > 0) {
for (size_t e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) {
@@ -288,11 +296,27 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
continue;
}
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]);
}
else {
creds_len++;
silent = false; // If we are able to load a credential, we are not silent
// Even we provide allowList, we need to check if the credential is resident
if (!resident) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue;
}
if (memcmp(file_get_data(ef) + 32, allowList[e].id.data, allowList[e].id.len) == 0) {
resident = true;
break;
}
}
if (resident) {
break;
}
}
}
}
}
@@ -308,6 +332,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
else {
creds_len++;
silent = false; // If we are able to load a credential, we are not silent
}
}
resident = true;
@@ -342,15 +367,32 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
}
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++) {
for (int j = i + 1; j < numberOfCredentials; j++) {
if (creds[j].creation > creds[i].creation) {
Credential tmp = creds[j];
creds[j] = creds[i];
creds[i] = tmp;
if (!silent) {
for (int i = 0; i < numberOfCredentials; i++) {
for (int j = i + 1; j < numberOfCredentials; j++) {
if (creds[j].creation > creds[i].creation) {
Credential tmp = creds[j];
creds[j] = creds[i];
creds[i] = tmp;
}
}
}
}
@@ -380,8 +422,8 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
}
if (up == false && uv == false) {
selcred = &creds[0];
if (silent && !resident) {
// Silent authentication, do nothing
}
else {
selcred = &creds[0];
@@ -410,106 +452,110 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
int ret = 0;
uint8_t largeBlobKey[32] = {0};
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
if (selcred) {
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
}
}
size_t ext_len = 0;
uint8_t ext[512] = {0};
if (extensions.present == true) {
if (selcred && extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0;
if (options.up == pfalse) {
extensions.hmac_secret = NULL;
}
if (extensions.hmac_secret != NULL) {
if (extensions.hmac_secret == ptrue) {
l++;
}
if (credBlob == ptrue) {
l++;
}
if (extensions.thirdPartyPayment != NULL) {
if (extensions.thirdPartyPayment == ptrue) {
l++;
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (credBlob == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
if (selcred->extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, selcred->extensions.credBlob.data,
selcred->extensions.credBlob.len));
if (l > 0) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (credBlob == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
if (selcred->extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, selcred->extensions.credBlob.data,
selcred->extensions.credBlob.len));
}
else {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, NULL, 0));
}
}
else {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, NULL, 0));
}
}
if (extensions.hmac_secret != NULL) {
if (extensions.hmac_secret == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret"));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret"));
uint8_t sharedSecret[64] = {0};
mbedtls_ecp_point Qp;
mbedtls_ecp_point_init(&Qp);
mbedtls_mpi_lset(&Qp.Z, 1);
if (mbedtls_mpi_read_binary(&Qp.X, kax.data, kax.len) != 0) {
uint8_t sharedSecret[64] = {0};
mbedtls_ecp_point Qp;
mbedtls_ecp_point_init(&Qp);
mbedtls_mpi_lset(&Qp.Z, 1);
if (mbedtls_mpi_read_binary(&Qp.X, kax.data, kax.len) != 0) {
mbedtls_ecp_point_free(&Qp);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (mbedtls_mpi_read_binary(&Qp.Y, kay.data, kay.len) != 0) {
mbedtls_ecp_point_free(&Qp);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
ret = ecdh((uint8_t)hmacSecretPinUvAuthProtocol, &Qp, sharedSecret);
mbedtls_ecp_point_free(&Qp);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (verify((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, (uint16_t)salt_enc.len, salt_auth.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_EXTENSION_FIRST);
}
uint8_t salt_dec[64] = {0}, poff = ((uint8_t)hmacSecretPinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, (uint16_t)salt_enc.len, salt_dec);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t cred_random[64] = {0}, *crd = NULL;
ret = credential_derive_hmac_key(selcred->id.data, selcred->id.len, cred_random);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (flags & FIDO2_AUT_FLAG_UV) {
crd = cred_random + 32;
}
else {
crd = cred_random;
}
uint8_t out1[64] = {0}, hmac_res[80] = {0};
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec, 32, out1);
if ((uint8_t)salt_enc.len == 64 + poff) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec + 32, 32, out1 + 32);
}
encrypt((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, out1, (uint16_t)(salt_enc.len - poff), hmac_res);
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, hmac_res, salt_enc.len));
}
if (mbedtls_mpi_read_binary(&Qp.Y, kay.data, kay.len) != 0) {
mbedtls_ecp_point_free(&Qp);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (extensions.thirdPartyPayment == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "thirdPartyPayment"));
if (selcred->extensions.thirdPartyPayment == ptrue) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
}
else {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, false));
}
}
ret = ecdh((uint8_t)hmacSecretPinUvAuthProtocol, &Qp, sharedSecret);
mbedtls_ecp_point_free(&Qp);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (verify((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, (uint16_t)salt_enc.len, salt_auth.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_EXTENSION_FIRST);
}
uint8_t salt_dec[64] = {0}, poff = ((uint8_t)hmacSecretPinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, (uint16_t)salt_enc.len, salt_dec);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t cred_random[64] = {0}, *crd = NULL;
ret = credential_derive_hmac_key(selcred->id.data, selcred->id.len, cred_random);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (flags & FIDO2_AUT_FLAG_UV) {
crd = cred_random + 32;
}
else {
crd = cred_random;
}
uint8_t out1[64] = {0}, hmac_res[80] = {0};
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec, 32, out1);
if ((uint8_t)salt_enc.len == 64 + poff) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec + 32, 32, out1 + 32);
}
encrypt((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, out1, (uint16_t)(salt_enc.len - poff), hmac_res);
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, hmac_res, salt_enc.len));
}
if (extensions.thirdPartyPayment != NULL) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "thirdPartyPayment"));
if (selcred->extensions.thirdPartyPayment == ptrue) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
}
else {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, false));
}
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED;
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED;
}
}
uint32_t ctr = get_sign_counter();
@@ -528,34 +574,56 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[64] = {0}, sig[MBEDTLS_ECDSA_MAX_LEN] = {0};
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey);
ret = fido_load_key((int)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);
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);
}
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
mbedtls_ecp_keypair ekey;
mbedtls_ecp_keypair_init(&ekey);
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 (selcred) {
ret = fido_load_key((int)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_ecp_keypair_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);
}
#ifdef MBEDTLS_EDDSA_C
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
#endif
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);
}
#ifdef MBEDTLS_EDDSA_C
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);
}
#endif
}
else {
// Bogus signature
olen = 64;
memset(sig, 0x0B, olen);
}
mbedtls_ecp_keypair_free(&ekey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
uint8_t lfields = 3;
if (selcred->opts.present == true && selcred->opts.rk == ptrue) {
if (selcred && selcred->opts.present == true && selcred->opts.rk == ptrue) {
lfields++;
}
if (numberOfCredentials > 1 && next == false) {
if (numberOfCredentials > 1 && next == false && (!resident || allowList_len <= 1)) {
lfields++;
}
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
lfields++;
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
@@ -564,7 +632,12 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 2));
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, "public-key"));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -574,7 +647,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_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));
uint8_t lu = 1;
if (numberOfCredentials > 1 && allowList_len == 0) {
@@ -601,11 +674,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
}
if (numberOfCredentials > 1 && next == false) {
if (numberOfCredentials > 1 && next == false && (!resident || allowList_len <= 1)) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));
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_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey)));
}

View File

@@ -50,11 +50,18 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aaguid, sizeof(aaguid)));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &arrayEncoder, 8));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &arrayEncoder, 9));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "ep"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, get_opts() & FIDO2_OPT_EA));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "rk"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "alwaysUv"));
if (file_has_data(ef_pin) && (get_opts() & FIDO2_OPT_AUV || !getUserVerifiedFlagValue())) {
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
}
else {
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, false));
}
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "credMgmt"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "authnrCfg"));
@@ -90,11 +97,33 @@ 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));
uint8_t curves = 3;
#ifdef MBEDTLS_EDDSA_C
curves++;
#endif
#ifndef ENABLE_EMULATION
if (phy_data.enabled_curves & PHY_CURVE_SECP256K1) {
#endif
curves++;
#ifndef ENABLE_EMULATION
}
#endif
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, curves));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2));
#ifdef MBEDTLS_EDDSA_C
CBOR_CHECK(COSE_public_key(FIDO2_ALG_EDDSA, &arrayEncoder, &mapEncoder2));
#endif
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));
#ifndef ENABLE_EMULATION
if (phy_data.enabled_curves & PHY_CURVE_SECP256K1) {
#endif
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2));
#ifndef ENABLE_EMULATION
}
#endif
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));

View File

@@ -217,11 +217,22 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
curve = FIDO2_CURVE_P521;
}
}
else if (pubKeyCredParams[i].alg == FIDO2_ALG_ES256K) {
else if (pubKeyCredParams[i].alg == FIDO2_ALG_ES256K
#ifndef ENABLE_EMULATION
&& (phy_data.enabled_curves & PHY_CURVE_SECP256K1)
#endif
) {
if (curve <= 0) {
curve = FIDO2_CURVE_P256K1;
}
}
#ifdef MBEDTLS_EDDSA_C
else if (pubKeyCredParams[i].alg == FIDO2_ALG_EDDSA) {
if (curve <= 0) {
curve = FIDO2_CURVE_ED25519;
}
}
#endif
else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass
}
@@ -337,13 +348,13 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0;
uint8_t minPinLen = 0;
if (extensions.hmac_secret != NULL) {
if (extensions.hmac_secret == ptrue) {
l++;
}
if (extensions.credProtect != 0) {
l++;
}
if (extensions.minPinLength != NULL) {
if (extensions.minPinLength == ptrue) {
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) {
uint8_t *minpin_data = file_get_data(ef_minpin);
@@ -361,40 +372,42 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (extensions.credBlob.present == true) {
l++;
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, extensions.credBlob.len < MAX_CREDBLOB_LENGTH));
}
if (extensions.credProtect != 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect"));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, extensions.credProtect));
}
if (extensions.hmac_secret != NULL) {
if (l > 0) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, extensions.credBlob.len < MAX_CREDBLOB_LENGTH));
}
if (extensions.credProtect != 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect"));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, extensions.credProtect));
}
if (extensions.hmac_secret == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, *extensions.hmac_secret));
}
if (minPinLen > 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
}
if (minPinLen > 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "minPinLength"));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, minPinLen));
}
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "minPinLength"));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, minPinLen));
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED;
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
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;
@@ -416,7 +429,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) {
mbedtls_ecdsa_free(&ekey);
mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
@@ -429,12 +442,19 @@ 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);
#ifdef MBEDTLS_EDDSA_C
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
#endif
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);
uint8_t key[32] = {0};
if (load_keydev(key) != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER);
@@ -444,8 +464,18 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
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);
}
#ifdef MBEDTLS_EDDSA_C
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);
}
#endif
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 (memcmp(user.parent.name.data, "+pico", 5) == 0) {
@@ -455,14 +485,13 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (memcmp(p, "CommissionProfile", 17) == 0) {
ret = phy_unserialize_data(user.id.data, user.id.len, &phy_data);
if (ret == PICOKEY_OK) {
file_put_data(ef_phy, user.id.data, user.id.len);
ret = phy_save();
}
}
#endif
if (ret != 0) {
if (ret != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
low_flash_available();
}
}
@@ -475,7 +504,14 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, extensions.largeBlobKey == ptrue && options.rk == ptrue ? 5 : 4));
uint8_t lparams = 3;
if (enterpriseAttestation == 2) {
lparams++;
}
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
lparams++;
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, lparams));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed"));
@@ -504,8 +540,10 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, enterpriseAttestation == 2));
if (enterpriseAttestation == 2) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
}
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));

View File

@@ -38,29 +38,29 @@ int cmd_authenticate() {
return SW_CONDITIONS_NOT_SATISFIED();
}
mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key);
mbedtls_ecp_keypair key;
mbedtls_ecp_keypair_init(&key);
int ret = 0;
uint8_t *tmp_kh = (uint8_t *) calloc(1, 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);
}
else {
ret = derive_key(req->appId, false, req->keyHandle, MBEDTLS_ECP_DP_SECP256R1, &key);
if (verify_key(req->appId, req->keyHandle, &key) != 0) {
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
free(tmp_kh);
return SW_INCORRECT_PARAMS();
}
}
free(tmp_kh);
if (ret != PICOKEY_OK) {
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
return SW_EXEC_ERROR();
}
if (P1(apdu) == CTAP_AUTH_CHECK_ONLY) {
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
return SW_CONDITIONS_NOT_SATISFIED();
}
resp->flags = 0;
@@ -74,12 +74,12 @@ int cmd_authenticate() {
memcpy(sig_base + CTAP_APPID_SIZE + 1 + 4, req->chal, CTAP_CHAL_SIZE);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sig_base, sizeof(sig_base), hash);
if (ret != 0) {
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&key, MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->sig, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
mbedtls_ecdsa_free(&key);
mbedtls_ecp_keypair_free(&key);
if (ret != 0) {
return SW_EXEC_ERROR();
}

View File

@@ -27,22 +27,59 @@
#include "random.h"
#include "files.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, const uint8_t *rp_id_hash, uint8_t *outk) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, 0);
if (otp_key_1) {
mbedtls_sha256_update(&ctx, otp_key_1, 32);
}
else {
mbedtls_sha256_update(&ctx, pico_serial.id, sizeof(pico_serial.id));
}
mbedtls_sha256_update(&ctx, rp_id_hash, 32);
mbedtls_sha256_finish(&ctx, outk);
mbedtls_sha256_free(&ctx);
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) {
return -1;
}
uint8_t key[32], *iv = cred_id + 4, *cipher = cred_id + 4 + 12,
*tag = cred_id + cred_id_len - 16;
memset(key, 0, sizeof(key));
credential_derive_chacha_key(key);
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
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);
mbedtls_chachapoly_free(&chatx);
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 - CRED_TAG_LEN;
cred_proto_t proto = CRED_PROTO_21;
if (memcmp(cred_id, CRED_PROTO_22_S, CRED_PROTO_LEN) == 0) { // New format
tag = cred_id + cred_id_len - CRED_SILENT_TAG_LEN - CRED_TAG_LEN;
proto = CRED_PROTO_22;
}
int ret = 0;
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, rp_id_hash, outk);
ret = memcmp(outk, cred_id + cred_id_len - CRED_SILENT_TAG_LEN, CRED_SILENT_TAG_LEN);
}
return ret;
}
@@ -113,25 +150,25 @@ int credential_create(CborCharString *rpId,
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
size_t rs = cbor_encoder_get_buffer_size(&encoder, cred_id);
*cred_id_len = 4 + 12 + rs + 16;
uint8_t key[32];
memset(key, 0, sizeof(key));
credential_derive_chacha_key(key);
uint8_t iv[12];
*cred_id_len = CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN + CRED_SILENT_TAG_LEN;
uint8_t key[32] = {0};
credential_derive_chacha_key(key, (const uint8_t *)CRED_PROTO);
uint8_t iv[CRED_IV_LEN] = {0};
random_gen(NULL, iv, sizeof(iv));
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key);
int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32,
cred_id + 4 + 12,
cred_id + 4 + 12,
cred_id + 4 + 12 + rs);
cred_id + CRED_PROTO_LEN + CRED_IV_LEN,
cred_id + CRED_PROTO_LEN + CRED_IV_LEN,
cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs);
mbedtls_chachapoly_free(&chatx);
if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER);
}
memcpy(cred_id, CRED_PROTO, 4);
memcpy(cred_id + 4, iv, 12);
memcpy(cred_id, CRED_PROTO, CRED_PROTO_LEN);
memcpy(cred_id + CRED_PROTO_LEN, iv, CRED_IV_LEN);
credential_silent_tag(cred_id, *cred_id_len, rp_id_hash, cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN);
err:
if (error != CborNoError) {
@@ -152,7 +189,7 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
}
memset(cred, 0, sizeof(Credential));
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 (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) {
CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL);
@@ -350,13 +387,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);
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, cred_id, cred_id_len, outk);
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);
int r = 0;
if ((r = load_keydev(outk)) != 0) {
@@ -365,7 +402,7 @@ int credential_derive_chacha_key(uint8_t *outk) {
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 *) 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);
return 0;
}
@@ -379,7 +416,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);
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, cred_id, cred_id_len, outk);
return 0;

View File

@@ -56,9 +56,23 @@ typedef struct Credential {
#define CRED_PROT_UV_OPTIONAL_WITH_LIST 0x02
#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,
CborByteString *userId,
CborCharString *userName,

View File

@@ -112,6 +112,14 @@ mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
else if (curve == FIDO2_CURVE_X448) {
return MBEDTLS_ECP_DP_CURVE448;
}
#ifdef MBEDTLS_EDDSA_C
else if (curve == FIDO2_CURVE_ED25519) {
return MBEDTLS_ECP_DP_ED25519;
}
else if (curve == FIDO2_CURVE_ED448) {
return MBEDTLS_ECP_DP_ED448;
}
#endif
return MBEDTLS_ECP_DP_NONE;
}
int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
@@ -133,10 +141,18 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
else if (id == MBEDTLS_ECP_DP_CURVE448) {
return FIDO2_CURVE_X448;
}
#ifdef MBEDTLS_EDDSA_C
else if (id == MBEDTLS_ECP_DP_ED25519) {
return FIDO2_CURVE_ED25519;
}
else if (id == MBEDTLS_ECP_DP_ED448) {
return FIDO2_CURVE_ED448;
}
#endif
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;
@@ -202,7 +218,7 @@ int load_keydev(uint8_t *key) {
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++) {
uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
if (!(k & 0x80000000)) {
@@ -235,7 +251,7 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
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
int r = 0;
memset(outk, 0, sizeof(outk));
@@ -280,6 +296,11 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (r != 0) {
return r;
}
#ifdef MBEDTLS_EDDSA_C
if (curve == MBEDTLS_ECP_DP_ED25519) {
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
}
#endif
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
}
mbedtls_platform_zeroize(outk, sizeof(outk));

View File

@@ -28,6 +28,9 @@
#endif
#include "mbedtls/ecdsa.h"
#ifdef MBEDTLS_EDDSA_C
#include "mbedtls/eddsa.h"
#endif
#ifndef ENABLE_EMULATION
#include "hid/ctap_hid.h"
#else
@@ -45,13 +48,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, 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);
@@ -82,6 +85,7 @@ extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSec
#define FIDO2_AUT_FLAG_ED 0x80
#define FIDO2_OPT_EA 0x01 // Enterprise Attestation
#define FIDO2_OPT_AUV 0x02 // User Verification
#define MAX_PIN_RETRIES 8
extern bool getUserPresentFlagValue();

View File

@@ -97,8 +97,21 @@ int man_get_config() {
if (!file_has_data(ef)) {
res_APDU[res_APDU_size++] = TAG_USB_ENABLED;
res_APDU[res_APDU_size++] = 2;
res_APDU[res_APDU_size++] = CAP_FIDO2 >> 8;
res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH;
uint16_t caps = 0;
if (cap_supported(CAP_FIDO2)) {
caps |= CAP_FIDO2;
}
if (cap_supported(CAP_OTP)) {
caps |= CAP_OTP;
}
if (cap_supported(CAP_U2F)) {
caps |= CAP_U2F;
}
if (cap_supported(CAP_OATH)) {
caps |= CAP_OATH;
}
res_APDU[res_APDU_size++] = caps >> 8;
res_APDU[res_APDU_size++] = caps & 0xFF;
res_APDU[res_APDU_size++] = TAG_DEVICE_FLAGS;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = FLAG_EJECT;
@@ -126,6 +139,15 @@ int cmd_write_config() {
file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1));
low_flash_available();
#ifndef ENABLE_EMULATION
if (cap_supported(CAP_OTP)) {
phy_data.enabled_usb_itf |= PHY_USB_ITF_KB;
}
else {
phy_data.enabled_usb_itf &= ~PHY_USB_ITF_KB;
}
phy_save();
#endif
return SW_OK();
}

View File

@@ -584,10 +584,53 @@ int cmd_verify_hotp() {
return SW_OK();
}
int cmd_rename() {
asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 };
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
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();
}
if (memcmp(name.data, new_name.data, name.len) == 0) {
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 = (uint8_t *) calloc(sizeof(uint8_t), fsize + new_name.len - name.len);
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_DELETE 0x02
#define INS_SET_CODE 0x03
#define INS_RESET 0x04
#define INS_RENAME 0x05
#define INS_LIST 0xa1
#define INS_CALCULATE 0xa2
#define INS_VALIDATE 0xa3
@@ -603,6 +646,7 @@ static const cmd_t cmds[] = {
{ INS_DELETE, cmd_delete },
{ INS_SET_CODE, cmd_set_code },
{ INS_RESET, cmd_reset },
{ INS_RENAME, cmd_rename },
{ INS_LIST, cmd_list },
{ INS_VALIDATE, cmd_validate },
{ INS_CALCULATE, cmd_calculate },

View File

@@ -111,7 +111,7 @@ typedef struct otp_config {
}) 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_unload();
@@ -140,10 +140,7 @@ int otp_select(app_t *a, uint8_t force) {
else {
config_seq = 0;
}
otp_status();
memmove(res_APDU, res_APDU + 1, 6);
res_APDU_size = 6;
apdu.ne = res_APDU_size;
otp_status(false);
return PICOKEY_OK;
}
return PICOKEY_ERR_FILE_NOT_FOUND;
@@ -339,22 +336,47 @@ int otp_unload() {
return PICOKEY_OK;
}
uint16_t otp_status() {
uint8_t status_byte = 0x0;
uint16_t otp_status(bool is_otp) {
if (scanned == false) {
scan_all();
scanned = true;
}
res_APDU_size = 0;
res_APDU[1] = PICO_FIDO_VERSION_MAJOR;
res_APDU[2] = PICO_FIDO_VERSION_MINOR;
res_APDU[3] = 0;
res_APDU[4] = config_seq;
res_APDU[5] = (CONFIG2_TOUCH | CONFIG1_TOUCH) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID :
0x00) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID :
0x00);
res_APDU[6] = 0;
if (is_otp) {
res_APDU_size++;
}
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq;
uint8_t opts = 0;
file_t *ef = search_dynamic_file(EF_OTP_SLOT1);
if (file_has_data(ef)) {
opts |= CONFIG1_VALID;
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
if (!(otp_config->tkt_flags & CHAL_RESP) || otp_config->cfg_flags & CHAL_BTN_TRIG) {
opts |= CONFIG1_TOUCH;
}
}
ef = search_dynamic_file(EF_OTP_SLOT2);
if (file_has_data(ef)) {
opts |= CONFIG2_VALID;
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
if (!(otp_config->tkt_flags & CHAL_RESP) || otp_config->cfg_flags & CHAL_BTN_TRIG) {
opts |= CONFIG2_TOUCH;
}
}
res_APDU[res_APDU_size++] = opts;
res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = status_byte;
if (is_otp) {
res_APDU_size = 0;
}
else {
apdu.ne = res_APDU_size;
}
return SW_OK();
}
@@ -363,6 +385,7 @@ bool check_crc(const otp_config_t *data) {
return crc == 0xF0B8;
}
bool _is_otp = false;
int cmd_otp() {
uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p2 != 0x00) {
@@ -386,18 +409,15 @@ int cmd_otp() {
file_put_data(ef, apdu.data, otp_config_size + 8);
low_flash_available();
config_seq++;
return otp_status();
return otp_status(_is_otp);
}
}
// Delete slot
delete_file(ef);
if (!file_has_data(search_dynamic_file(EF_OTP_SLOT1)) &&
!file_has_data(search_dynamic_file(EF_OTP_SLOT2))) {
config_seq = 0;
}
return otp_status();
config_seq++;
return otp_status(_is_otp);
}
else if (p1 == 0x04 || p1 == 0x05) {
else if (p1 == 0x04 || p1 == 0x05) { // Update slot
otp_config_t *odata = (otp_config_t *) apdu.data;
if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) {
return SW_WRONG_DATA();
@@ -414,13 +434,20 @@ int cmd_otp() {
(odata->ext_flags & EXTFLAG_UPDATE_MASK);
odata->tkt_flags = (otpc->tkt_flags & ~TKTFLAG_UPDATE_MASK) |
(odata->tkt_flags & TKTFLAG_UPDATE_MASK);
odata->cfg_flags = (otpc->cfg_flags & ~CFGFLAG_UPDATE_MASK) |
(odata->cfg_flags & CFGFLAG_UPDATE_MASK);
if (!(otpc->tkt_flags & CHAL_RESP)) {
odata->cfg_flags = (otpc->cfg_flags & ~CFGFLAG_UPDATE_MASK) |
(odata->cfg_flags & CFGFLAG_UPDATE_MASK);
}
else {
odata->cfg_flags = otpc->cfg_flags;
}
file_put_data(ef, apdu.data, otp_config_size);
low_flash_available();
config_seq++;
}
return otp_status(_is_otp);
}
else if (p1 == 0x06) {
else if (p1 == 0x06) { // Swap slots
uint8_t tmp[otp_config_size + 8];
bool ef1_data = false;
file_t *ef1 = file_new(EF_OTP_SLOT1);
@@ -434,6 +461,8 @@ int cmd_otp() {
}
else {
delete_file(ef1);
// When a dynamic file is deleted, existing referenes are invalidated
ef2 = file_new(EF_OTP_SLOT2);
}
if (ef1_data) {
file_put_data(ef2, tmp, sizeof(tmp));
@@ -442,34 +471,60 @@ int cmd_otp() {
delete_file(ef2);
}
low_flash_available();
config_seq++;
return otp_status(_is_otp);
}
else if (p1 == 0x10) {
memcpy(res_APDU, pico_serial.id, 4);
res_APDU_size = 4;
}
else if (p1 == 0x13) {
else if (p1 == 0x13) { // Get config
man_get_config();
}
else if (p1 == 0x30 || p1 == 0x38 || p1 == 0x20 || p1 == 0x28) {
else if (p1 == 0x30 || p1 == 0x38 || p1 == 0x20 || p1 == 0x28) { // Calculate OTP
file_t *ef = search_dynamic_file(p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
if (file_has_data(ef)) {
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
if (!(otp_config->cfg_flags & CHAL_YUBICO && otp_config->tkt_flags & CHAL_RESP)) {
if (!(otp_config->tkt_flags & CHAL_RESP)) {
return SW_WRONG_DATA();
}
int ret = 0;
#ifndef ENABLE_EMULATION
uint8_t *rdata_bk = apdu.rdata;
if (otp_config->cfg_flags & CHAL_BTN_TRIG) {
status_byte = 0x20;
otp_status(_is_otp);
if (wait_button() == true) {
status_byte = 0x00;
otp_status(_is_otp);
return SW_CONDITIONS_NOT_SATISFIED();
}
status_byte = 0x10;
apdu.rdata = rdata_bk;
}
#endif
if (p1 == 0x30 || p1 == 0x38) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
otp_config->aes_key,
KEY_SIZE,
apdu.data,
8,
res_APDU);
if (!(otp_config->cfg_flags & CHAL_HMAC)) {
return SW_WRONG_DATA();
}
uint8_t aes_key[KEY_SIZE + UID_SIZE];
memcpy(aes_key, otp_config->aes_key, KEY_SIZE);
memcpy(aes_key + KEY_SIZE, otp_config->uid, UID_SIZE);
uint8_t chal_len = 64;
if (otp_config->cfg_flags & HMAC_LT64) {
while (chal_len > 0 && apdu.data[63] == apdu.data[chal_len - 1]) {
chal_len--;
}
}
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), aes_key, sizeof(aes_key), apdu.data, chal_len, res_APDU);
if (ret == 0) {
res_APDU_size = 20;
}
}
else if (p1 == 0x20 || p1 == 0x28) {
if (!(otp_config->cfg_flags & CHAL_YUBICO)) {
return SW_WRONG_DATA();
}
uint8_t challenge[16];
memcpy(challenge, apdu.data, 6);
memcpy(challenge + 6, pico_serial_str, 10);
@@ -482,6 +537,9 @@ int cmd_otp() {
res_APDU_size = 16;
}
}
if (ret == 0) {
status_byte = 0x00;
}
}
}
return SW_OK();
@@ -530,49 +588,45 @@ int otp_send_frame(uint8_t *frame, size_t frame_len) {
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 (itf == ITF_KEYBOARD) {
if (report_type == 3) {
DEBUG_PAYLOAD(buffer, bufsize);
if (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));
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 (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));
DEBUG_PAYLOAD(otp_frame_rx, sizeof(otp_frame_rx));
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_t_le(otp_frame_rx + 65);
uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) {
uint8_t hdr[5];
apdu.header = hdr;
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;
_is_otp = true;
int ret = otp_process_apdu();
if (ret == 0x9000 && res_APDU_size > 0) {
otp_send_frame(apdu.rdata, apdu.rlen);
}
_is_otp = false;
}
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 = get_uint16_t_le(otp_frame_rx + 65);
uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) {
uint8_t hdr[5];
apdu.header = hdr;
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");
}
else {
printf("[OTP] Bad CRC!\n");
}
}
}
@@ -610,7 +664,8 @@ uint16_t otp_hid_get_report_cb(uint8_t itf,
}
else {
res_APDU = buffer;
otp_status();
otp_status(true);
DEBUG_DATA(buffer, 8);
}
return reqlen;

View File

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

View File

@@ -3,5 +3,5 @@
source tests/docker_env.sh
#run_in_docker rm -rf CMakeFiles
run_in_docker mkdir -p build_in_docker
run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 ..
run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -DENABLE_EDDSA=1 ..
run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC}

View File

@@ -19,7 +19,7 @@
from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512
from fido2.cose import ES256, ES384, ES512, EdDSA
import fido2.features
fido2.features.webauthn_json_mapping.enabled = False
from utils import ES256K
@@ -124,7 +124,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):

View File

@@ -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):
@@ -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=[
{"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):
device.reset()
with pytest.raises(CtapError) as e:

View File

@@ -57,9 +57,8 @@ def test_with_allow_list_after_reset(device, MCRes_DC, GARes_DC):
device.reset()
with pytest.raises(CtapError) as e:
ga_res = device.doGA(allow_list=allow_list)
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
# It returns a silent authentication
ga_res = device.doGA(allow_list=allow_list)
@@ -255,5 +254,5 @@ def test_returned_credential(device):
device.GNA()
# the returned credential should have user id in it
print(ga_res)
assert 'id' in ga_res.user and len(ga_res.user["id"]) > 0
#print(ga_res)
#assert 'id' in ga_res.user and len(ga_res.user["id"]) > 0

View File

@@ -69,7 +69,7 @@ def test_minpin(SetMinPin, MCMinPin):
def test_minpin_bad_rpid(SetMinPinWrongRpid, MCMinPin):
assert not MCMinPin.auth_data.extensions
assert "minPinLength" not in MCMinPin.auth_data.extensions
#assert "minPinLength" not in MCMinPin.auth_data.extensions
def test_setminpin(device, SetMinPin, MCMinPin):
cfg = FidoConfig(device)

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
git clone https://github.com/raspberrypi/pico-sdk
cd pico-sdk
git checkout tags/2.1.0
git checkout tags/2.1.1
git submodule update --init
cd ..
git clone https://github.com/raspberrypi/picotool
@@ -37,6 +37,16 @@ mkdir -p release
cd build
esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_fido_esp32-s3.bin @flash_args
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
mkdir build
cd build