Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfe1321d62 | ||
|
|
2cbea57c86 | ||
|
|
b6bf2e6c66 | ||
|
|
3212f95915 | ||
|
|
21b12a7bff | ||
|
|
c8dbc213a0 | ||
|
|
0a2ee6523f | ||
|
|
c3ea413592 | ||
|
|
64f371e6e5 | ||
|
|
fdd4afb993 | ||
|
|
fef46dc1c5 | ||
|
|
23a45ac297 | ||
|
|
b152ff15a8 | ||
|
|
751fcf0538 | ||
|
|
4e4c28a479 | ||
|
|
23b60beb2e | ||
|
|
37d7d7faeb | ||
|
|
49c0179ccf | ||
|
|
eacb8a040c | ||
|
|
cb99b8f401 | ||
|
|
94f8d5f65f | ||
|
|
38d332f450 | ||
|
|
c67f5e3a1f | ||
|
|
bfb8a4cb20 | ||
|
|
0f5a24c9b6 | ||
|
|
dd207bd031 | ||
|
|
6069cf949b | ||
|
|
297c34914b | ||
|
|
529a12e7a3 | ||
|
|
bdbdd92be8 | ||
|
|
3807e23914 | ||
|
|
ce7d3ea72f | ||
|
|
eb857df3e1 | ||
|
|
2842944d90 | ||
|
|
7be92f5331 | ||
|
|
403b26b60a | ||
|
|
b91ece8ec3 | ||
|
|
d54bc1b0f3 | ||
|
|
e2dbbe2cc3 | ||
|
|
8aa9d1c5a3 | ||
|
|
2d2814cefc | ||
|
|
89a9d013f0 | ||
|
|
964184cd9f | ||
|
|
d6a060f214 | ||
|
|
c443dec4a0 | ||
|
|
8ae4ab5af4 | ||
|
|
d2c25b69bc | ||
|
|
21765a6f10 | ||
|
|
eb2c92bc5c | ||
|
|
233c5a7c7d | ||
|
|
3b4ac12d0f | ||
|
|
7c5bab8b05 | ||
|
|
21035d649d | ||
|
|
abe91823c0 | ||
|
|
91e049b997 | ||
|
|
8836902dc1 | ||
|
|
a019b54d69 | ||
|
|
3adb1a8422 | ||
|
|
95a9fe4214 | ||
|
|
8af7cac57a | ||
|
|
7997eefdc8 | ||
|
|
e18f841a34 | ||
|
|
73b51cabfc | ||
|
|
ad3b2bbe4b | ||
|
|
b9ad8f4745 | ||
|
|
8242dc8d80 | ||
|
|
2f6e4d5568 | ||
|
|
911dab031e | ||
|
|
3a71275bc8 | ||
|
|
9f1e879efe | ||
|
|
57bf97196d | ||
|
|
e8c8ce4d15 | ||
|
|
69d618cc6b | ||
|
|
e057f17180 |
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@@ -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
|
||||||
|
|||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Submodule pico-keys-sdk updated: 6e6b524878...580b0acffa
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
165
src/fido/otp.c
165
src/fido/otp.c
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user