From 99fc76a385d35b22bad29ecf286cfb29a8d21f61 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 21 Sep 2022 14:29:28 +0200 Subject: [PATCH] Finalizing get assertion. Signed-off-by: Pol Henarejos --- src/fido/cbor.c | 2 + src/fido/cbor_get_assertion.c | 173 ++++++++++++++++++++++++++++++-- src/fido/cbor_make_credential.c | 25 +---- src/fido/credential.c | 8 ++ src/fido/credential.h | 3 + src/fido/ctap2_cbor.h | 1 + src/fido/fido.c | 32 +++++- src/fido/fido.h | 2 + 8 files changed, 213 insertions(+), 33 deletions(-) diff --git a/src/fido/cbor.c b/src/fido/cbor.c index dc2a26e..e6fc351 100644 --- a/src/fido/cbor.c +++ b/src/fido/cbor.c @@ -44,6 +44,8 @@ int cbor_parse(const uint8_t *data, size_t len) { return cbor_reset(); else if (data[0] == CTAP_CLIENT_PIN) return cbor_client_pin(data + 1, len - 1); + else if (data[0] == CTAP_GET_ASSERTION) + return cbor_get_assertion(data + 1, len - 1); return CTAP2_ERR_INVALID_CBOR; } diff --git a/src/fido/cbor_get_assertion.c b/src/fido/cbor_get_assertion.c index f638e5c..18297f0 100644 --- a/src/fido/cbor_get_assertion.c +++ b/src/fido/cbor_get_assertion.c @@ -27,14 +27,26 @@ #include "apdu.h" #include "cbor_make_credential.h" #include "credential.h" +#include -int cbor_client_pin(const uint8_t *data, size_t len) { +CborCharString rpIdx = {0}; +CborByteString pinUvAuthParamx = {0}, clientDataHashx = {0}; +bool residentx = false; +Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; +uint64_t pinUvAuthProtocolx = 0; +CredExtensions extensionx = {0}; +CredOptions optionsx = {0}; +uint8_t flagsx = 0; +uint8_t credentialCounter = 1; +uint8_t numberOfCredentialsx = 0; + +int cbor_get_assertion(const uint8_t *data, size_t len) { size_t resp_size = 0; uint64_t pinUvAuthProtocol = 0; CredOptions options = {0}; CredExtensions extensions = {0}; CborParser parser; - CborEncoder encoder, mapEncoder; + CborEncoder encoder, mapEncoder, mapEncoder2; CborValue map; CborError error = CborNoError; CborByteString pinUvAuthParam = {0}, clientDataHash = {0}; @@ -42,6 +54,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) { PublicKeyCredentialDescriptor allowList[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; Credential creds[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; size_t allowList_len = 0, creds_len = 0; + uint8_t *aut_data = NULL; + bool asserted = false; CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); uint64_t val_c = 1; @@ -173,7 +187,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) { int ret = credential_load(file_get_data(ef) + 32, file_get_size(ef) - 32, rp_id_hash, &creds[creds_len]); if (ret != 0) credential_free(&creds[creds_len]); - creds_len++; + else + creds_len++; } resident = true; } @@ -207,17 +222,157 @@ int cbor_client_pin(const uint8_t *data, size_t len) { clearUserVerifiedFlag(); clearPinUvAuthTokenPermissionsExceptLbw(); } - if (resident) { - + if (numberOfCredentials == 0) + CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS); + Credential *selcred = NULL; + if (resident == false) { + selcred = &creds[0]; } else { - + if (numberOfCredentials == 1) + selcred = &creds[0]; + else { + asserted = true; + rpIdx = rpId; + pinUvAuthParamx = pinUvAuthParamx; + clientDataHashx = clientDataHash; + residentx = resident; + for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) + credsx[i] = creds[i]; + numberOfCredentialsx = numberOfCredentials; + pinUvAuthProtocolx = pinUvAuthProtocol; + extensionx = extensions; + optionsx = options; + flagsx = flags; + } } + uint8_t cred_id[MAX_CRED_ID_LENGTH]; + size_t cred_id_len = 0; + if (credential_create_cred(selcred, cred_id, &cred_id_len) != 0) + CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE); + + mbedtls_ecdsa_context ekey; + mbedtls_ecdsa_init(&ekey); + int ret = fido_load_key(selcred->curve, cred_id, &ekey); + if (ret != 0) { + mbedtls_ecdsa_free(&ekey); + CBOR_ERROR(CTAP1_ERR_OTHER); + } + + size_t ext_len = 0; + uint8_t ext [512]; + if (extensions.present == true) { + cbor_encoder_init(&encoder, ext, sizeof(ext), 0); + int l = 0; + if (extensions.hmac_secret != NULL) + l++; + if (extensions.credProtect != 0) + l++; + CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); + if (extensions.credProtect != 0) { + CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect")); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, extensions.credProtect)); + } + if (extensions.hmac_secret != NULL) { + + CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret")); + CBOR_CHECK(cbor_encode_boolean(&mapEncoder, *extensions.hmac_secret)); + } + + CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); + ext_len = cbor_encoder_get_buffer_size(&encoder, ext); + 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) + CBOR_ERROR(CTAP1_ERR_OTHER); + size_t olen = 0, pkey_len = ceil((float)cinfo->bit_size/8); + uint32_t ctr = *(uint32_t *)file_get_data(ef_counter); + uint8_t cbor_buf[1024]; + cbor_encoder_init(&encoder, cbor_buf, sizeof(cbor_buf), 0); + CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 5)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 1)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 2)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 3)); + CBOR_CHECK(cbor_encode_negative_int(&mapEncoder, -selcred->alg)); + CBOR_CHECK(cbor_encode_negative_int(&mapEncoder, 1)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, selcred->curve)); + CBOR_CHECK(cbor_encode_negative_int(&mapEncoder, 2)); + mbedtls_mpi_write_binary(&ekey.Q.X, pkey, pkey_len); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, pkey, pkey_len)); + CBOR_CHECK(cbor_encode_negative_int(&mapEncoder, 3)); + mbedtls_mpi_write_binary(&ekey.Q.Y, pkey, pkey_len); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, pkey, pkey_len)); + + CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); + size_t rs = cbor_encoder_get_buffer_size(&encoder, cbor_buf); + + size_t aut_data_len = 32 + 1 + 4 + (16 + 2 + cred_id_len + rs) + ext_len; + aut_data = (uint8_t *)calloc(1, aut_data_len + clientDataHash.len); + uint8_t *pa = aut_data; + memcpy(pa, rp_id_hash, 32); pa += 32; + *pa++ = flags; + *pa++ = ctr >> 24; + *pa++ = ctr >> 16; + *pa++ = ctr >> 8; + *pa++ = ctr & 0xff; + memcpy(pa, aaguid, 16); pa += 16; + *pa++ = cred_id_len >> 8; + *pa++ = cred_id_len & 0xff; + 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) + 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); + ret = mbedtls_ecdsa_write_signature(&ekey, MBEDTLS_MD_SHA256, hash, 32, sig, sizeof(sig), &olen, random_gen, NULL); + mbedtls_ecdsa_free(&ekey); + + uint8_t lfields = 3; + if (resident) + lfields++; + if (numberOfCredentials > 1) + lfields++; + cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); + CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, lfields)); + + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); + CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 2)); + CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "type")); + CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "public-key")); + CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, cred_id, cred_id_len)); + CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); + + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02)); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aut_data, aut_data_len)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, sig, olen)); + + if (resident) { + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); + CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 1)); + CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); + CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->userId.data, selcred->userId.len)); + CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); + } + if (numberOfCredentials > 1) { + CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05)); + CBOR_CHECK(cbor_encode_uint(&mapEncoder, numberOfCredentials)); + } + CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); + res_APDU_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); err: + if (asserted == false) { CBOR_FREE_BYTE_STRING(clientDataHash); - CBOR_FREE_BYTE_STRING(pinUvAuthParam); - CBOR_FREE_BYTE_STRING(rpId); + CBOR_FREE_BYTE_STRING(pinUvAuthParam); + CBOR_FREE_BYTE_STRING(rpId); + } for (int m = 0; m < allowList_len; m++) { CBOR_FREE_BYTE_STRING(allowList[m].type); @@ -226,6 +381,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) { CBOR_FREE_BYTE_STRING(allowList[m].transports[n]); } } + if (aut_data) + free(aut_data); if (error != CborNoError) { if (error == CborErrorImproperValue) return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index ec4f3aa..285fe5b 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -244,30 +244,9 @@ int cbor_make_credential(const uint8_t *data, size_t len) { CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &extensions, (!ka || ka->use_sign_count == ptrue), alg, curve, cred_id, &cred_id_len)); - mbedtls_ecp_group_id mbedtls_curve = MBEDTLS_ECP_DP_SECP256R1; - if (curve == FIDO2_CURVE_P256) - mbedtls_curve = MBEDTLS_ECP_DP_SECP256R1; - else if (curve == FIDO2_CURVE_P384) - mbedtls_curve = MBEDTLS_ECP_DP_SECP384R1; - else if (curve == FIDO2_CURVE_P521) - mbedtls_curve = MBEDTLS_ECP_DP_SECP521R1; - else if (curve == FIDO2_CURVE_P256K1) - mbedtls_curve = MBEDTLS_ECP_DP_SECP256K1; - else if (curve == FIDO2_CURVE_X25519) - mbedtls_curve = MBEDTLS_ECP_DP_CURVE25519; - else if (curve == FIDO2_CURVE_X448) - mbedtls_curve = MBEDTLS_ECP_DP_CURVE448; - else - CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_ALGORITHM); - mbedtls_ecdsa_context ekey; mbedtls_ecdsa_init(&ekey); - uint8_t key_path[KEY_PATH_LEN]; - memcpy(key_path, cred_id, KEY_PATH_LEN); - *(uint32_t *)key_path = 0x80000000 | 10022; - for (int i = 1; i < KEY_PATH_ENTRIES; i++) - *(uint32_t *)(key_path+i*sizeof(uint32_t)) |= 0x80000000; - int ret = derive_key(NULL, false, key_path, mbedtls_curve, &ekey); + int ret = fido_load_key(curve, cred_id, &ekey); if (ret != 0) { mbedtls_ecdsa_free(&ekey); CBOR_ERROR(CTAP1_ERR_OTHER); @@ -301,7 +280,7 @@ 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(mbedtls_curve); + const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id); if (cinfo == NULL) CBOR_ERROR(CTAP1_ERR_OTHER); size_t olen = 0, pkey_len = ceil((float)cinfo->bit_size/8); diff --git a/src/fido/credential.c b/src/fido/credential.c index 9b8ef6a..49615d1 100644 --- a/src/fido/credential.c +++ b/src/fido/credential.c @@ -38,6 +38,10 @@ int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id return mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - (4 + 12 + 16), iv, rp_id_hash, 32, tag, cipher, cipher); } +int credential_create_cred(Credential *cred, uint8_t *cred_id, size_t *cred_id_len) { + return credential_create(&cred->rpId, &cred->userId, &cred->userName, &cred->userDisplayName, &cred->extensions, cred->use_sign_count, cred->alg, cred->curve, cred_id, cred_id_len); +} + int credential_create(CborCharString *rpId, CborByteString *userId, CborCharString *userName, CborCharString *userDisplayName, CredExtensions *extensions, bool use_sign_count, int alg, int curve, uint8_t *cred_id, size_t *cred_id_len) { CborEncoder encoder, mapEncoder, mapEncoder2; CborError error = CborNoError; @@ -108,6 +112,8 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r CborValue map; CborError error; memset(cred, 0, sizeof(Credential)); + cred->curve = FIDO2_CURVE_P256; + cred->alg = FIDO2_ALG_ES256; CBOR_CHECK(cbor_parser_init(copy_cred_id + 4 + 12, cred_id_len - (4 + 12 + 16), 0, &parser, &map)); CBOR_PARSE_MAP_START(map, 1) { uint64_t val_u = 0; @@ -160,6 +166,8 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r void credential_free(Credential *cred) { CBOR_FREE_BYTE_STRING(cred->rpId); CBOR_FREE_BYTE_STRING(cred->userId); + CBOR_FREE_BYTE_STRING(cred->userName); + CBOR_FREE_BYTE_STRING(cred->userDisplayName); cred->present = false; cred->extensions.present = false; } diff --git a/src/fido/credential.h b/src/fido/credential.h index 8ac53ed..1004e03 100644 --- a/src/fido/credential.h +++ b/src/fido/credential.h @@ -37,6 +37,8 @@ typedef struct Credential { CborCharString rpId; CborByteString userId; + CborCharString userName; + CborCharString userDisplayName; uint64_t creation; CredExtensions extensions; const bool *use_sign_count; @@ -54,5 +56,6 @@ extern int credential_create(CborCharString *rpId, CborByteString *userId, CborC extern void credential_free(Credential *cred); extern int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash); extern int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, Credential *cred); +extern int credential_create_cred(Credential *cred, uint8_t *cred_id, size_t *cred_id_len); #endif // _CREDENTIAL_H_ diff --git a/src/fido/ctap2_cbor.h b/src/fido/ctap2_cbor.h index 78c2f17..19559e0 100644 --- a/src/fido/ctap2_cbor.h +++ b/src/fido/ctap2_cbor.h @@ -30,6 +30,7 @@ extern int cbor_reset(); extern int cbor_get_info(); extern int cbor_make_credential(const uint8_t *data, size_t len); extern int cbor_client_pin(const uint8_t *data, size_t len); +extern int cbor_get_assertion(const uint8_t *data, size_t len); extern const uint8_t aaguid[16]; extern const bool _btrue, _bfalse; diff --git a/src/fido/fido.c b/src/fido/fido.c index e762afc..e9b547c 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -62,6 +62,34 @@ int fido_unload() { return CCID_OK; } +mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) { + if (curve == FIDO2_CURVE_P256) + return MBEDTLS_ECP_DP_SECP256R1; + else if (curve == FIDO2_CURVE_P384) + return MBEDTLS_ECP_DP_SECP384R1; + else if (curve == FIDO2_CURVE_P521) + return MBEDTLS_ECP_DP_SECP521R1; + else if (curve == FIDO2_CURVE_P256K1) + return MBEDTLS_ECP_DP_SECP256K1; + else if (curve == FIDO2_CURVE_X25519) + return MBEDTLS_ECP_DP_CURVE25519; + else if (curve == FIDO2_CURVE_X448) + return MBEDTLS_ECP_DP_CURVE448; + return MBEDTLS_ECP_DP_NONE; +} + +int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) { + mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve); + if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) + return CTAP2_ERR_UNSUPPORTED_ALGORITHM; + uint8_t key_path[KEY_PATH_LEN]; + memcpy(key_path, cred_id, KEY_PATH_LEN); + *(uint32_t *)key_path = 0x80000000 | 10022; + for (int i = 1; i < KEY_PATH_ENTRIES; i++) + *(uint32_t *)(key_path+i*sizeof(uint32_t)) |= 0x80000000; + return derive_key(NULL, false, key_path, mbedtls_curve, key); +} + int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffer_size) { mbedtls_x509write_cert ctx; mbedtls_x509write_crt_init(&ctx); @@ -107,7 +135,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur { if (new_key == true) { uint32_t val = 0; - random_gen_core0(NULL, (uint8_t *) &val, sizeof(val)); + random_gen(NULL, (uint8_t *) &val, sizeof(val)); val |= 0x80000000; memcpy(&key_handle[i*sizeof(uint32_t)], &val, sizeof(uint32_t)); } @@ -137,7 +165,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur mbedtls_platform_zeroize(outk, sizeof(outk)); if (r != 0) return r; - return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen_core0, NULL); + return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL); } mbedtls_platform_zeroize(outk, sizeof(outk)); return r; diff --git a/src/fido/fido.h b/src/fido/fido.h index eaf88b4..7328c1b 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -35,6 +35,8 @@ extern int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, extern bool wait_button_pressed(); extern CTAPHID_FRAME *ctap_req, *ctap_resp; extern void init_fido(); +extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); +extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key); #define FIDO2_ALG_ES256 -7 //ECDSA-SHA256 P256 #define FIDO2_ALG_EDDSA -8 //EdDSA