From fc8bc892c1d6733c40053dd8e47658cec478fb6b Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Mon, 12 Nov 2018 11:51:43 -0500 Subject: [PATCH] add initial resident key support --- fido2/ctap.c | 286 ++++++++++++++++++++++++--------- fido2/ctap.h | 26 +-- fido2/ctap_parse.c | 7 +- fido2/device.h | 8 + fido2/log.c | 1 + fido2/log.h | 1 + fido2/storage.h | 2 + targets/stm32l442/src/app.h | 2 +- targets/stm32l442/src/device.c | 88 +++++++++- 9 files changed, 325 insertions(+), 96 deletions(-) diff --git a/fido2/ctap.c b/fido2/ctap.c index 7750dc9..7670ab6 100644 --- a/fido2/ctap.c +++ b/fido2/ctap.c @@ -56,6 +56,7 @@ static struct { uint32_t count; uint32_t index; uint32_t time; + uint8_t user_verified; } getAssertionState; uint8_t verify_pin_auth(uint8_t * pinAuth, uint8_t * clientDataHash) @@ -154,7 +155,7 @@ uint8_t ctap_get_info(CborEncoder * encoder) ret = cbor_encode_text_string(&options, "rk", 2); check_ret(ret); { - ret = cbor_encode_boolean(&options, 0); // State-less device, requires allowList parameter. + ret = cbor_encode_boolean(&options, 1); // Capable of storing keys locally check_ret(ret); } @@ -265,23 +266,32 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input, printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype); return -1; } - ctap_add_cose_key(cose_key, x, y, credtype, algtype); + int ret = ctap_add_cose_key(cose_key, x, y, credtype, algtype); + check_ret(ret); return 0; } -void make_auth_tag(uint8_t * nonce, CTAP_userEntity * user, uint32_t count, uint8_t * tag) +void make_auth_tag(uint8_t * rpIdHash, uint8_t * nonce, uint32_t count, uint8_t * tag) { uint8_t hashbuf[32]; crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, hashbuf); + crypto_sha256_update(rpIdHash, 32); crypto_sha256_update(nonce, CREDENTIAL_NONCE_SIZE); - crypto_sha256_update(user->id, user->id_size); - crypto_sha256_update(user->name, strnlen((const char*)user->name, USER_NAME_LIMIT)); crypto_sha256_update((uint8_t*)&count, 4); crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY,0,hashbuf); memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE); } +void ctap_flush_state(int backup) +{ + authenticator_write_state(&STATE, 0); + if (backup) + { + authenticator_write_state(&STATE, 1); + } +} + static uint32_t auth_data_update_count(CTAP_authDataHeader * authData) { uint32_t count = ctap_atomic_count( 0 ); @@ -292,19 +302,34 @@ static uint32_t auth_data_update_count(CTAP_authDataHeader * authData) } uint8_t * byte = (uint8_t*) &authData->signCount; - *byte++ = (count >> 24) & 0xff; - *byte++ = (count >> 16) & 0xff; - *byte++ = (count >> 8) & 0xff; *byte++ = (count >> 0) & 0xff; + *byte++ = (count >> 8) & 0xff; + *byte++ = (count >> 16) & 0xff; + *byte++ = (count >> 24) & 0xff; return count; } -static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, int len, CTAP_userEntity * user, uint8_t credtype, int32_t algtype, int32_t * sz) +static void ctap_increment_rk_store() +{ + STATE.rk_stored++; + ctap_flush_state(1); +} + +static int is_matching_rk(CTAP_residentKey * rk, CTAP_residentKey * rk2) +{ + return (memcmp(rk->id.rpIdHash, rk2->id.rpIdHash, 32) == 0) && + (memcmp(rk->user.id, rk2->user.id, rk->user.id_size) == 0) && + (rk->user.id_size == rk2->user.id_size); +} + + +static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, int len, CTAP_userEntity * user, uint8_t credtype, int32_t algtype, int32_t * sz, int store) { CborEncoder cose_key; int auth_data_sz, ret; uint32_t count; + CTAP_residentKey rk, rk2; CTAP_authData * authData = (CTAP_authData *)auth_data_buf; uint8_t * cose_key_buf = auth_data_buf + sizeof(CTAP_authData); @@ -347,29 +372,56 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au cbor_encoder_init(&cose_key, cose_key_buf, len - sizeof(CTAP_authData), 0); memmove(authData->attest.aaguid, CTAP_AAGUID, 16); - authData->attest.credLenL = CREDENTIAL_ID_SIZE & 0x00FF; - authData->attest.credLenH = (CREDENTIAL_ID_SIZE & 0xFF00) >> 8; + authData->attest.credLenL = sizeof(CredentialId) & 0x00FF; + authData->attest.credLenH = (sizeof(CredentialId) & 0xFF00) >> 8; -#if CREDENTIAL_ID_SIZE != 168 -#error "need to double check credential ID layout" -#else - memset((uint8_t*)&authData->attest.credential, 0, sizeof(struct Credential)); + memset((uint8_t*)&authData->attest.id, 0, sizeof(CredentialId)); - ctap_generate_rng(authData->attest.credential.nonce, CREDENTIAL_NONCE_SIZE); + ctap_generate_rng(authData->attest.id.nonce, CREDENTIAL_NONCE_SIZE); - memmove(&authData->attest.credential.enc.user, user, sizeof(CTAP_userEntity)); - authData->attest.credential.enc.count = count; + authData->attest.id.count = count; + + memmove(authData->attest.id.rpIdHash, authData->head.rpIdHash, 32); // Make a tag we can later check to make sure this is a token we made - make_auth_tag(authData->attest.credential.nonce, user, count, authData->attest.credential.tag); + make_auth_tag(authData->head.rpIdHash, authData->attest.id.nonce, count, authData->attest.id.tag); - crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); - crypto_aes256_encrypt((uint8_t*)&authData->attest.credential.enc, CREDENTIAL_ENC_SIZE); + // resident key + if (store) + { + memmove(&rk.id, &authData->attest.id, sizeof(CredentialId)); + memmove(&rk.user, user, sizeof(CTAP_userEntity)); - ctap_generate_cose_key(&cose_key, (uint8_t*)&authData->attest.credential, sizeof(struct Credential), credtype, algtype); + int index = STATE.rk_stored; + int i; + for (i = 0; i < index; i++) + { + ctap_load_rk(i, &rk2); + if (is_matching_rk(&rk, &rk2)) + { + ctap_overwrite_rk(i, &rk); + goto done_rk; + } + } + if (index >= ctap_rk_size()) + { + printf2(TAG_ERR, "Out of memory for resident keys\r\n"); + return CTAP2_ERR_KEY_STORE_FULL; + } + ctap_increment_rk_store(); + ctap_store_rk(index, &rk); + dump_hex1(TAG_GREEN, rk.id.rpIdHash, 32); + } +done_rk: + + // DELETE + //crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); + //crypto_aes256_encrypt((uint8_t*)&authData->attest.credential.user, CREDENTIAL_ENC_SIZE); + printf1(TAG_GREEN, "MADE credId: "); dump_hex1(TAG_GREEN, (uint8_t*) &authData->attest.id, sizeof(CredentialId)); + + ctap_generate_cose_key(&cose_key, (uint8_t*)&authData->attest.id, sizeof(CredentialId), credtype, algtype); auth_data_sz = sizeof(CTAP_authData) + cbor_encoder_get_buffer_size(&cose_key, cose_key_buf); -#endif } else @@ -489,9 +541,9 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d { uint8_t tag[16]; - make_auth_tag(desc->credential.nonce, &desc->credential.enc.user, desc->credential.enc.count, tag); + make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag); - return (memcmp(desc->credential.tag, tag, CREDENTIAL_TAG_SIZE) == 0); + return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0); } @@ -536,7 +588,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt return CTAP2_ERR_INVALID_OPTION; } - crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); + // crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); for (i = 0; i < MC.excludeListSize; i++) { ret = parse_credential_descriptor(&MC.excludeList, excl_cred); @@ -546,8 +598,10 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt } check_retr(ret); - crypto_aes256_reset_iv(NULL); - crypto_aes256_decrypt((uint8_t*)& excl_cred->credential.enc, CREDENTIAL_ENC_SIZE); + printf1(TAG_GREEN, "checking credId: "); dump_hex1(TAG_GREEN, (uint8_t*) &excl_cred->credential.id, sizeof(CredentialId)); + // DELETE + // crypto_aes256_reset_iv(NULL); + // crypto_aes256_decrypt((uint8_t*)& excl_cred->credential.enc, CREDENTIAL_ENC_SIZE); if (ctap_authenticate_credential(&MC.rp, excl_cred)) { printf1(TAG_MC, "Cred %d failed!\r\n",i); @@ -564,7 +618,8 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt int32_t auth_data_sz; ret = ctap_make_auth_data(&MC.rp, &map, auth_data_buf, sizeof(auth_data_buf), - &MC.user, MC.publicKeyCredentialType, MC.COSEAlgorithmIdentifier, &auth_data_sz); + &MC.user, MC.publicKeyCredentialType, MC.COSEAlgorithmIdentifier, &auth_data_sz, MC.rk); + check_retr(ret); crypto_ecc256_load_attestation_key(); @@ -620,7 +675,7 @@ static uint8_t ctap_add_credential_descriptor(CborEncoder * map, CTAP_credential ret = cbor_encode_text_string(&desc, "id", 2); check_ret(ret); - ret = cbor_encode_byte_string(&desc, (uint8_t*)&cred->credential, sizeof(struct Credential)); + ret = cbor_encode_byte_string(&desc, (uint8_t*)&cred->credential.id, sizeof(CredentialId)); check_ret(ret); } @@ -636,9 +691,15 @@ uint8_t ctap_add_user_entity(CborEncoder * map, CTAP_userEntity * user) int ret = cbor_encode_int(map, RESP_publicKeyCredentialUserEntity); check_ret(ret); - ret = cbor_encoder_create_map(map, &entity, 2); + int dispname = (user->name[0] != 0); + + if (dispname) + ret = cbor_encoder_create_map(map, &entity, 2); + else + ret = cbor_encoder_create_map(map, &entity, 1); check_ret(ret); + printf1(TAG_GREEN,"id_size: %d\r\n", user->id_size); { ret = cbor_encode_text_string(&entity, "id", 2); check_ret(ret); @@ -647,9 +708,9 @@ uint8_t ctap_add_user_entity(CborEncoder * map, CTAP_userEntity * user) check_ret(ret); } - + if (dispname) { - ret = cbor_encode_text_string(&entity, "displayName", 11); + ret = cbor_encode_text_string(&entity, "name", 4); check_ret(ret); ret = cbor_encode_text_stringz(&entity, (const char *)user->name); @@ -666,7 +727,26 @@ static int cred_cmp_func(const void * _a, const void * _b) { CTAP_credentialDescriptor * a = (CTAP_credentialDescriptor * )_a; CTAP_credentialDescriptor * b = (CTAP_credentialDescriptor * )_b; - return b->credential.enc.count - a->credential.enc.count; + return b->credential.id.count - a->credential.id.count; +} + +static void add_existing_user_info(CTAP_credentialDescriptor * cred) +{ + CTAP_residentKey rk; + int index = STATE.rk_stored; + int i; + for (i = 0; i < index; i++) + { + ctap_load_rk(i, &rk); + if (is_matching_rk(&rk, (CTAP_residentKey *)&cred->credential)) + { + printf1(TAG_GREEN, "found rk match for allowList item (%d)\r\n", i); + memmove(&cred->credential.user, &rk.user, sizeof(CTAP_userEntity)); + return; + } + + } + printf1(TAG_GREEN, "NO rk match for allowList item \r\n"); } // @return the number of valid credentials @@ -675,23 +755,52 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA) { int i; int count = 0; - crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); - + uint8_t rpIdHash[32]; + CTAP_residentKey rk; for (i = 0; i < GA->credLen; i++) { - crypto_aes256_reset_iv(NULL); - crypto_aes256_decrypt((uint8_t*)&GA->creds[i].credential.enc, CREDENTIAL_ENC_SIZE); if (! ctap_authenticate_credential(&GA->rp, &GA->creds[i])) { - printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.enc.count); - GA->creds[i].credential.enc.count = 0; // invalidate + printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.id.count); + GA->creds[i].credential.id.count = 0; // invalidate } else { + // add user info if it exists + add_existing_user_info(&GA->creds[i]); count++; } } + + // No allowList, so use all matching RK's matching rpId + if (!GA->credLen) + { + crypto_sha256_init(); + crypto_sha256_update(GA->rp.id,GA->rp.size); + crypto_sha256_final(rpIdHash); + + printf1(TAG_GREEN, "true rpIdHash: "); dump_hex1(TAG_GREEN, rpIdHash, 32); + for(i = 0; i < STATE.rk_stored; i++) + { + ctap_load_rk(i, &rk); + printf1(TAG_GREEN, "rpIdHash%d: ", i); dump_hex1(TAG_GREEN, rk.id.rpIdHash, 32); + if (memcmp(rk.id.rpIdHash, rpIdHash, 32) == 0) + { + printf1(TAG_GA, "RK %d is a rpId match!\r\n", i); + if (count == ALLOW_LIST_MAX_SIZE-1) + { + printf2(TAG_ERR, "not enough ram allocated for matching RK's (%d)\r\n", count); + break; + } + GA->creds[count].type = PUB_KEY_CRED_PUB_KEY; + memmove(&(GA->creds[count].credential), &rk, sizeof(CTAP_residentKey)); + count++; + } + } + GA->credLen = count; + } + printf1(TAG_GA, "qsort length: %d\n", GA->credLen); qsort(GA->creds, GA->credLen, sizeof(CTAP_credentialDescriptor), cred_cmp_func); return count; @@ -728,24 +837,24 @@ static CTAP_credentialDescriptor * pop_credential() } } -uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cred, uint8_t * auth_data_buf, uint8_t * clientDataHash) +// adds 2 to map, or 3 if add_user is true +uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cred, uint8_t * auth_data_buf, uint8_t * clientDataHash, int add_user) { int ret; uint8_t sigbuf[64]; uint8_t sigder[72]; - //ret = ctap_add_user_entity(map, &cred->credential.enc.user); - //check_retr(ret); - - // Re-encrypt the credential - crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); - crypto_aes256_encrypt((uint8_t*)&cred->credential.enc, CREDENTIAL_ENC_SIZE); - // + if (add_user) + { + printf1(TAG_GREEN, "adding user details to output\r\n"); + ret = ctap_add_user_entity(map, &cred->credential.user); + check_retr(ret); + } ret = ctap_add_credential_descriptor(map, cred); check_retr(ret); - crypto_ecc256_load_key((uint8_t*)&cred->credential, sizeof(struct Credential), NULL, 0); + crypto_ecc256_load_key((uint8_t*)&cred->credential.id, sizeof(CredentialId), NULL, 0); int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder); @@ -772,9 +881,19 @@ uint8_t ctap_get_next_assertion(CborEncoder * encoder) } auth_data_update_count(authData); + int add_user_info = cred->credential.user.id_size && getAssertionState.user_verified; + if (getAssertionState.user_verified) + { + printf1(TAG_GREEN, "adding user info to assertion response\r\n"); + ret = cbor_encoder_create_map(encoder, &map, 4); + } + else + { + printf1(TAG_GREEN, "NOT adding user info to assertion response\r\n"); + ret = cbor_encoder_create_map(encoder, &map, 3); + } - ret = cbor_encoder_create_map(encoder, &map, 3); check_ret(ret); { @@ -784,7 +903,7 @@ uint8_t ctap_get_next_assertion(CborEncoder * encoder) check_ret(ret); } - ret = ctap_end_get_assertion(&map, cred, (uint8_t *)authData, getAssertionState.clientDataHash); + ret = ctap_end_get_assertion(&map, cred, (uint8_t *)authData, getAssertionState.clientDataHash, add_user_info); check_retr(ret); ret = cbor_encoder_close_container(encoder, &map); @@ -816,6 +935,7 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) { ret = verify_pin_auth(GA.pinAuth, GA.clientDataHash); check_retr(ret); + getAssertionState.user_verified = 1; } } @@ -824,16 +944,29 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) return CTAP2_ERR_MISSING_PARAMETER; } CborEncoder map; - if (GA.credLen > 1) - ret = cbor_encoder_create_map(encoder, &map, 4); - else - ret = cbor_encoder_create_map(encoder, &map, 3); - check_ret(ret); - ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL); - check_retr(ret); + int map_size = 3; printf1(TAG_GA, "ALLOW_LIST has %d creds\n", GA.credLen); + int validCredCount = ctap_filter_invalid_credentials(&GA); + + int add_user_info = GA.creds[validCredCount - 1].credential.user.id_size && getAssertionState.user_verified; + if (validCredCount > 1) + { + map_size += 1; + } + + if (add_user_info) + { + map_size += 1; + } + + ret = cbor_encoder_create_map(encoder, &map, map_size); + check_ret(ret); + + ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL, 0); + check_retr(ret); + /*for (int j = 0; j < GA.credLen; j++)*/ /*{*/ /*printf1(TAG_GA,"CRED ID (# %d): ", GA.creds[j].credential.enc.count);*/ @@ -851,7 +984,6 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) // Decrypt here // - int validCredCount = ctap_filter_invalid_credentials(&GA); if (validCredCount > 0) { save_credential_list((CTAP_authDataHeader*)auth_data_buf, GA.clientDataHash, GA.creds, validCredCount-1); // skip last one @@ -862,25 +994,30 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) return CTAP2_ERR_NO_CREDENTIALS; } + // if only one account for this RP, null out the user details + if (validCredCount < 2) + { + printf1(TAG_GREEN, "Only one account, nulling out user details on response\r\n"); + memset(&GA.creds[0].credential.user.name, 0, USER_NAME_LIMIT); + } + printf1(TAG_GA,"resulting order of creds:\n"); for (int j = 0; j < GA.credLen; j++) { - printf1(TAG_GA,"CRED ID (# %d)\n", GA.creds[j].credential.enc.count); + printf1(TAG_GA,"CRED ID (# %d)\n", GA.creds[j].credential.id.count); } + if (validCredCount > 1) { - if (GA.credLen > 1) - { - ret = cbor_encode_int(&map, RESP_numberOfCredentials); - check_ret(ret); - ret = cbor_encode_int(&map, validCredCount); - check_ret(ret); - } + ret = cbor_encode_int(&map, RESP_numberOfCredentials); + check_ret(ret); + ret = cbor_encode_int(&map, validCredCount); + check_ret(ret); } CTAP_credentialDescriptor * cred = &GA.creds[validCredCount - 1]; - ret = ctap_end_get_assertion(&map, cred, auth_data_buf, GA.clientDataHash); + ret = ctap_end_get_assertion(&map, cred, auth_data_buf, GA.clientDataHash, add_user_info); check_retr(ret); ret = cbor_encoder_close_container(encoder, &map); @@ -1320,14 +1457,7 @@ done: return status; } -void ctap_flush_state(int backup) -{ - authenticator_write_state(&STATE, 0); - if (backup) - { - authenticator_write_state(&STATE, 1); - } -} + static void ctap_state_init() { @@ -1339,6 +1469,9 @@ static void ctap_state_init() STATE.is_initialized = INITIALIZED_MARKER; STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS; STATE.is_pin_set = 0; + STATE.rk_stored = 0; + + ctap_reset_rk(); } void ctap_init() @@ -1597,6 +1730,7 @@ int8_t ctap_load_key(uint8_t index, uint8_t * key) void ctap_reset() { ctap_state_init(); + authenticator_write_state(&STATE, 0); authenticator_write_state(&STATE, 1); diff --git a/fido2/ctap.h b/fido2/ctap.h index 0140824..bd629d2 100644 --- a/fido2/ctap.h +++ b/fido2/ctap.h @@ -111,12 +111,11 @@ #define USER_NAME_LIMIT 65 // Must be minimum of 64 bytes but can be more. #define CTAP_MAX_MESSAGE_SIZE 1200 +#define CREDENTIAL_RK_FLASH_PAD 2 // size of RK should be 8-byte aligned to store in flash easily. #define CREDENTIAL_TAG_SIZE 16 -#define CREDENTIAL_NONCE_SIZE 8 +#define CREDENTIAL_NONCE_SIZE (16 + CREDENTIAL_RK_FLASH_PAD) #define CREDENTIAL_COUNTER_SIZE (4) -#define CREDENTIAL_ENC_SIZE 144 // pad to multiple of 16 bytes -#define CREDENTIAL_PAD_SIZE (CREDENTIAL_ENC_SIZE - (USER_ID_MAX_SIZE + USER_NAME_LIMIT + CREDENTIAL_COUNTER_SIZE + 1)) -#define CREDENTIAL_ID_SIZE (CREDENTIAL_TAG_SIZE + CREDENTIAL_NONCE_SIZE + CREDENTIAL_ENC_SIZE) +#define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes #define PUB_KEY_CRED_PUB_KEY 0x01 #define PUB_KEY_CRED_UNKNOWN 0x3F @@ -143,22 +142,27 @@ typedef struct uint8_t name[USER_NAME_LIMIT]; }__attribute__((packed)) CTAP_userEntity; -struct Credential { +typedef struct { uint8_t tag[CREDENTIAL_TAG_SIZE]; uint8_t nonce[CREDENTIAL_NONCE_SIZE]; - struct { - CTAP_userEntity user; - uint32_t count; - uint8_t _pad[CREDENTIAL_PAD_SIZE]; - } __attribute__((packed)) enc; + uint8_t rpIdHash[32]; + uint32_t count; +}__attribute__((packed)) CredentialId; + +struct Credential { + CredentialId id; + CTAP_userEntity user; }; +typedef struct Credential CTAP_residentKey; + + typedef struct { uint8_t aaguid[16]; uint8_t credLenH; uint8_t credLenL; - struct Credential credential; + CredentialId id; } __attribute__((packed)) CTAP_attestHeader; typedef struct diff --git a/fido2/ctap_parse.c b/fido2/ctap_parse.c index 2b6905a..d45351f 100644 --- a/fido2/ctap_parse.c +++ b/fido2/ctap_parse.c @@ -150,6 +150,7 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val) return CTAP2_ERR_LIMIT_EXCEEDED; } MC->user.id_size = sz; + printf1(TAG_GREEN,"parsed id_size: %d\r\n", MC->user.id_size); check_ret(ret); } else if (strcmp((const char *)key, "name") == 0) @@ -737,9 +738,9 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * return CTAP2_ERR_MISSING_PARAMETER; } - buflen = sizeof(struct Credential); - cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential, &buflen, NULL); - if (buflen != CREDENTIAL_ID_SIZE) + buflen = sizeof(CredentialId); + cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL); + if (buflen != sizeof(CredentialId)) { printf2(TAG_ERR,"Ignoring credential is incorrect length\n"); //return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail? diff --git a/fido2/device.h b/fido2/device.h index e750568..e07cc1e 100644 --- a/fido2/device.h +++ b/fido2/device.h @@ -82,4 +82,12 @@ extern int ctap_user_verification(uint8_t arg); // data is HID_MESSAGE_SIZE long in bytes extern void ctaphid_write_block(uint8_t * data); + +// Resident key +void ctap_reset_rk(); +uint32_t ctap_rk_size(); +void ctap_store_rk(int index,CTAP_residentKey * rk); +void ctap_load_rk(int index,CTAP_residentKey * rk); +void ctap_overwrite_rk(int index,CTAP_residentKey * rk); + #endif diff --git a/fido2/log.c b/fido2/log.c index 887e3fb..b2f0b6e 100644 --- a/fido2/log.c +++ b/fido2/log.c @@ -47,6 +47,7 @@ struct logtag tagtable[] = { {TAG_CTAP,"CTAP"}, {TAG_U2F,"U2F"}, {TAG_DUMP,"DUMP"}, + {TAG_DUMP2,"DUMP2"}, {TAG_HID,"HID"}, {TAG_USB,"USB"}, {TAG_GREEN,"DEBUG"}, diff --git a/fido2/log.h b/fido2/log.h index b230d78..3f0ba33 100644 --- a/fido2/log.h +++ b/fido2/log.h @@ -54,6 +54,7 @@ typedef enum TAG_USB = (1 << 13), TAG_WALLET = (1 << 14), TAG_STOR = (1 << 15), + TAG_DUMP2 = (1 << 16), TAG_FILENO = (1<<31) } LOG_TAG; diff --git a/fido2/storage.h b/fido2/storage.h index aafde2d..56403be 100644 --- a/fido2/storage.h +++ b/fido2/storage.h @@ -43,6 +43,8 @@ typedef struct int pin_code_length; int8_t remaining_tries; + uint16_t rk_stored; + uint16_t key_lens[MAX_KEYS]; uint8_t key_space[KEY_SPACE_BYTES]; } AuthenticatorState; diff --git a/targets/stm32l442/src/app.h b/targets/stm32l442/src/app.h index f506427..23134e2 100644 --- a/targets/stm32l442/src/app.h +++ b/targets/stm32l442/src/app.h @@ -33,7 +33,7 @@ void hw_init(void); #define SOLO_BUTTON_PORT GPIOA #define SOLO_BUTTON_PIN LL_GPIO_PIN_0 -#define SKIP_BUTTON_CHECK_WITH_DELAY 0 +#define SKIP_BUTTON_CHECK_WITH_DELAY 1 #define SKIP_BUTTON_CHECK_FAST 0 #endif diff --git a/targets/stm32l442/src/device.c b/targets/stm32l442/src/device.c index 2660b45..7979173 100644 --- a/targets/stm32l442/src/device.c +++ b/targets/stm32l442/src/device.c @@ -16,6 +16,7 @@ #include "fifo.h" #include "log.h" #include "ctaphid.h" +#include "ctap.h" #define PAGE_SIZE 2048 @@ -26,11 +27,15 @@ #define STATE2_PAGE (PAGES - 2) #define STATE1_PAGE (PAGES - 1) +#define RK_NUM_PAGES 10 +#define RK_START_PAGE (PAGES - 14) +#define RK_END_PAGE (PAGES - 14 + RK_NUM_PAGES) + #define APPLICATION_START_PAGE (0) #define APPLICATION_START_ADDR flash_addr(APPLICATION_START_PAGE) -#define APPLICATION_END_PAGE ((PAGES - 9)) // 119 is NOT included in application +#define APPLICATION_END_PAGE ((PAGES - 19)) // 119 is NOT included in application #define APPLICATION_END_ADDR (flash_addr(APPLICATION_END_PAGE)-4) // NOT included in application #define AUTH_WORD_ADDR (flash_addr(APPLICATION_END_PAGE)-4) @@ -113,8 +118,8 @@ int usbhid_recv(uint8_t * msg) if (fifo_hidmsg_size()) { fifo_hidmsg_take(msg); - printf1(TAG_DUMP,">> "); - dump_hex1(TAG_DUMP,msg, HID_PACKET_SIZE); + printf1(TAG_DUMP2,">> "); + dump_hex1(TAG_DUMP2,msg, HID_PACKET_SIZE); return HID_PACKET_SIZE; } return 0; @@ -123,8 +128,8 @@ int usbhid_recv(uint8_t * msg) void usbhid_send(uint8_t * msg) { - printf1(TAG_DUMP,"<< "); - dump_hex1(TAG_DUMP, msg, HID_PACKET_SIZE); + printf1(TAG_DUMP2,"<< "); + dump_hex1(TAG_DUMP2, msg, HID_PACKET_SIZE); while (PCD_GET_EP_TX_STATUS(USB, HID_EPIN_ADDR & 0x0f) == USB_EP_TX_VALID) ; USBD_LL_Transmit(&Solo_USBD_Device, HID_EPIN_ADDR, msg, HID_PACKET_SIZE); @@ -411,6 +416,79 @@ int ctap_user_verification(uint8_t arg) return 1; } +void ctap_reset_rk() +{ + int i; + printf1(TAG_GREEN, "resetting RK \r\n"); + for(i = 0; i < RK_NUM_PAGES; i++) + { + flash_erase_page(RK_START_PAGE + i); + } +} + +uint32_t ctap_rk_size() +{ + return RK_NUM_PAGES * (PAGE_SIZE / sizeof(CTAP_residentKey)); +} + +void ctap_store_rk(int index,CTAP_residentKey * rk) +{ + int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE; + uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + ((sizeof(CTAP_residentKey)*index) % PAGE_SIZE); + + printf1(TAG_GREEN, "storing RK %d @ %04x\r\n", index,addr); + + if (page_offset < RK_NUM_PAGES) + { + flash_write(addr, (uint8_t*)rk, sizeof(CTAP_residentKey)); + //dump_hex1(TAG_GREEN,rk,sizeof(CTAP_residentKey)); + } + else + { + printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index); + } +} + +void ctap_load_rk(int index,CTAP_residentKey * rk) +{ + int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE; + uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + ((sizeof(CTAP_residentKey)*index) % PAGE_SIZE); + + printf1(TAG_GREEN, "reading RK %d @ %04x\r\n", index, addr); + if (page_offset < RK_NUM_PAGES) + { + uint32_t * ptr = (uint32_t *)addr; + memmove((uint8_t*)rk,ptr,sizeof(CTAP_residentKey)); + //dump_hex1(TAG_GREEN,rk,sizeof(CTAP_residentKey)); + } + else + { + printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index); + } +} + +void ctap_overwrite_rk(int index,CTAP_residentKey * rk) +{ + uint8_t tmppage[PAGE_SIZE]; + int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE; + int page = page_offset + RK_START_PAGE; + + printf1(TAG_GREEN, "overwriting RK %d\r\n", index); + if (page_offset < RK_NUM_PAGES) + { + memmove(tmppage, (uint8_t*)flash_addr(page), PAGE_SIZE); + + memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey)); + flash_erase_page(page); + flash_write(flash_addr(page), tmppage, ((sizeof(CTAP_residentKey) * (index + 1)) % PAGE_SIZE) ); + } + else + { + printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index); + } +} + + void _Error_Handler(char *file, int line) {