74 Commits
v6.4 ... 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
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
24 changed files with 478 additions and 235 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

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

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

@@ -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,23 +1,47 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="6" VERSION_MAJOR="6"
VERSION_MINOR="4" VERSION_MINOR="6"
NO_EDDSA=0
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}"
#fi #fi
rm -rf release/* if [[ $1 == "--no-eddsa" ]]; then
NO_EDDSA=1
echo "Skipping EDDSA build"
fi
mkdir -p build_release mkdir -p build_release
mkdir -p 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 cd build_release
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}" PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}"
board_dir=${PICO_SDK_PATH}/src/boards/include/boards board_dir=${PICO_SDK_PATH}/src/boards/include/boards
for board in "$board_dir"/* for board in "$board_dir"/*
do do
board_name="$(basename -- $board .h)" board_name="$(basename -- "$board" .h)"
rm -rf * rm -rf -- ./*
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=../../ec_private_key.pem
make -j`nproc` make -j`nproc`
mv pico_fido.uf2 ../release/pico_fido_$board_name-$SUFFIX.uf2 mv pico_fido.uf2 ../release/pico_fido_$board_name-$SUFFIX.uf2
done 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); apdu.sw = cbor_parse(cbor_cmd, cbor_data, cbor_len);
if (apdu.sw == 0) { if (apdu.sw == 0) {
DEBUG_DATA(res_APDU + 1, res_APDU_size); DEBUG_DATA(res_APDU, res_APDU_size);
} }
else { else {
if (apdu.sw >= CTAP1_ERR_INVALID_CHANNEL) { 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) { else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
alg = FIDO2_ALG_ECDH_ES_HKDF_256; 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); 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

@@ -243,11 +243,11 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
} }
mbedtls_ecdsa_context key; mbedtls_ecp_keypair key;
mbedtls_ecdsa_init(&key); mbedtls_ecp_keypair_init(&key);
if (fido_load_key((int)cred.curve, cred.id.data, &key) != 0) { if (fido_load_key((int)cred.curve, cred.id.data, &key) != 0) {
credential_free(&cred); credential_free(&cred);
mbedtls_ecdsa_free(&key); mbedtls_ecp_keypair_free(&key);
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); 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)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, false));
} }
credential_free(&cred); credential_free(&cred);
mbedtls_ecdsa_free(&key); mbedtls_ecp_keypair_free(&key);
} }
else if (subcommand == 0x06) { else if (subcommand == 0x06) {
if (credentialId.id.present == false) { 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 }; Credential creds[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
size_t allowList_len = 0, creds_len = 0; size_t allowList_len = 0, creds_len = 0;
uint8_t *aut_data = NULL; 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; int64_t kty = 2, alg = 0, crv = 0;
CborByteString kax = { 0 }, kay = { 0 }, salt_enc = { 0 }, salt_auth = { 0 }; CborByteString kax = { 0 }, kay = { 0 }, salt_enc = { 0 }, salt_auth = { 0 };
const bool *credBlob = NULL; 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 if (options.uv == ptrue) { //4.3
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); 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 //if (options.up != NULL) { //4.5
// CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); // 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 //else if (options.up == NULL) //5.7
//rup = ptrue; //rup = ptrue;
if (options.uv != NULL) {
uv = *options.uv;
}
if (options.up != NULL) { if (options.up != NULL) {
up = *options.up; up = *options.up;
} }
else {
up = true;
}
} }
if (pinUvAuthParam.present == true) { //6.1 if (pinUvAuthParam.present == true) { //6.1
@@ -294,6 +300,23 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
else { else {
creds_len++; 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;
}
}
} }
} }
} }
@@ -309,6 +332,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
else { else {
creds_len++; creds_len++;
silent = false; // If we are able to load a credential, we are not silent
} }
} }
resident = true; resident = true;
@@ -445,91 +469,93 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (options.up == pfalse) { if (options.up == pfalse) {
extensions.hmac_secret = NULL; extensions.hmac_secret = NULL;
} }
if (extensions.hmac_secret != NULL) { if (extensions.hmac_secret == ptrue) {
l++; l++;
} }
if (credBlob == ptrue) { if (credBlob == ptrue) {
l++; l++;
} }
if (extensions.thirdPartyPayment != NULL) { if (extensions.thirdPartyPayment == ptrue) {
l++; l++;
} }
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); if (l > 0) {
if (credBlob == ptrue) { CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob")); if (credBlob == ptrue) {
if (selcred->extensions.credBlob.present == true) { CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, selcred->extensions.credBlob.data, if (selcred->extensions.credBlob.present == true) {
selcred->extensions.credBlob.len)); 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 { if (extensions.hmac_secret == ptrue) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, NULL, 0));
}
}
if (extensions.hmac_secret != NULL) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret"));
uint8_t sharedSecret[64] = {0}; uint8_t sharedSecret[64] = {0};
mbedtls_ecp_point Qp; mbedtls_ecp_point Qp;
mbedtls_ecp_point_init(&Qp); mbedtls_ecp_point_init(&Qp);
mbedtls_mpi_lset(&Qp.Z, 1); mbedtls_mpi_lset(&Qp.Z, 1);
if (mbedtls_mpi_read_binary(&Qp.X, kax.data, kax.len) != 0) { 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); 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) { if (extensions.thirdPartyPayment == ptrue) {
mbedtls_ecp_point_free(&Qp); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "thirdPartyPayment"));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); 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)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
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;
}
} }
uint32_t ctr = get_sign_counter(); uint32_t ctr = get_sign_counter();
@@ -548,14 +574,14 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
memcpy(pa, clientDataHash.data, clientDataHash.len); memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[64] = {0}, sig[MBEDTLS_ECDSA_MAX_LEN] = {0}; 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); const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_ecdsa_context ekey; mbedtls_ecp_keypair ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
size_t olen = 0; size_t olen = 0;
if (selcred) { if (selcred) {
ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey); ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey);
if (ret != 0) { if (ret != 0) {
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) { if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
} }
@@ -565,21 +591,36 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
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); #ifdef MBEDTLS_EDDSA_C
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 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 { else {
// Bogus signature // Bogus signature
olen = 64; olen = 64;
memset(sig, 0x0B, olen); memset(sig, 0x0B, olen);
} }
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
uint8_t lfields = 3; uint8_t lfields = 3;
if (selcred && 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 && (!resident || allowList_len <= 1)) {
lfields++; lfields++;
} }
if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) { if (selcred && extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
@@ -633,7 +674,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); 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, 0x05));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials));
} }

View File

@@ -50,11 +50,18 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aaguid, sizeof(aaguid))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aaguid, sizeof(aaguid)));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); 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_text_stringz(&arrayEncoder, "ep"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, get_opts() & FIDO2_OPT_EA)); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, get_opts() & FIDO2_OPT_EA));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "rk")); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "rk"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true)); 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_text_stringz(&arrayEncoder, "credMgmt"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "authnrCfg")); 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, 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));
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)); 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_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)); #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_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B)); 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; 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) { if (curve <= 0) {
curve = FIDO2_CURVE_P256K1; 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) { else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass // pass
} }
@@ -337,13 +348,13 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0); cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0; int l = 0;
uint8_t minPinLen = 0; uint8_t minPinLen = 0;
if (extensions.hmac_secret != NULL) { if (extensions.hmac_secret == ptrue) {
l++; l++;
} }
if (extensions.credProtect != 0) { if (extensions.credProtect != 0) {
l++; l++;
} }
if (extensions.minPinLength != NULL) { if (extensions.minPinLength == ptrue) {
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) { if (file_has_data(ef_minpin)) {
uint8_t *minpin_data = file_get_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) { if (extensions.credBlob.present == true) {
l++; l++;
} }
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); if (l > 0) {
if (extensions.credBlob.present == true) { CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob")); if (extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, extensions.credBlob.len < MAX_CREDBLOB_LENGTH)); 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")); if (extensions.credProtect != 0) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, extensions.credProtect)); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect"));
} CBOR_CHECK(cbor_encode_uint(&mapEncoder, extensions.credProtect));
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"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, *extensions.hmac_secret)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
} }
if (minPinLen > 0) { if (minPinLen > 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "minPinLength")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "minPinLength"));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, minPinLen)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, minPinLen));
} }
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
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 +429,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 +442,19 @@ 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); #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; 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 +464,18 @@ 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);
}
#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 (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) {
@@ -474,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_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_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed"));
@@ -503,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_encoder_close_container(&mapEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); if (enterpriseAttestation == 2) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, enterpriseAttestation == 2)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
}
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) { if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));

View File

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

View File

@@ -31,13 +31,20 @@
int credential_derive_chacha_key(uint8_t *outk, const uint8_t *); int credential_derive_chacha_key(uint8_t *outk, const uint8_t *);
static int credential_silent_tag(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) { 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) { if (otp_key_1) {
memcpy(outk, otp_key_1, 32); mbedtls_sha256_update(&ctx, otp_key_1, 32);
} }
else { else {
mbedtls_sha256(pico_serial.id, PICO_UNIQUE_BOARD_ID_SIZE_BYTES, outk, 0); 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); return mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, cred_id, cred_id_len - CRED_SILENT_TAG_LEN, outk);
} }
@@ -70,7 +77,7 @@ int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id
return -1; return -1;
} }
uint8_t outk[32]; uint8_t outk[32];
ret = credential_silent_tag(cred_id, cred_id_len, outk); 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); ret = memcmp(outk, cred_id + cred_id_len - CRED_SILENT_TAG_LEN, CRED_SILENT_TAG_LEN);
} }
return ret; return ret;
@@ -161,7 +168,7 @@ int credential_create(CborCharString *rpId,
} }
memcpy(cred_id, CRED_PROTO, CRED_PROTO_LEN); memcpy(cred_id, CRED_PROTO, CRED_PROTO_LEN);
memcpy(cred_id + CRED_PROTO_LEN, iv, CRED_IV_LEN); 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); credential_silent_tag(cred_id, *cred_id_len, rp_id_hash, cred_id + CRED_PROTO_LEN + CRED_IV_LEN + rs + CRED_TAG_LEN);
err: err:
if (error != CborNoError) { if (error != CborNoError) {

View File

@@ -112,6 +112,14 @@ 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;
} }
#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; 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 +141,18 @@ 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;
} }
#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; 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 +218,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 +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)); 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 +296,11 @@ 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;
} }
#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); 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,9 @@
#endif #endif
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#ifdef MBEDTLS_EDDSA_C
#include "mbedtls/eddsa.h"
#endif
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#else #else
@@ -45,13 +48,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);
@@ -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_AUT_FLAG_ED 0x80
#define FIDO2_OPT_EA 0x01 // Enterprise Attestation #define FIDO2_OPT_EA 0x01 // Enterprise Attestation
#define FIDO2_OPT_AUV 0x02 // User Verification
#define MAX_PIN_RETRIES 8 #define MAX_PIN_RETRIES 8
extern bool getUserPresentFlagValue(); extern bool getUserPresentFlagValue();

View File

@@ -97,8 +97,21 @@ int man_get_config() {
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
res_APDU[res_APDU_size++] = TAG_USB_ENABLED; res_APDU[res_APDU_size++] = TAG_USB_ENABLED;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
res_APDU[res_APDU_size++] = CAP_FIDO2 >> 8; uint16_t caps = 0;
res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH; 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++] = TAG_DEVICE_FLAGS;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = FLAG_EJECT; res_APDU[res_APDU_size++] = FLAG_EJECT;
@@ -126,6 +139,15 @@ int cmd_write_config() {
file_t *ef = file_new(EF_DEV_CONF); file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1)); file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1));
low_flash_available(); 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(); return SW_OK();
} }

View File

@@ -586,6 +586,10 @@ int cmd_verify_hotp() {
int cmd_rename() { int cmd_rename() {
asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 }; asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 };
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (apdu.data[0] != TAG_NAME) { if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
@@ -598,6 +602,9 @@ int cmd_rename() {
if (asn1_find_tag(&ctxi, TAG_NAME, &new_name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
return SW_WRONG_DATA(); 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); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
@@ -608,13 +615,7 @@ int cmd_rename() {
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) { if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
uint8_t *new_data; uint8_t *new_data = (uint8_t *) calloc(sizeof(uint8_t), fsize + new_name.len - name.len);
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); memcpy(new_data, fdata, name.data - fdata);
*(new_data + (name.data - fdata) - 1) = new_name.len; *(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.data, new_name.len);

View File

@@ -336,6 +336,7 @@ int otp_unload() {
return PICOKEY_OK; return PICOKEY_OK;
} }
uint8_t status_byte = 0x0;
uint16_t otp_status(bool is_otp) { uint16_t otp_status(bool is_otp) {
if (scanned == false) { if (scanned == false) {
scan_all(); scan_all();
@@ -349,12 +350,26 @@ uint16_t otp_status(bool is_otp) {
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq; res_APDU[res_APDU_size++] = config_seq;
res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) | uint8_t opts = 0;
(file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID : file_t *ef = search_dynamic_file(EF_OTP_SLOT1);
0x00) | if (file_has_data(ef)) {
(file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID : opts |= CONFIG1_VALID;
0x00); 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++] = 0;
res_APDU[res_APDU_size++] = status_byte;
if (is_otp) { if (is_otp) {
res_APDU_size = 0; res_APDU_size = 0;
} }
@@ -402,7 +417,7 @@ int cmd_otp() {
config_seq++; config_seq++;
return otp_status(_is_otp); 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; otp_config_t *odata = (otp_config_t *) apdu.data;
if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) { if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
@@ -419,14 +434,20 @@ int cmd_otp() {
(odata->ext_flags & EXTFLAG_UPDATE_MASK); (odata->ext_flags & EXTFLAG_UPDATE_MASK);
odata->tkt_flags = (otpc->tkt_flags & ~TKTFLAG_UPDATE_MASK) | odata->tkt_flags = (otpc->tkt_flags & ~TKTFLAG_UPDATE_MASK) |
(odata->tkt_flags & TKTFLAG_UPDATE_MASK); (odata->tkt_flags & TKTFLAG_UPDATE_MASK);
odata->cfg_flags = (otpc->cfg_flags & ~CFGFLAG_UPDATE_MASK) | if (!(otpc->tkt_flags & CHAL_RESP)) {
(odata->cfg_flags & CFGFLAG_UPDATE_MASK); 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); file_put_data(ef, apdu.data, otp_config_size);
low_flash_available(); low_flash_available();
config_seq++;
} }
return otp_status(_is_otp); return otp_status(_is_otp);
} }
else if (p1 == 0x06) { else if (p1 == 0x06) { // Swap slots
uint8_t tmp[otp_config_size + 8]; uint8_t tmp[otp_config_size + 8];
bool ef1_data = false; bool ef1_data = false;
file_t *ef1 = file_new(EF_OTP_SLOT1); file_t *ef1 = file_new(EF_OTP_SLOT1);
@@ -440,6 +461,8 @@ int cmd_otp() {
} }
else { else {
delete_file(ef1); delete_file(ef1);
// When a dynamic file is deleted, existing referenes are invalidated
ef2 = file_new(EF_OTP_SLOT2);
} }
if (ef1_data) { if (ef1_data) {
file_put_data(ef2, tmp, sizeof(tmp)); file_put_data(ef2, tmp, sizeof(tmp));
@@ -448,30 +471,60 @@ int cmd_otp() {
delete_file(ef2); delete_file(ef2);
} }
low_flash_available(); low_flash_available();
config_seq++;
return otp_status(_is_otp); 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);
res_APDU_size = 4; res_APDU_size = 4;
} }
else if (p1 == 0x13) { else if (p1 == 0x13) { // Get config
man_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); file_t *ef = search_dynamic_file(p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
if (file_has_data(ef)) { if (file_has_data(ef)) {
otp_config_t *otp_config = (otp_config_t *) file_get_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(); return SW_WRONG_DATA();
} }
int ret = 0; 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) { 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) { if (ret == 0) {
res_APDU_size = 20; res_APDU_size = 20;
} }
} }
else if (p1 == 0x20 || p1 == 0x28) { else if (p1 == 0x20 || p1 == 0x28) {
if (!(otp_config->cfg_flags & CHAL_YUBICO)) {
return SW_WRONG_DATA();
}
uint8_t challenge[16]; uint8_t challenge[16];
memcpy(challenge, apdu.data, 6); memcpy(challenge, apdu.data, 6);
memcpy(challenge + 6, pico_serial_str, 10); memcpy(challenge + 6, pico_serial_str, 10);
@@ -484,6 +537,9 @@ int cmd_otp() {
res_APDU_size = 16; res_APDU_size = 16;
} }
} }
if (ret == 0) {
status_byte = 0x00;
}
} }
} }
return SW_OK(); return SW_OK();
@@ -532,51 +588,45 @@ int otp_send_frame(uint8_t *frame, size_t frame_len) {
return 0; return 0;
} }
int otp_hid_set_report_cb(uint8_t itf, 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) {
uint8_t report_id, if (report_type == 3) {
hid_report_type_t report_type, DEBUG_PAYLOAD(buffer, bufsize);
uint8_t const *buffer, if (buffer[7] == 0xFF) { // reset
uint16_t bufsize) *get_send_buffer_size(ITF_KEYBOARD) = 0;
{ otp_curr_seq = otp_exp_seq = 0;
if (itf == ITF_KEYBOARD) { memset(otp_frame_tx, 0, sizeof(otp_frame_tx));
if (report_type == 3) { }
DEBUG_PAYLOAD(buffer, bufsize); else if (buffer[7] & 0x80) { // a frame
if (buffer[7] == 0xFF) { // reset uint8_t rseq = buffer[7] & 0x1F;
*get_send_buffer_size(ITF_KEYBOARD) = 0; if (rseq < 10) {
otp_curr_seq = otp_exp_seq = 0; if (rseq == 0) {
memset(otp_frame_tx, 0, sizeof(otp_frame_tx)); memset(otp_frame_rx, 0, sizeof(otp_frame_rx));
} }
else if (buffer[7] & 0x80) { // a frame memcpy(otp_frame_rx + rseq * 7, buffer, 7);
uint8_t rseq = buffer[7] & 0x1F; if (rseq == 9) {
if (rseq < 10) { DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx));
if (rseq == 0) { DEBUG_PAYLOAD(otp_frame_rx, sizeof(otp_frame_rx));
memset(otp_frame_rx, 0, 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); else {
if (rseq == 9) { printf("[OTP] Bad CRC!\n");
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;
_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;
}
else {
printf("[OTP] Bad CRC!\n");
}
} }
} }
} }
@@ -615,6 +665,7 @@ uint16_t otp_hid_get_report_cb(uint8_t itf,
else { else {
res_APDU = buffer; res_APDU = buffer;
otp_status(true); otp_status(true);
DEBUG_DATA(buffer, 8);
} }
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 0x0604 #define PICO_FIDO_VERSION 0x0606
#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

@@ -3,5 +3,5 @@
source tests/docker_env.sh source tests/docker_env.sh
#run_in_docker rm -rf CMakeFiles #run_in_docker rm -rf CMakeFiles
run_in_docker mkdir -p build_in_docker 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} 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.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):

View File

@@ -57,9 +57,8 @@ def test_with_allow_list_after_reset(device, MCRes_DC, GARes_DC):
device.reset() device.reset()
with pytest.raises(CtapError) as e: # It returns a silent authentication
ga_res = device.doGA(allow_list=allow_list) ga_res = device.doGA(allow_list=allow_list)
assert e.value.code == CtapError.ERR.NO_CREDENTIALS

View File

@@ -69,7 +69,7 @@ def test_minpin(SetMinPin, MCMinPin):
def test_minpin_bad_rpid(SetMinPinWrongRpid, MCMinPin): def test_minpin_bad_rpid(SetMinPinWrongRpid, MCMinPin):
assert not MCMinPin.auth_data.extensions 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): def test_setminpin(device, SetMinPin, MCMinPin):
cfg = FidoConfig(device) cfg = FidoConfig(device)