diff --git a/src/fido/cbor_client_pin.c b/src/fido/cbor_client_pin.c index fe2014d..125ad35 100644 --- a/src/fido/cbor_client_pin.c +++ b/src/fido/cbor_client_pin.c @@ -59,7 +59,7 @@ void clearUserVerifiedFlag() { void clearPinUvAuthTokenPermissionsExceptLbw() { if (paut.in_use == true) - paut.permissions = FIDO2_PERMISSION_LBW; + paut.permissions = CTAP_PERMISSION_LBW; } void stopUsingPinUvAuthToken() { diff --git a/src/fido/cbor_config.c b/src/fido/cbor_config.c index 30a9080..402a931 100644 --- a/src/fido/cbor_config.c +++ b/src/fido/cbor_config.c @@ -188,6 +188,10 @@ int cbor_config(const uint8_t *data, size_t len) { low_flash_available(); goto err; //No return } + else if (subcommand == 0x01) { + set_opts(get_opts() | FIDO2_OPT_EA); + goto err; + } else CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); diff --git a/src/fido/cbor_get_info.c b/src/fido/cbor_get_info.c index f213d1a..2850681 100644 --- a/src/fido/cbor_get_info.c +++ b/src/fido/cbor_get_info.c @@ -46,7 +46,9 @@ int cbor_get_info() { CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aaguid, sizeof(aaguid))); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); - CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &arrayEncoder, 6)); + CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &arrayEncoder, 7)); + CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "ep")); + CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, get_opts() & FIDO2_OPT_EA)); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "rk")); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true)); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "credMgmt")); diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index 99be982..d1b80aa 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -207,6 +207,9 @@ int cbor_make_credential(const uint8_t *data, size_t len) { CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED); } if (enterpriseAttestation > 0) { + if (!(get_opts() & FIDO2_OPT_EA)) { + CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); + } if (enterpriseAttestation != 1 && enterpriseAttestation != 2) { //9.2.1 CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); } @@ -259,14 +262,6 @@ int cbor_make_credential(const uint8_t *data, size_t len) { CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &options, &extensions, (!ka || ka->use_sign_count == ptrue), alg, curve, cred_id, &cred_id_len)); - mbedtls_ecdsa_context ekey; - mbedtls_ecdsa_init(&ekey); - int ret = fido_load_key(curve, cred_id, &ekey); - if (ret != 0) { - mbedtls_ecdsa_free(&ekey); - CBOR_ERROR(CTAP1_ERR_OTHER); - } - if (getUserVerifiedFlagValue()) flags |= FIDO2_AUT_FLAG_UV; size_t ext_len = 0; @@ -315,9 +310,18 @@ int cbor_make_credential(const uint8_t *data, size_t len) { flags |= FIDO2_AUT_FLAG_ED; } uint8_t pkey[66]; - const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id); - if (cinfo == NULL) + mbedtls_ecdsa_context ekey; + mbedtls_ecdsa_init(&ekey); + int ret = fido_load_key(curve, cred_id, &ekey); + if (ret != 0) { + mbedtls_ecdsa_free(&ekey); CBOR_ERROR(CTAP1_ERR_OTHER); + } + const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id); + if (cinfo == NULL) { + mbedtls_ecdsa_free(&ekey); + CBOR_ERROR(CTAP1_ERR_OTHER); + } size_t olen = 0; uint32_t ctr = get_sign_counter(); uint8_t cbor_buf[1024]; @@ -354,15 +358,17 @@ int cbor_make_credential(const uint8_t *data, size_t len) { memcpy(pa, cred_id, cred_id_len); pa += cred_id_len; memcpy(pa, cbor_buf, rs); pa += rs; memcpy(pa, ext, ext_len); pa += ext_len; - if (pa-aut_data != aut_data_len) + if (pa-aut_data != aut_data_len) { + mbedtls_ecdsa_free(&ekey); CBOR_ERROR(CTAP1_ERR_OTHER); + } memcpy(pa, clientDataHash.data, clientDataHash.len); uint8_t hash[32], sig[MBEDTLS_ECDSA_MAX_LEN]; ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), aut_data, aut_data_len+clientDataHash.len, hash); bool self_attestation = true; - if (ka && ka->use_self_attestation == pfalse) { + if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) { mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_init(&ekey); ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), 32); @@ -372,7 +378,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) { mbedtls_ecdsa_free(&ekey); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); - CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 3)); + CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 4)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed")); @@ -394,6 +400,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) { } CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); + CBOR_CHECK(cbor_encode_boolean(&mapEncoder, enterpriseAttestation == 2)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); diff --git a/src/fido/fido.c b/src/fido/fido.c index e53512b..894c682 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -325,6 +325,19 @@ uint32_t get_sign_counter() { return (*caddr) | (*(caddr + 1) << 8) | (*(caddr + 2) << 16) | (*(caddr + 3) << 24); } +uint8_t get_opts() { + file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF); + if (file_has_data(ef)) + return *file_get_data(ef); + return 0; +} + +void set_opts(uint8_t opts) { + file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF); + flash_write_data_to_file(ef, &opts, sizeof(uint8_t)); + low_flash_available(); +} + typedef struct cmd { uint8_t ins; diff --git a/src/fido/fido.h b/src/fido/fido.h index 0762e0c..c1d54e7 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -63,12 +63,7 @@ extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSec #define FIDO2_AUT_FLAG_AT 0x40 #define FIDO2_AUT_FLAG_ED 0x80 -#define FIDO2_PERMISSION_MC 0x1 -#define FIDO2_PERMISSION_GA 0x2 -#define FIDO2_PERMISSION_CM 0x4 -#define FIDO2_PERMISSION_BE 0x8 -#define FIDO2_PERMISSION_LBW 0x10 -#define FIDO2_PERMISSION_ACFG 0x20 +#define FIDO2_OPT_EA 0x01 // Enterprise Attestation #define MAX_PIN_RETRIES 8 extern bool getUserPresentFlagValue(); @@ -78,6 +73,8 @@ extern void clearUserVerifiedFlag(); extern void clearPinUvAuthTokenPermissionsExceptLbw(); extern void send_keepalive(); extern uint32_t get_sign_counter(); +extern uint8_t get_opts(); +extern void set_opts(uint8_t); #define MAX_CREDENTIAL_COUNT_IN_LIST 16 #define MAX_CRED_ID_LENGTH 1024 #define MAX_RESIDENT_CREDENTIALS 256 diff --git a/src/fido/files.c b/src/fido/files.c index 660c35f..ceb5859 100644 --- a/src/fido/files.c +++ b/src/fido/files.c @@ -27,6 +27,7 @@ file_t file_entries[] = { {.fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // PIN {.fid = EF_AUTHTOKEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // AUTH TOKEN {.fid = EF_MINPINLEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // MIN PIN LENGTH + {.fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // Global options { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end }; diff --git a/src/fido/files.h b/src/fido/files.h index 9182928..7073842 100644 --- a/src/fido/files.h +++ b/src/fido/files.h @@ -24,6 +24,7 @@ #define EF_KEY_DEV_ENC 0xCC01 #define EF_EE_DEV 0xCE00 #define EF_COUNTER 0xC000 +#define EF_OPTS 0xC001 #define EF_PIN 0x1080 #define EF_AUTHTOKEN 0x1090 #define EF_MINPINLEN 0x1100