From 682a443f4e3564e96d0bcd557d5d58da2f2ed27d Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Tue, 24 Mar 2020 15:07:10 -0400 Subject: [PATCH] refactor credMgmt to parse as subCommandParams, and get ready for delete command --- fido2/ctap.c | 52 ++++++++++++++++++++++++++-------------------- fido2/ctap.h | 17 +++++++++++++-- fido2/ctap_parse.c | 35 ++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 32 deletions(-) diff --git a/fido2/ctap.c b/fido2/ctap.c index daf09be..afa2998 100644 --- a/fido2/ctap.c +++ b/fido2/ctap.c @@ -382,6 +382,19 @@ static void ctap_increment_rk_store() STATE.rk_stored++; ctap_flush_state(); } +static void ctap_decrement_rk_store() +{ + STATE.rk_stored--; + ctap_flush_state(); +} + +// Return 1 if rk is valid, 0 if not. +static int ctap_rk_is_valid(CTAP_residentKey * rk) +{ + return (rk->id.count > 0 && rk->id.count != 0xffffffff); +} + + static int is_matching_rk(CTAP_residentKey * rk, CTAP_residentKey * rk2) { @@ -1121,9 +1134,13 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA) crypto_sha256_final(rpIdHash); printf1(TAG_GREEN, "true rpIdHash: "); dump_hex1(TAG_GREEN, rpIdHash, 32); - for(i = 0; i < STATE.rk_stored; i++) + for(i = 0; i < ctap_rk_size(); i++) { ctap_load_rk(i, &rk); + if (! ctap_rk_is_valid(&rk)) { + continue; + } + printf1(TAG_GREEN, "rpIdHash%d: ", i); dump_hex1(TAG_GREEN, rk.id.rpIdHash, 32); int protection_status = @@ -1454,31 +1471,17 @@ uint8_t ctap_cred_rk(CborEncoder * encoder, int rk_ind, int rk_count) uint8_t ctap_cred_mgmt_pinauth(CTAP_credMgmt *CM) { - uint8_t ret = 0; - if (CM->cmd != CM_cmdMetadata && CM->cmd != CM_cmdRPBegin && CM->cmd != CM_cmdRKBegin) + if (CM->cmd != CM_cmdMetadata && + CM->cmd != CM_cmdRPBegin && + CM->cmd != CM_cmdRKBegin && + CM->cmd != CM_cmdRKDelete) { // pinAuth is not required for other commands return 0; } - if (CM->pinProtocol != 1) - { - return CTAP1_ERR_OTHER; - } - if (CM->cmd == CM_cmdMetadata || CM->cmd == CM_cmdRPBegin) - { - uint8_t cmd = (uint8_t) CM->cmd; - ret = verify_pin_auth_ex(CM->pinAuth, &cmd, 1); - } - else if (CM->cmd == CM_cmdRKBegin) - { - uint8_t params[5 + sizeof(CM->rpIdHash)] = {CM->cmd, 0xa1, 0x01, 0x58, 0x20}; - if (CM->pinProtocol != 1) - { - return CTAP1_ERR_OTHER; - } - memcpy(¶ms[5], CM->rpIdHash, sizeof(CM->rpIdHash)); - ret = verify_pin_auth_ex(CM->pinAuth, params, sizeof(params)); - } + + int8_t ret = verify_pin_auth_ex(CM->pinAuth, (uint8_t*)&CM->hashed, CM->subCommandParamsCborSize + 1); + if (ret == CTAP2_ERR_PIN_AUTH_INVALID) { ctap_decrement_pin_attempts(); @@ -1492,6 +1495,7 @@ uint8_t ctap_cred_mgmt_pinauth(CTAP_credMgmt *CM) { ctap_reset_pin_attempts(); } + return ret; } @@ -1539,7 +1543,7 @@ uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length) rk_auth = true; rp_auth = false; // store the specified hash, we will need it for CM_cmdRKNext - memcpy(rpIdHash, CM.rpIdHash, 32); + memcpy(rpIdHash, CM.subCommandParams.rpIdHash, 32); // count how many RKs have this hash for (i = 0; i < STATE.rk_stored; i++) { @@ -1601,6 +1605,8 @@ uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length) check_ret(ret); curr_rk_ind++; break; + case CM_cmdRKDelete: + break; default: printf2(TAG_ERR, "error, invalid credMgmt cmd: 0x%02x\n", CM.cmd); return CTAP1_ERR_INVALID_COMMAND; diff --git a/fido2/ctap.h b/fido2/ctap.h index 10bb6c5..9b67691 100644 --- a/fido2/ctap.h +++ b/fido2/ctap.h @@ -44,7 +44,10 @@ #define CM_cmdRPNext 0x03 #define CM_cmdRKBegin 0x04 #define CM_cmdRKNext 0x05 -#define CM_rpIdHash 0x02 + #define CM_cmdRKDelete 0x06 +#define CM_subCommandParams 0x02 + #define CM_subCommandRpId 0x01 + #define CM_subCommandCred 0x02 #define CM_pinProtocol 0x03 #define CM_pinAuth 0x04 @@ -311,7 +314,17 @@ typedef struct typedef struct { int cmd; - uint8_t rpIdHash[32]; + struct { + uint8_t rpIdHash[32]; + CTAP_credentialDescriptor credentialDescriptor; + } subCommandParams; + + struct { + uint8_t cmd; + uint8_t subCommandParamsCborCopy[sizeof(CTAP_credentialDescriptor) + 16]; + } hashed; + uint32_t subCommandParamsCborSize; + uint8_t pinAuth[16]; uint8_t pinAuthPresent; int pinProtocol; diff --git a/fido2/ctap_parse.c b/fido2/ctap_parse.c index d49ae1d..27e596a 100644 --- a/fido2/ctap_parse.c +++ b/fido2/ctap_parse.c @@ -1007,7 +1007,7 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it) return 0; } -static uint8_t parse_rpid_hash(CborValue * val, CTAP_credMgmt * CM) +static uint8_t parse_cred_mgmt_subcommandparams(CborValue * val, CTAP_credMgmt * CM) { size_t map_length; int key; @@ -1022,8 +1022,12 @@ static uint8_t parse_rpid_hash(CborValue * val, CTAP_credMgmt * CM) return CTAP2_ERR_INVALID_CBOR_TYPE; } + ret = cbor_value_enter_container(val,&map); check_ret(ret); + + const uint8_t * start_byte = cbor_value_get_next_byte(&map) - 1; + ret = cbor_value_get_map_length(val, &map_length); check_ret(ret); @@ -1040,8 +1044,8 @@ static uint8_t parse_rpid_hash(CborValue * val, CTAP_credMgmt * CM) check_ret(ret); switch(key) { - case 1: - ret = cbor_value_copy_byte_string(&map, CM->rpIdHash, &sz, NULL); + case CM_subCommandRpId: + ret = cbor_value_copy_byte_string(&map, CM->subCommandParams.rpIdHash, &sz, NULL); if (ret == CborErrorOutOfMemory) { printf2(TAG_ERR,"Error, map key is too large\n"); @@ -1049,10 +1053,26 @@ static uint8_t parse_rpid_hash(CborValue * val, CTAP_credMgmt * CM) } check_ret(ret); break; + case CM_subCommandCred: + ret = parse_credential_descriptor(&map, &CM->subCommandParams.credentialDescriptor); + check_ret(ret);; + break; } ret = cbor_value_advance(&map); check_ret(ret); } + + const uint8_t * end_byte = cbor_value_get_next_byte(&map); + + uint32_t length = (uint32_t)end_byte - (uint32_t)start_byte; + if (length > sizeof(CM->hashed.subCommandParamsCborCopy)) + { + return CTAP2_ERR_LIMIT_EXCEEDED; + } + // Copy the details that were hashed so they can be verified later. + memmove(CM->hashed.subCommandParamsCborCopy, start_byte, length); + CM->subCommandParamsCborSize = length; + return 0; } @@ -1076,6 +1096,7 @@ uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length) return CTAP2_ERR_INVALID_CBOR_TYPE; } + ret = cbor_value_enter_container(&it,&map); check_ret(ret); @@ -1106,17 +1127,17 @@ uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length) { ret = cbor_value_get_int_checked(&map, &CM->cmd); check_ret(ret); + CM->hashed.cmd = CM->cmd; } else { return CTAP2_ERR_INVALID_CBOR_TYPE; } break; - case CM_rpIdHash: - printf1(TAG_CM, "CM_rpIdHash\n"); - ret = parse_rpid_hash(&map, CM); + case CM_subCommandParams: + printf1(TAG_CM, "CM_subCommandParams\n"); + ret = parse_cred_mgmt_subcommandparams(&map, CM); check_ret(ret); - dump_hex1(TAG_CM, CM->rpIdHash, 32); break; case CM_pinProtocol: printf1(TAG_CM, "CM_pinProtocol\n");