diff --git a/src/fido/cmd_authenticate.c b/src/fido/cmd_authenticate.c index 884f43f..dd6fd87 100644 --- a/src/fido/cmd_authenticate.c +++ b/src/fido/cmd_authenticate.c @@ -52,24 +52,7 @@ int cmd_authenticate() { return SW_EXEC_ERROR(); } if (P1(apdu) == CTAP_AUTH_CHECK_ONLY) { - for (int i = 0; i < KEY_PATH_ENTRIES; i++) { - uint32_t k = *(uint32_t *)&req->keyHandle[i*sizeof(uint32_t)]; - if (!(k & 0x80000000)) { - mbedtls_ecdsa_free(&key); - return SW_WRONG_DATA(); - } - } - uint8_t hmac[32], d[32]; - ret = mbedtls_ecp_write_key(&key, d, sizeof(d)); - mbedtls_ecdsa_free(&key); - if (ret != 0) - return SW_WRONG_DATA(); - uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN]; - memcpy(key_base, req->appId, CTAP_APPID_SIZE); - memcpy(key_base + CTAP_APPID_SIZE, req->keyHandle, KEY_PATH_LEN); - ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), d, 32, key_base, sizeof(key_base), hmac); - mbedtls_platform_zeroize(d, sizeof(d)); - if (memcmp(req->keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac)) != 0) + if (verify_key(req->appId, req->keyHandle, &key) != 0) return SW_WRONG_DATA(); return SW_CONDITIONS_NOT_SATISFIED(); } diff --git a/src/fido/credential.c b/src/fido/credential.c index f8afd12..7594267 100644 --- a/src/fido/credential.c +++ b/src/fido/credential.c @@ -104,52 +104,56 @@ int credential_create(CborCharString *rpId, CborByteString *userId, CborCharStri int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, Credential *cred) { int ret = 0; + CborError error; uint8_t *copy_cred_id = (uint8_t *)calloc(1, cred_id_len); memcpy(copy_cred_id, cred_id, cred_id_len); ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash); - if (ret != 0) - return ret; - CborParser parser; - 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; - CBOR_FIELD_GET_UINT(val_u, 1); - if (val_u == 0x01) { - CBOR_FIELD_GET_TEXT(cred->rpId, 1); - } - else if (val_u == 0x03) { - CBOR_FIELD_GET_BYTES(cred->userId, 1); - } - else if (val_u == 0x06) { - CBOR_FIELD_GET_UINT(cred->creation, 1); - } - else if (val_u == 0x07) { - cred->extensions.present = true; - CBOR_PARSE_MAP_START(_f1, 2) - { - CBOR_FIELD_GET_KEY_TEXT(2); - CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "hmac-secret", cred->extensions.hmac_secret); - CBOR_FIELD_KEY_TEXT_VAL_UINT(2, "credProtect", cred->extensions.credProtect); - CBOR_ADVANCE(2); + if (ret != 0) { // U2F? + if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) + CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL); + } + else { + CborParser parser; + CborValue map; + 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; + CBOR_FIELD_GET_UINT(val_u, 1); + if (val_u == 0x01) { + CBOR_FIELD_GET_TEXT(cred->rpId, 1); + } + else if (val_u == 0x03) { + CBOR_FIELD_GET_BYTES(cred->userId, 1); + } + else if (val_u == 0x06) { + CBOR_FIELD_GET_UINT(cred->creation, 1); + } + else if (val_u == 0x07) { + cred->extensions.present = true; + CBOR_PARSE_MAP_START(_f1, 2) + { + CBOR_FIELD_GET_KEY_TEXT(2); + CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "hmac-secret", cred->extensions.hmac_secret); + CBOR_FIELD_KEY_TEXT_VAL_UINT(2, "credProtect", cred->extensions.credProtect); + CBOR_ADVANCE(2); + } + CBOR_PARSE_MAP_END(_f1, 2); + } + else if (val_u == 0x08) { + CBOR_FIELD_GET_BOOL(cred->use_sign_count, 1); + } + else if (val_u == 0x09) { + CBOR_FIELD_GET_INT(cred->alg, 1); + } + else if (val_u == 0x0A) { + CBOR_FIELD_GET_INT(cred->curve, 1); + } + else { + CBOR_ADVANCE(1); } - CBOR_PARSE_MAP_END(_f1, 2); - } - else if (val_u == 0x08) { - CBOR_FIELD_GET_BOOL(cred->use_sign_count, 1); - } - else if (val_u == 0x09) { - CBOR_FIELD_GET_INT(cred->alg, 1); - } - else if (val_u == 0x0A) { - CBOR_FIELD_GET_INT(cred->curve, 1); - } - else { - CBOR_ADVANCE(1); } } cred->id.present = true; diff --git a/src/fido/fido.c b/src/fido/fido.c index 132b832..ca662fb 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -124,6 +124,36 @@ int load_keydev(uint8_t *key) { return CCID_OK; } +int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) { + for (int i = 0; i < KEY_PATH_ENTRIES; i++) { + uint32_t k = *(uint32_t *)&keyHandle[i*sizeof(uint32_t)]; + if (!(k & 0x80000000)) { + return -1; + } + } + mbedtls_ecdsa_context ctx; + if (key == NULL) { + mbedtls_ecdsa_init(&ctx); + key = &ctx; + if (derive_key(appId, false, (uint8_t *)keyHandle, MBEDTLS_ECP_DP_SECP256R1, &ctx) != 0) { + mbedtls_ecdsa_free(&ctx); + return -3; + } + } + uint8_t hmac[32], d[32]; + int ret = mbedtls_ecp_write_key(key, d, sizeof(d)); + if (key == NULL) + mbedtls_ecdsa_free(&ctx); + if (ret != 0) + return -2; + uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN]; + memcpy(key_base, appId, CTAP_APPID_SIZE); + memcpy(key_base + CTAP_APPID_SIZE, keyHandle, KEY_PATH_LEN); + ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), d, 32, key_base, sizeof(key_base), hmac); + mbedtls_platform_zeroize(d, sizeof(d)); + 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) { uint8_t outk[64] = {0}; int r = 0; @@ -131,8 +161,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur if ((r = load_keydev(outk)) != CCID_OK) return r; const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); - for (int i = 0; i < KEY_PATH_ENTRIES; i++) - { + for (int i = 0; i < KEY_PATH_ENTRIES; i++) { if (new_key == true) { uint32_t val = 0; random_gen(NULL, (uint8_t *) &val, sizeof(val)); @@ -140,8 +169,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur memcpy(&key_handle[i*sizeof(uint32_t)], &val, sizeof(uint32_t)); } r = mbedtls_hkdf(md_info, &key_handle[i * sizeof(uint32_t)], sizeof(uint32_t), outk, 32, outk + 32, 32, outk, sizeof(outk)); - if (r != 0) - { + if (r != 0) { mbedtls_platform_zeroize(outk, sizeof(outk)); return r; } diff --git a/src/fido/fido.h b/src/fido/fido.h index d069179..41209e4 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -32,6 +32,7 @@ extern int scan_files(bool); extern int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int, mbedtls_ecdsa_context *key); +extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *); extern bool wait_button_pressed(); extern CTAPHID_FRAME *ctap_req, *ctap_resp; extern void init_fido(bool);