diff --git a/ctap.c b/ctap.c index 0493050..13793e3 100644 --- a/ctap.c +++ b/ctap.c @@ -344,6 +344,7 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au // @return length of der signature int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHash, uint8_t * hashbuf, uint8_t * sigbuf, uint8_t * sigder) { + int i; // calculate attestation sig crypto_sha256_init(); crypto_sha256_update(data, datalen); @@ -351,27 +352,38 @@ int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHa crypto_sha256_final(hashbuf); printf1(TAG_GREEN, "sha256: "); dump_hex1(TAG_DUMP,hashbuf,32); - crypto_ecc256_sign(hashbuf, 32, sigbuf); + // Need to caress into dumb der format .. - uint8_t pad_s = (sigbuf[32] & 0x80) == 0x80; - uint8_t pad_r = (sigbuf[0] & 0x80) == 0x80; + int8_t pad_s = ((sigbuf[32 + lead_s] & 0x80) == 0x80); // Is MSBit a 1? + int8_t pad_r = ((sigbuf[0 + lead_r] & 0x80) == 0x80); + + int8_t lead_s = 0; // leading zeros + int8_t lead_r = 0; + for (i=0; i < 32; i++) + if (sigbuf[i] == 0) lead_r++; + else break; + + for (i=0; i < 32; i++) + if (sigbuf[i+32] == 0) lead_s++; + else break; + sigder[0] = 0x30; - sigder[1] = 0x44 + pad_s + pad_r; + sigder[1] = 0x44 + pad_s + pad_r - lead_s - lead_r; sigder[2] = 0x02; sigder[3 + pad_r] = 0; - sigder[3] = 0x20 + pad_r; - memmove(sigder + 4 + pad_r, sigbuf, 32); + sigder[3] = 0x20 + pad_r - lead_r; + memmove(sigder + 4 + pad_r, sigbuf + lead_r, 32); - sigder[4 + 32 + pad_r] = 0x02; - sigder[5 + 32 + pad_r + pad_s] = 0; - sigder[5 + 32 + pad_r] = 0x20 + pad_s; - memmove(sigder + 6 + 32 + pad_r + pad_s, sigbuf + 32, 32); + sigder[4 + 32 + pad_r - lead_r] = 0x02; + sigder[5 + 32 + pad_r + pad_s - lead_r] = 0; + sigder[5 + 32 + pad_r - lead_r] = 0x20 + pad_s - lead_s; + memmove(sigder + 6 + 32 + pad_r + pad_s - lead_r, sigbuf + 32 + lead_s, 32); // - return 0x46 + pad_s + pad_r; + return 0x46 + pad_s + pad_r - lead_r - lead_s; } uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len) @@ -415,12 +427,29 @@ uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len) check_ret(ret); } +// Return 1 if credential belongs to this token +int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * desc) +{ + uint8_t tag[16]; + if (desc->type != PUB_KEY_CRED_PUB_KEY) + { + printf1(TAG_GA,"unsupported credential type: %d\n", desc->type); + return 0; + } + + make_auth_tag(rp, &desc->credential.fields.user, desc->credential.fields.count, tag); + + return (memcmp(desc->credential.fields.tag, tag, CREDENTIAL_TAG_SIZE) == 0); +} + + uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int length) { CTAP_makeCredential MC; - int ret; + int ret, i; uint8_t auth_data_buf[300]; + CTAP_credentialDescriptor * excl_cred = (CTAP_credentialDescriptor *) auth_data_buf; uint8_t * hashbuf = auth_data_buf + 0; uint8_t * sigbuf = auth_data_buf + 32; uint8_t * sigder = auth_data_buf + 32 + 64; @@ -451,6 +480,20 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt } } + for (i = 0; i < MC.excludeListSize; i++) + { + ret = parse_credential_descriptor(&MC.excludeList, excl_cred); + check_retr(ret); + + if (ctap_authenticate_credential(&MC.rp, excl_cred)) + { + return CTAP2_ERR_CREDENTIAL_EXCLUDED; + } + + ret = cbor_value_advance(&MC.excludeList); + check_ret(ret); + } + CborEncoder map; ret = cbor_encoder_create_map(encoder, &map, 3); check_ret(ret); @@ -478,22 +521,6 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt return CTAP1_ERR_SUCCESS; } -// Return 1 if credential belongs to this token -int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * desc) -{ - uint8_t tag[16]; - if (desc->type != PUB_KEY_CRED_PUB_KEY) - { - printf1(TAG_GA,"unsupported credential type: %d\n", desc->type); - return 0; - } - - make_auth_tag(rp, &desc->credential.fields.user, desc->credential.fields.count, tag); - - return (memcmp(desc->credential.fields.tag, tag, CREDENTIAL_TAG_SIZE) == 0); -} - - static int pick_first_authentic_credential(CTAP_getAssertion * GA) { int i; diff --git a/ctap.h b/ctap.h index 1c9482b..485969f 100644 --- a/ctap.h +++ b/ctap.h @@ -1,6 +1,8 @@ #ifndef _CTAP_H #define _CTAP_H +#include "cbor.h" + #define CTAP_MAKE_CREDENTIAL 0x01 #define CTAP_GET_ASSERTION 0x02 #define CTAP_CANCEL 0x03 @@ -162,6 +164,9 @@ typedef struct uint8_t publicKeyCredentialType; int32_t COSEAlgorithmIdentifier; + CborValue excludeList; + int excludeListSize; + uint8_t rk; uint8_t uv; diff --git a/ctap_device.c b/ctap_device.c index aa99ea2..a99fcfe 100644 --- a/ctap_device.c +++ b/ctap_device.c @@ -10,6 +10,7 @@ #include "util.h" #include "usbhid.h" +#include "log.h" void ctaphid_write_block(uint8_t * data) @@ -34,15 +35,16 @@ uint32_t ctap_atomic_count(int sel) { static uint32_t counter1 = 25; static uint32_t counter2 = 25; + /*return 713;*/ if (sel == 0) { + printf1(TAG_RED,"counter1: %d\n", counter1); return counter1++; } else { return counter2++; } - return 44; } int ctap_generate_rng(uint8_t * dst, size_t num) @@ -55,6 +57,9 @@ int ctap_generate_rng(uint8_t * dst, size_t num) } fread(dst, 1, num, urand); fclose(urand); + + /*memset(dst,0xaa,num);*/ + return 1; } diff --git a/ctap_parse.c b/ctap_parse.c index f54afc6..531574e 100644 --- a/ctap_parse.c +++ b/ctap_parse.c @@ -556,6 +556,18 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod break; case MC_excludeList: printf1(TAG_MC,"CTAP_excludeList\n"); + if( cbor_value_get_type(&map) == CborArrayType ) + { + ret = cbor_value_enter_container(&map, &MC->excludeList); + check_ret(ret); + ret = cbor_value_get_int_checked(&map, &MC->excludeListSize); + check_ret(ret); + } + else + { + return CTAP2_ERR_INVALID_CBOR_TYPE; + } + break; case MC_extensions: printf1(TAG_MC,"CTAP_extensions\n"); @@ -604,12 +616,68 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod return 0; } +uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred) +{ + int ret; + size_t buflen; + uint8_t type[12]; + CborValue val; + if (cbor_value_get_type(arr) != CborMapType) + { + printf2(TAG_ERR,"Error, CborMapType expected in allow_list\n"); + return CTAP2_ERR_INVALID_CBOR_TYPE; + } + + ret = cbor_value_map_find_value(arr, "id", &val); + check_ret(ret); + + if (cbor_value_get_type(&val) != CborByteStringType) + { + printf2(TAG_ERR,"Error, No valid ID field (%s)\n", cbor_value_get_type_string(&val)); + return CTAP2_ERR_MISSING_PARAMETER; + } + + buflen = CREDENTIAL_ID_SIZE; + cbor_value_copy_byte_string(&val, cred->credential.id, &buflen, NULL); + if (buflen != CREDENTIAL_ID_SIZE) + { + printf2(TAG_ERR,"Error, credential is incorrect length\n"); + return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail? + } + + ret = cbor_value_map_find_value(arr, "type", &val); + check_ret(ret); + + if (cbor_value_get_type(&val) != CborTextStringType) + { + printf2(TAG_ERR,"Error, No valid type field\n"); + return CTAP2_ERR_MISSING_PARAMETER; + } + + buflen = sizeof(type); + cbor_value_copy_text_string(&val, type, &buflen, NULL); + + if (strcmp(type, "public-key") == 0) + { + cred->type = PUB_KEY_CRED_PUB_KEY; + } + else + { + cred->type = PUB_KEY_CRED_UNKNOWN; + } + + ret = cbor_value_advance(arr); + check_ret(ret); + + return 0; +} + uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it) { - CborValue arr, val; - size_t len,buflen; - uint8_t type[12]; + CborValue arr; + size_t len; int i,ret; + CTAP_credentialDescriptor * cred; if (cbor_value_get_type(it) != CborArrayType) { @@ -634,53 +702,10 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it) } GA->credLen += 1; + cred = &GA->creds[i]; - if (cbor_value_get_type(&arr) != CborMapType) - { - printf2(TAG_ERR,"Error, CborMapType expected in allow_list\n"); - return CTAP2_ERR_INVALID_CBOR_TYPE; - } - - ret = cbor_value_map_find_value(&arr, "id", &val); - check_ret(ret); - - if (cbor_value_get_type(&val) != CborByteStringType) - { - printf2(TAG_ERR,"Error, No valid ID field (%s)\n", cbor_value_get_type_string(&val)); - return CTAP2_ERR_MISSING_PARAMETER; - } - - buflen = CREDENTIAL_ID_SIZE; - cbor_value_copy_byte_string(&val, GA->creds[i].credential.id, &buflen, NULL); - if (buflen != CREDENTIAL_ID_SIZE) - { - printf2(TAG_ERR,"Error, credential is incorrect length\n"); - return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail? - } - - ret = cbor_value_map_find_value(&arr, "type", &val); - check_ret(ret); - - if (cbor_value_get_type(&val) != CborTextStringType) - { - printf2(TAG_ERR,"Error, No valid type field\n"); - return CTAP2_ERR_MISSING_PARAMETER; - } - - buflen = sizeof(type); - cbor_value_copy_text_string(&val, type, &buflen, NULL); - - if (strcmp(type, "public-key") == 0) - { - GA->creds[i].type = PUB_KEY_CRED_PUB_KEY; - } - else - { - GA->creds[i].type = PUB_KEY_CRED_UNKNOWN; - } - - ret = cbor_value_advance(&arr); - check_ret(ret); + ret = parse_credential_descriptor(&arr,cred); + check_retr(ret); } return 0; } diff --git a/ctap_parse.h b/ctap_parse.h index 9e0d566..6fa1583 100644 --- a/ctap_parse.h +++ b/ctap_parse.h @@ -30,6 +30,7 @@ uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length); uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length); uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length); +uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred); #endif