From cf5dbc9ae511c1a8f685a6208947d74171bbaf5e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 18 Sep 2024 19:42:14 +0200 Subject: [PATCH] Add support for dynamic VIDPID via PHY. Signed-off-by: Pol Henarejos --- src/fido/cbor_config.c | 55 +++++++++++++++++++++++++++++++++++++++--- src/fido/cbor_vendor.c | 53 ++++++---------------------------------- src/fido/ctap.h | 2 ++ 3 files changed, 62 insertions(+), 48 deletions(-) diff --git a/src/fido/cbor_config.c b/src/fido/cbor_config.c index d12b11a..e29eb2b 100644 --- a/src/fido/cbor_config.c +++ b/src/fido/cbor_config.c @@ -27,6 +27,7 @@ #include "mbedtls/ecdh.h" #include "mbedtls/chachapoly.h" #include "mbedtls/sha256.h" +#include "file.h" extern uint8_t keydev_dec[32]; extern bool has_keydev_dec; @@ -35,7 +36,7 @@ int cbor_config(const uint8_t *data, size_t len) { CborParser parser; CborValue map; CborError error = CborNoError; - uint64_t subcommand = 0, pinUvAuthProtocol = 0, vendorCommandId = 0, newMinPinLength = 0; + uint64_t subcommand = 0, pinUvAuthProtocol = 0, vendorCommandId = 0, newMinPinLength = 0, vendorParam = 0; CborByteString pinUvAuthParam = { 0 }, vendorAutCt = { 0 }; CborCharString minPinLengthRPIDs[32] = { 0 }; size_t resp_size = 0, raw_subpara_len = 0, minPinLengthRPIDs_len = 0; @@ -65,7 +66,7 @@ int cbor_config(const uint8_t *data, size_t len) { raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1); CBOR_PARSE_MAP_START(_f1, 2) { - if (subcommand == 0x7f) { + if (subcommand == 0x7f) { // Config Aut CBOR_FIELD_GET_UINT(subpara, 2); if (subpara == 0x01) { CBOR_FIELD_GET_UINT(vendorCommandId, 2); @@ -74,7 +75,7 @@ int cbor_config(const uint8_t *data, size_t len) { CBOR_FIELD_GET_BYTES(vendorAutCt, 2); } } - else if (subcommand == 0x03) { + else if (subcommand == 0x03) { // Extensions CBOR_FIELD_GET_UINT(subpara, 2); if (subpara == 0x01) { CBOR_FIELD_GET_UINT(newMinPinLength, 2); @@ -94,6 +95,15 @@ int cbor_config(const uint8_t *data, size_t len) { CBOR_FIELD_GET_BOOL(forceChangePin, 2); } } + else if (subcommand == 0x1B) { // PHY + CBOR_FIELD_GET_UINT(subpara, 2); + if (subpara == 0x01) { + CBOR_FIELD_GET_UINT(vendorCommandId, 2); + } + else if (subpara == 0x02) { + CBOR_FIELD_GET_UINT(vendorParam, 2); + } + } } CBOR_PARSE_MAP_END(_f1, 2); raw_subpara_len = cbor_value_get_next_byte(&_f1) - raw_subpara; @@ -212,6 +222,45 @@ int cbor_config(const uint8_t *data, size_t len) { set_opts(get_opts() | FIDO2_OPT_EA); goto err; } +#ifndef ENABLE_EMULATION + else if (subcommand == 0x1B) { + uint8_t tmp[PHY_MAX_SIZE]; + memset(tmp, 0, sizeof(tmp)); + uint16_t opts = 0; + if (file_has_data(ef_phy)) { + memcpy(tmp, file_get_data(ef_phy), MIN(sizeof(tmp), file_get_size(ef_phy))); + if (file_get_size(ef_phy) >= 8) { + opts = (tmp[PHY_OPTS] << 8) | tmp[PHY_OPTS + 1]; + } + } + if (vendorCommandId == CTAP_CONFIG_PHY_VIDPID) { + if (vendorParam != 0) { + uint8_t d[4] = { (vendorParam >> 24) & 0xFF, (vendorParam >> 16) & 0xFF, (vendorParam >> 8) & 0xFF, vendorParam & 0xFF }; + memcpy(tmp + PHY_VID, d, sizeof(d)); + opts |= PHY_OPT_VPID; + } + else { + CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); + } + } + else if (vendorCommandId == CTAP_CONFIG_PHY_OPTS) { + if (vendorParam != 0) { + uint16_t opt = (uint16_t)vendorParam; + opts = (opts & ~PHY_OPT_MASK) | (opt & PHY_OPT_MASK); + } + else { + CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); + } + } + else { + CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); + } + tmp[PHY_OPTS] = opts >> 8; + tmp[PHY_OPTS + 1] = opts & 0xff; + file_put_data(ef_phy, tmp, sizeof(tmp)); + low_flash_available(); + } +#endif else { CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); } diff --git a/src/fido/cbor_vendor.c b/src/fido/cbor_vendor.c index 3e99c92..d2ef5f4 100644 --- a/src/fido/cbor_vendor.c +++ b/src/fido/cbor_vendor.c @@ -37,14 +37,7 @@ int mse_decrypt_ct(uint8_t *data, size_t len) { mbedtls_chachapoly_context chatx; mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12); - int ret = mbedtls_chachapoly_auth_decrypt(&chatx, - len - 16, - mse.key_enc, - mse.Qpt, - 65, - data + len - 16, - data, - data); + int ret = mbedtls_chachapoly_auth_decrypt(&chatx, len - 16, mse.key_enc, mse.Qpt, 65, data + len - 16, data, data); mbedtls_chachapoly_free(&chatx); return ret; } @@ -112,8 +105,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); - CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_keydev_enc), - file_get_size(ef_keydev_enc))); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_keydev_enc), file_get_size(ef_keydev_enc))); } else if (vendorCmd == 0x02) { if (vendorParam.present == false) { @@ -140,11 +132,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { mbedtls_ecdh_context hkey; mbedtls_ecdh_init(&hkey); mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1); - int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, - &hkey.ctx.mbed_ecdh.d, - &hkey.ctx.mbed_ecdh.Q, - random_gen, - NULL); + int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL); mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1); if (ret != 0) { CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); @@ -160,37 +148,19 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { uint8_t buf[MBEDTLS_ECP_MAX_BYTES]; size_t olen = 0; - ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, - &hkey.ctx.mbed_ecdh.Qp, - MBEDTLS_ECP_PF_UNCOMPRESSED, - &olen, - mse.Qpt, - sizeof(mse.Qpt)); + ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Qp, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, mse.Qpt,sizeof(mse.Qpt)); if (ret != 0) { mbedtls_ecdh_free(&hkey); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); } - ret = mbedtls_ecdh_calc_secret(&hkey, - &olen, - buf, - MBEDTLS_ECP_MAX_BYTES, - random_gen, - NULL); + ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL); if (ret != 0) { mbedtls_ecdh_free(&hkey); mbedtls_platform_zeroize(buf, sizeof(buf)); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); } - ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), - NULL, - 0, - buf, - olen, - mse.Qpt, - sizeof(mse.Qpt), - mse.key_enc, - sizeof(mse.key_enc)); + ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, buf, olen, mse.Qpt, sizeof(mse.Qpt), mse.key_enc, sizeof(mse.key_enc)); mbedtls_platform_zeroize(buf, sizeof(buf)); if (ret != 0) { mbedtls_ecdh_free(&hkey); @@ -248,9 +218,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { } mbedtls_x509write_csr ctx; mbedtls_x509write_csr_init(&ctx); - snprintf((char *) buffer, - sizeof(buffer), - "C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %s", pico_serial_str); + snprintf((char *) buffer, sizeof(buffer), "C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %s", pico_serial_str); mbedtls_x509write_csr_set_subject_name(&ctx, (char *) buffer); mbedtls_pk_context key; mbedtls_pk_init(&key); @@ -258,12 +226,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) { key.pk_ctx = &ekey; mbedtls_x509write_csr_set_key(&ctx, &key); mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256); - mbedtls_x509write_csr_set_extension(&ctx, - "\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04", - 0xB, - 0, - aaguid, - sizeof(aaguid)); + mbedtls_x509write_csr_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04", 0xB, 0, aaguid, sizeof(aaguid)); ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_gen, NULL); mbedtls_ecdsa_free(&ekey); if (ret <= 0) { diff --git a/src/fido/ctap.h b/src/fido/ctap.h index 79d00f6..1a82ade 100644 --- a/src/fido/ctap.h +++ b/src/fido/ctap.h @@ -114,6 +114,8 @@ typedef struct { #define CTAP_CONFIG_AUT_ENABLE 0x03e43f56b34285e2 #define CTAP_CONFIG_AUT_DISABLE 0x1831a40f04a25ed9 +#define CTAP_CONFIG_PHY_VIDPID 0x6fcb19b0cbe3acfa +#define CTAP_CONFIG_PHY_OPTS 0x969f3b09eceb805f #define CTAP_VENDOR_CBOR (CTAPHID_VENDOR_FIRST + 1)