add initial resident key support

This commit is contained in:
Conor Patrick 2018-11-12 11:51:43 -05:00 committed by Emanuele Cesena
parent 36fdc64fab
commit fc8bc892c1
9 changed files with 325 additions and 96 deletions

View File

@ -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);
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);
}
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 (GA.credLen > 1)
if (validCredCount > 1)
{
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);

View File

@ -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;
uint8_t rpIdHash[32];
uint32_t count;
uint8_t _pad[CREDENTIAL_PAD_SIZE];
} __attribute__((packed)) enc;
}__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

View File

@ -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?

View File

@ -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

View File

@ -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"},

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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)
{