pass fido2 tests
This commit is contained in:
parent
2f911368da
commit
2fd96f8e4b
201
fido2/ctap.c
201
fido2/ctap.c
@ -26,6 +26,7 @@
|
||||
#include "cbor.h"
|
||||
|
||||
#include "ctap.h"
|
||||
#include "ctaphid.h"
|
||||
#include "ctap_parse.h"
|
||||
#include "ctap_errors.h"
|
||||
#include "cose_key.h"
|
||||
@ -43,6 +44,7 @@ uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
||||
uint8_t KEY_AGREEMENT_PUB[64];
|
||||
static uint8_t KEY_AGREEMENT_PRIV[32];
|
||||
static uint8_t PIN_CODE_HASH[32];
|
||||
static int8_t PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||
|
||||
AuthenticatorState STATE;
|
||||
|
||||
@ -264,11 +266,11 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void make_auth_tag(struct rpId * rp, CTAP_userEntity * user, uint32_t count, uint8_t * tag)
|
||||
void make_auth_tag(uint8_t * nonce, CTAP_userEntity * user, uint32_t count, uint8_t * tag)
|
||||
{
|
||||
uint8_t hashbuf[32];
|
||||
crypto_sha256_hmac_init(NULL, 0, hashbuf);
|
||||
crypto_sha256_update(rp->id, rp->size);
|
||||
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);
|
||||
@ -283,21 +285,19 @@ static uint32_t auth_data_update_count(CTAP_authDataHeader * authData)
|
||||
if (count == 0) // count 0 will indicate invalid token
|
||||
{
|
||||
count = ctap_atomic_count( 0 );
|
||||
|
||||
}
|
||||
uint8_t * byte = (uint8_t*) &authData->signCount;
|
||||
|
||||
*byte++ = count & 0xff;
|
||||
count = count >> 8;
|
||||
*byte++ = count & 0xff;
|
||||
count = count >> 8;
|
||||
*byte++ = count & 0xff;
|
||||
count = count >> 8;
|
||||
*byte++ = count & 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)
|
||||
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)
|
||||
{
|
||||
CborEncoder cose_key;
|
||||
int auth_data_sz, ret;
|
||||
@ -318,10 +318,24 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
|
||||
count = auth_data_update_count(&authData->head);
|
||||
|
||||
authData->head.flags = (ctap_user_presence_test() << 0);
|
||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||
int but = ctap_user_presence_test();
|
||||
|
||||
if (!but)
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
else if (but < 0) // Cancel
|
||||
{
|
||||
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
||||
}
|
||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||
|
||||
authData->head.flags = (but << 0);
|
||||
authData->head.flags |= (ctap_user_verification(0) << 2);
|
||||
|
||||
|
||||
|
||||
if (credtype != 0)
|
||||
{
|
||||
// add attestedCredentialData
|
||||
@ -338,19 +352,19 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
#else
|
||||
memset((uint8_t*)&authData->attest.credential, 0, sizeof(struct Credential));
|
||||
|
||||
// Make a tag we can later check to make sure this is a token we made
|
||||
make_auth_tag(rp, user, count, authData->attest.credential.tag);
|
||||
ctap_generate_rng(authData->attest.credential.nonce, CREDENTIAL_NONCE_SIZE);
|
||||
|
||||
memmove(&authData->attest.credential.enc.user, user, sizeof(CTAP_userEntity)); //TODO encrypt this
|
||||
authData->attest.credential.enc.count = count;
|
||||
|
||||
// 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);
|
||||
|
||||
crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL);
|
||||
crypto_aes256_encrypt((uint8_t*)&authData->attest.credential.enc, CREDENTIAL_ENC_SIZE);
|
||||
|
||||
ctap_generate_cose_key(&cose_key, (uint8_t*)&authData->attest.credential, sizeof(struct Credential), credtype, algtype);
|
||||
|
||||
printf1(TAG_MC,"COSE_KEY: "); dump_hex1(TAG_MC, cose_key_buf, cbor_encoder_get_buffer_size(&cose_key, cose_key_buf));
|
||||
|
||||
auth_data_sz = sizeof(CTAP_authData) + cbor_encoder_get_buffer_size(&cose_key, cose_key_buf);
|
||||
#endif
|
||||
|
||||
@ -367,7 +381,8 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
return auth_data_sz;
|
||||
if (sz) *sz = auth_data_sz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -419,7 +434,6 @@ int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHa
|
||||
crypto_sha256_update(clientDataHash, CLIENT_DATA_HASH_SIZE);
|
||||
crypto_sha256_final(hashbuf);
|
||||
|
||||
printf1(TAG_GREEN, "sha256: "); dump_hex1(TAG_DUMP,hashbuf,32);
|
||||
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
||||
|
||||
return ctap_encode_der_sig(sigbuf,sigder);
|
||||
@ -471,13 +485,8 @@ uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
|
||||
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.enc.user, desc->credential.enc.count, tag);
|
||||
make_auth_tag(desc->credential.nonce, &desc->credential.enc.user, desc->credential.enc.count, tag);
|
||||
|
||||
return (memcmp(desc->credential.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
||||
}
|
||||
@ -519,6 +528,12 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
}
|
||||
}
|
||||
|
||||
if (MC.up)
|
||||
{
|
||||
return CTAP2_ERR_INVALID_OPTION;
|
||||
}
|
||||
|
||||
crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL);
|
||||
for (i = 0; i < MC.excludeListSize; i++)
|
||||
{
|
||||
ret = parse_credential_descriptor(&MC.excludeList, excl_cred);
|
||||
@ -528,8 +543,11 @@ 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);
|
||||
if (ctap_authenticate_credential(&MC.rp, excl_cred))
|
||||
{
|
||||
printf1(TAG_MC, "Cred %d failed!\r\n",i);
|
||||
return CTAP2_ERR_CREDENTIAL_EXCLUDED;
|
||||
}
|
||||
|
||||
@ -540,9 +558,11 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
CborEncoder map;
|
||||
ret = cbor_encoder_create_map(encoder, &map, 3);
|
||||
check_ret(ret);
|
||||
int32_t auth_data_sz;
|
||||
|
||||
int auth_data_sz = ctap_make_auth_data(&MC.rp, &map, auth_data_buf, sizeof(auth_data_buf),
|
||||
&MC.user, MC.publicKeyCredentialType, MC.COSEAlgorithmIdentifier);
|
||||
ret = ctap_make_auth_data(&MC.rp, &map, auth_data_buf, sizeof(auth_data_buf),
|
||||
&MC.user, MC.publicKeyCredentialType, MC.COSEAlgorithmIdentifier, &auth_data_sz);
|
||||
check_retr(ret);
|
||||
|
||||
crypto_ecc256_load_attestation_key();
|
||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_sz, MC.clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
@ -724,11 +744,6 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
||||
|
||||
crypto_ecc256_load_key((uint8_t*)&cred->credential, sizeof(struct Credential), NULL, 0);
|
||||
|
||||
/*printf1(TAG_GREEN,"auth_data_buf: "); dump_hex1(TAG_DUMP, auth_data_buf, sizeof(CTAP_authDataHeader));*/
|
||||
/*printf1(TAG_GREEN,"clientdatahash: "); dump_hex1(TAG_DUMP, clientDataHash, 32);*/
|
||||
/*printf1(TAG_GREEN,"credential: # %d\n", cred->credential.enc.count);*/
|
||||
/*dump_hex1(TAG_DUMP, clientDataHash, 32);*/
|
||||
|
||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
|
||||
{
|
||||
@ -801,12 +816,16 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!GA.rp.size || !GA.clientDataHashPresent)
|
||||
{
|
||||
return CTAP2_ERR_MISSING_PARAMETER;
|
||||
}
|
||||
CborEncoder map;
|
||||
ret = cbor_encoder_create_map(encoder, &map, 5);
|
||||
check_ret(ret);
|
||||
|
||||
ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0);
|
||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL);
|
||||
check_retr(ret);
|
||||
|
||||
printf1(TAG_GA, "ALLOW_LIST has %d creds\n", GA.credLen);
|
||||
/*for (int j = 0; j < GA.credLen; j++)*/
|
||||
@ -834,13 +853,13 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR,"Error, no authentic credential\n");
|
||||
return CTAP2_ERR_CREDENTIAL_NOT_VALID;
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
printf1(TAG_RED,"resulting order of creds:\n");
|
||||
printf1(TAG_GA,"resulting order of creds:\n");
|
||||
for (int j = 0; j < GA.credLen; j++)
|
||||
{
|
||||
printf1(TAG_RED,"CRED ID (# %d)\n", GA.creds[j].credential.enc.count);
|
||||
printf1(TAG_GA,"CRED ID (# %d)\n", GA.creds[j].credential.enc.count);
|
||||
}
|
||||
|
||||
{
|
||||
@ -861,6 +880,18 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return how many trailing zeros in a buffer
|
||||
static int trailing_zeros(uint8_t * buf, int indx)
|
||||
{
|
||||
int c = 0;
|
||||
while(0==buf[indx] && indx)
|
||||
{
|
||||
indx--;
|
||||
c++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platform_pubkey, uint8_t * pinAuth, uint8_t * pinHashEnc)
|
||||
{
|
||||
uint8_t shared_secret[32];
|
||||
@ -876,7 +907,11 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
||||
{
|
||||
if (ctap_device_locked())
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
return CTAP2_ERR_PIN_BLOCKED;
|
||||
}
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -911,25 +946,31 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
||||
|
||||
crypto_aes256_decrypt(pinEnc, len);
|
||||
|
||||
printf1(TAG_CP,"new pin: %s\n", pinEnc);
|
||||
|
||||
ret = strnlen((const char *)pinEnc, NEW_PIN_ENC_MAX_SIZE);
|
||||
if (ret == NEW_PIN_ENC_MAX_SIZE)
|
||||
|
||||
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
|
||||
ret = NEW_PIN_ENC_MIN_SIZE - ret;
|
||||
|
||||
if (ret < NEW_PIN_MIN_SIZE || ret >= NEW_PIN_MAX_SIZE)
|
||||
{
|
||||
printf2(TAG_ERR,"No NULL terminator in new pin string\n");
|
||||
return CTAP1_ERR_OTHER;
|
||||
}
|
||||
else if (ret < 4)
|
||||
{
|
||||
printf2(TAG_ERR,"new PIN is too short\n");
|
||||
printf2(TAG_ERR,"new PIN is too short or too long [%d bytes]\n", ret);
|
||||
return CTAP2_ERR_PIN_POLICY_VIOLATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_CP,"new pin: %s [%d bytes]\n", pinEnc, ret);
|
||||
dump_hex1(TAG_CP, pinEnc, ret);
|
||||
}
|
||||
|
||||
if (ctap_is_pin_set())
|
||||
{
|
||||
if (ctap_device_locked())
|
||||
{
|
||||
return CTAP2_ERR_OPERATION_DENIED;
|
||||
return CTAP2_ERR_PIN_BLOCKED;
|
||||
}
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||
}
|
||||
crypto_aes256_reset_iv(NULL);
|
||||
crypto_aes256_decrypt(pinHashEnc, 16);
|
||||
@ -937,6 +978,10 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
||||
{
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
ctap_decrement_pin_attempts();
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||
}
|
||||
return CTAP2_ERR_PIN_INVALID;
|
||||
}
|
||||
else
|
||||
@ -976,6 +1021,10 @@ uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubke
|
||||
// Generate new keyAgreement pair
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
ctap_decrement_pin_attempts();
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||
}
|
||||
return CTAP2_ERR_PIN_INVALID;
|
||||
}
|
||||
|
||||
@ -995,6 +1044,20 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
|
||||
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
|
||||
int ret = ctap_parse_client_pin(&CP,request,length);
|
||||
|
||||
switch(CP.subCommand)
|
||||
{
|
||||
case CP_cmdSetPin:
|
||||
case CP_cmdChangePin:
|
||||
case CP_cmdGetPinToken:
|
||||
if (ctap_device_locked())
|
||||
{
|
||||
return CTAP2_ERR_PIN_BLOCKED;
|
||||
}
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
@ -1104,7 +1167,7 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
if (num_map)
|
||||
if (num_map || CP.getRetries)
|
||||
{
|
||||
ret = cbor_encoder_close_container(encoder, &map);
|
||||
check_ret(ret);
|
||||
@ -1141,10 +1204,14 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
{
|
||||
case CTAP_MAKE_CREDENTIAL:
|
||||
case CTAP_GET_ASSERTION:
|
||||
case CTAP_CLIENT_PIN:
|
||||
if (ctap_device_locked())
|
||||
{
|
||||
status = CTAP2_ERR_OPERATION_DENIED;
|
||||
status = CTAP2_ERR_PIN_BLOCKED;
|
||||
goto done;
|
||||
}
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
status = CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
@ -1153,6 +1220,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
switch(cmd)
|
||||
{
|
||||
case CTAP_MAKE_CREDENTIAL:
|
||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||
printf1(TAG_CTAP,"CTAP_MAKE_CREDENTIAL\n");
|
||||
t1 = millis();
|
||||
status = ctap_make_credential(&encoder, pkt_raw, length);
|
||||
@ -1164,6 +1232,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
||||
break;
|
||||
case CTAP_GET_ASSERTION:
|
||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||
printf1(TAG_CTAP,"CTAP_GET_ASSERTION\n");
|
||||
t1 = millis();
|
||||
status = ctap_get_assertion(&encoder, pkt_raw, length);
|
||||
@ -1190,6 +1259,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
case CTAP_CLIENT_PIN:
|
||||
printf1(TAG_CTAP,"CTAP_CLIENT_PIN\n");
|
||||
status = ctap_client_pin(&encoder, pkt_raw, length);
|
||||
|
||||
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
||||
dump_hex1(TAG_DUMP, buf, cbor_encoder_get_buffer_size(&encoder, buf));
|
||||
break;
|
||||
@ -1228,6 +1298,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
}
|
||||
|
||||
done:
|
||||
device_set_status(CTAPHID_STATUS_IDLE);
|
||||
getAssertionState.lastcmd = cmd;
|
||||
|
||||
if (status != CTAP1_ERR_SUCCESS)
|
||||
@ -1235,7 +1306,7 @@ done:
|
||||
resp->length = 0;
|
||||
}
|
||||
|
||||
printf1(TAG_CTAP,"cbor output structure: %d bytes\n", resp->length);
|
||||
printf1(TAG_CTAP,"cbor output structure: %d bytes. Return 0x%02x\n", resp->length, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -1267,6 +1338,8 @@ void ctap_init()
|
||||
|
||||
authenticator_read_state(&STATE);
|
||||
|
||||
device_set_status(CTAPHID_STATUS_IDLE);
|
||||
|
||||
if (STATE.is_initialized == INITIALIZED_MARKER)
|
||||
{
|
||||
printf1(TAG_STOR,"Auth state is initialized\n");
|
||||
@ -1295,7 +1368,7 @@ void ctap_init()
|
||||
{
|
||||
printf1(TAG_STOR,"pin code: \"%s\"\n", STATE.pin_code);
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(STATE.pin_code, strnlen(STATE.pin_code, NEW_PIN_ENC_MAX_SIZE));
|
||||
crypto_sha256_update(STATE.pin_code, STATE.pin_code_length);
|
||||
crypto_sha256_final(PIN_CODE_HASH);
|
||||
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
|
||||
}
|
||||
@ -1335,14 +1408,15 @@ uint8_t ctap_pin_matches(uint8_t * pin, int len)
|
||||
|
||||
void ctap_update_pin(uint8_t * pin, int len)
|
||||
{
|
||||
// TODO this should go in flash
|
||||
if (len > NEW_PIN_ENC_MAX_SIZE-1 || len < 4)
|
||||
if (len > NEW_PIN_ENC_MIN_SIZE || len < 4)
|
||||
{
|
||||
printf2(TAG_ERR, "Update pin fail length\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(STATE.pin_code, 0, NEW_PIN_ENC_MAX_SIZE);
|
||||
memset(STATE.pin_code, 0, NEW_PIN_ENC_MIN_SIZE);
|
||||
memmove(STATE.pin_code, pin, len);
|
||||
STATE.pin_code_length = len;
|
||||
STATE.pin_code[NEW_PIN_ENC_MIN_SIZE - 1] = 0;
|
||||
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(STATE.pin_code, len);
|
||||
@ -1350,18 +1424,25 @@ void ctap_update_pin(uint8_t * pin, int len)
|
||||
|
||||
STATE.is_pin_set = 1;
|
||||
|
||||
authenticator_write_state(&STATE, 1);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
|
||||
printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
|
||||
}
|
||||
|
||||
uint8_t ctap_decrement_pin_attempts()
|
||||
{
|
||||
if (STATE.remaining_tries > 0)
|
||||
if (PIN_BOOT_ATTEMPTS_LEFT > 0)
|
||||
{
|
||||
PIN_BOOT_ATTEMPTS_LEFT--;
|
||||
}
|
||||
if (! ctap_device_locked())
|
||||
{
|
||||
STATE.remaining_tries--;
|
||||
ctap_flush_state(0);
|
||||
printf1(TAG_CP, "ATTEMPTS left: %d\n", STATE.remaining_tries);
|
||||
|
||||
if (STATE.remaining_tries == 0)
|
||||
if (ctap_device_locked())
|
||||
{
|
||||
memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
|
||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||
@ -1378,7 +1459,12 @@ uint8_t ctap_decrement_pin_attempts()
|
||||
|
||||
int8_t ctap_device_locked()
|
||||
{
|
||||
return STATE.remaining_tries == 0;
|
||||
return STATE.remaining_tries <= 0;
|
||||
}
|
||||
|
||||
int8_t ctap_device_boot_locked()
|
||||
{
|
||||
return PIN_BOOT_ATTEMPTS_LEFT <= 0;
|
||||
}
|
||||
|
||||
int8_t ctap_leftover_pin_attempts()
|
||||
@ -1389,6 +1475,7 @@ int8_t ctap_leftover_pin_attempts()
|
||||
void ctap_reset_pin_attempts()
|
||||
{
|
||||
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||
PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||
ctap_flush_state(0);
|
||||
}
|
||||
|
||||
|
16
fido2/ctap.h
16
fido2/ctap.h
@ -34,7 +34,8 @@
|
||||
#define CTAP_VENDOR_FIRST 0x40
|
||||
#define CTAP_VENDOR_LAST 0xBF
|
||||
|
||||
#define CTAP_AAGUID ((uint8_t*)"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")
|
||||
// AAGUID For Solo
|
||||
#define CTAP_AAGUID ((uint8_t*)"\x88\x76\x63\x1b\xd4\xa0\x42\x7f\x57\x73\x0e\xc7\x1c\x9e\x02\x79")
|
||||
|
||||
#define MC_clientDataHash 0x01
|
||||
#define MC_rp 0x02
|
||||
@ -126,10 +127,14 @@
|
||||
#define ALLOW_LIST_MAX_SIZE 20
|
||||
|
||||
#define NEW_PIN_ENC_MAX_SIZE 256 // includes NULL terminator
|
||||
#define NEW_PIN_ENC_MIN_SIZE 64
|
||||
#define NEW_PIN_MAX_SIZE 64
|
||||
#define NEW_PIN_MIN_SIZE 4
|
||||
|
||||
#define CTAP_RESPONSE_BUFFER_SIZE 1024
|
||||
#define CTAP_RESPONSE_BUFFER_SIZE 4096
|
||||
|
||||
#define PIN_LOCKOUT_ATTEMPTS 8
|
||||
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
|
||||
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -198,6 +203,7 @@ typedef struct
|
||||
|
||||
uint8_t rk;
|
||||
uint8_t uv;
|
||||
uint8_t up;
|
||||
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
@ -215,6 +221,7 @@ typedef struct
|
||||
{
|
||||
uint32_t paramsParsed;
|
||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||
uint8_t clientDataHashPresent;
|
||||
|
||||
struct rpId rp;
|
||||
|
||||
@ -222,12 +229,14 @@ typedef struct
|
||||
|
||||
uint8_t rk;
|
||||
uint8_t uv;
|
||||
uint8_t up;
|
||||
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
int pinProtocol;
|
||||
|
||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
||||
uint8_t allowListPresent;
|
||||
} CTAP_getAssertion;
|
||||
|
||||
typedef struct
|
||||
@ -281,6 +290,7 @@ uint8_t ctap_is_pin_set();
|
||||
uint8_t ctap_pin_matches(uint8_t * pin, int len);
|
||||
void ctap_reset();
|
||||
int8_t ctap_device_locked();
|
||||
int8_t ctap_device_boot_locked();
|
||||
|
||||
// Key storage API
|
||||
|
||||
|
@ -92,7 +92,7 @@ const char * cbor_value_get_type_string(const CborValue *value)
|
||||
uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||
{
|
||||
size_t sz, map_length;
|
||||
uint8_t key[8];
|
||||
uint8_t key[24];
|
||||
int ret;
|
||||
int i;
|
||||
CborValue map;
|
||||
@ -126,6 +126,7 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||
printf2(TAG_ERR,"Error, rp map key is too large\n");
|
||||
return CTAP2_ERR_LIMIT_EXCEEDED;
|
||||
}
|
||||
|
||||
check_ret(ret);
|
||||
key[sizeof(key) - 1] = 0;
|
||||
|
||||
@ -153,6 +154,11 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||
}
|
||||
else if (strcmp((const char *)key, "name") == 0)
|
||||
{
|
||||
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, expecting text string type for user.name value\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
sz = USER_NAME_LIMIT;
|
||||
ret = cbor_value_copy_text_string(&map, (char *)MC->user.name, &sz, NULL);
|
||||
if (ret != CborErrorOutOfMemory)
|
||||
@ -161,6 +167,22 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||
}
|
||||
MC->user.name[USER_NAME_LIMIT - 1] = 0;
|
||||
}
|
||||
else if (strcmp((const char *)key, "displayName") == 0)
|
||||
{
|
||||
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, expecting text string type for user.displayName value\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
}
|
||||
else if (strcmp((const char *)key, "icon") == 0)
|
||||
{
|
||||
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, expecting text string type for user.icon value\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_PARSE,"ignoring key %s for user map\n", key);
|
||||
@ -263,6 +285,19 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
||||
ret = cbor_value_get_array_length(val, &arr_length);
|
||||
check_ret(ret);
|
||||
|
||||
for (i = 0; i < arr_length; i++)
|
||||
{
|
||||
if ((ret = parse_pub_key_cred_param(&arr, &cred_type, &alg_type)) != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
ret = cbor_value_advance(&arr);
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
ret = cbor_value_enter_container(val,&arr);
|
||||
check_ret(ret);
|
||||
|
||||
for (i = 0; i < arr_length; i++)
|
||||
{
|
||||
if ((ret = parse_pub_key_cred_param(&arr, &cred_type, &alg_type)) == 0)
|
||||
@ -275,11 +310,6 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continue? fail?
|
||||
return ret;
|
||||
}
|
||||
ret = cbor_value_advance(&arr);
|
||||
check_ret(ret);
|
||||
}
|
||||
@ -309,10 +339,40 @@ uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t parse_verify_exclude_list(CborValue * val)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
CborValue arr;
|
||||
size_t size;
|
||||
CTAP_credentialDescriptor cred;
|
||||
if (cbor_value_get_type(val) != CborArrayType)
|
||||
{
|
||||
printf2(TAG_ERR,"error, exclude list is not a map\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
ret = cbor_value_get_array_length(val, &size);
|
||||
check_ret(ret);
|
||||
ret = cbor_value_enter_container(val,&arr);
|
||||
check_ret(ret);
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
ret = parse_credential_descriptor(&arr, &cred);
|
||||
check_ret(ret);
|
||||
ret = cbor_value_advance(&arr);
|
||||
check_ret(ret);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t parse_rp_id(struct rpId * rp, CborValue * val)
|
||||
{
|
||||
size_t sz = DOMAIN_NAME_MAX_SIZE;
|
||||
if (cbor_value_get_type(val) != CborTextStringType)
|
||||
{
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
int ret = cbor_value_copy_text_string(val, (char*)rp->id, &sz, NULL);
|
||||
if (ret == CborErrorOutOfMemory)
|
||||
{
|
||||
@ -413,7 +473,7 @@ uint8_t parse_rp(struct rpId * rp, CborValue * val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv)
|
||||
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
|
||||
{
|
||||
size_t sz, map_length;
|
||||
char key[8];
|
||||
@ -463,21 +523,27 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv)
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
|
||||
if (strcmp(key, "rk") == 0)
|
||||
if (strncmp(key, "rk",2) == 0)
|
||||
{
|
||||
ret = cbor_value_get_boolean(&map, &b);
|
||||
check_ret(ret);
|
||||
*rk = b;
|
||||
}
|
||||
else if (strcmp(key, "uv") == 0)
|
||||
else if (strncmp(key, "uv",2) == 0)
|
||||
{
|
||||
ret = cbor_value_get_boolean(&map, &b);
|
||||
check_ret(ret);
|
||||
*uv = b;
|
||||
}
|
||||
else if (strncmp(key, "up",2) == 0)
|
||||
{
|
||||
ret = cbor_value_get_boolean(&map, &b);
|
||||
check_ret(ret);
|
||||
*up = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_PARSE,"ignoring key %s for option map\n", key);
|
||||
printf2(TAG_PARSE,"ignoring option specified %s\n", key);
|
||||
}
|
||||
|
||||
|
||||
@ -576,27 +642,30 @@ 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 = parse_verify_exclude_list(&map);
|
||||
check_ret(ret);
|
||||
|
||||
ret = cbor_value_enter_container(&map, &MC->excludeList);
|
||||
check_ret(ret);
|
||||
|
||||
ret = cbor_value_get_array_length(&map, &MC->excludeListSize);
|
||||
check_ret(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
|
||||
|
||||
printf1(TAG_MC,"CTAP_excludeList done\n");
|
||||
break;
|
||||
case MC_extensions:
|
||||
printf1(TAG_MC,"CTAP_extensions\n");
|
||||
type = cbor_value_get_type(&map);
|
||||
if (type != CborMapType)
|
||||
{
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
break;
|
||||
|
||||
case MC_options:
|
||||
printf1(TAG_MC,"CTAP_options\n");
|
||||
ret = parse_options(&map, &MC->rk, &MC->uv);
|
||||
ret = parse_options(&map, &MC->rk, &MC->uv, &MC->up);
|
||||
check_retr(ret);
|
||||
break;
|
||||
case MC_pinAuth:
|
||||
@ -661,8 +730,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
||||
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential, &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?
|
||||
printf2(TAG_ERR,"Ignoring 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);
|
||||
@ -677,13 +746,14 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
||||
buflen = sizeof(type);
|
||||
cbor_value_copy_text_string(&val, type, &buflen, NULL);
|
||||
|
||||
if (strcmp(type, "public-key") == 0)
|
||||
if (strncmp(type, "public-key",11) == 0)
|
||||
{
|
||||
cred->type = PUB_KEY_CRED_PUB_KEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
cred->type = PUB_KEY_CRED_UNKNOWN;
|
||||
printf1(TAG_RED, "Unknown type: %s\r\n", type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -783,6 +853,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
|
||||
ret = parse_fixed_byte_string(&map, GA->clientDataHash, CLIENT_DATA_HASH_SIZE);
|
||||
check_retr(ret);
|
||||
GA->clientDataHashPresent = 1;
|
||||
|
||||
printf1(TAG_GA," "); dump_hex1(TAG_GA, GA->clientDataHash, 32);
|
||||
break;
|
||||
@ -796,10 +867,9 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
case GA_allowList:
|
||||
printf1(TAG_GA,"GA_allowList\n");
|
||||
ret = parse_allow_list(GA, &map);
|
||||
if (ret == 0)
|
||||
{
|
||||
check_ret(ret);
|
||||
GA->allowListPresent = 1;
|
||||
|
||||
}
|
||||
break;
|
||||
case GA_extensions:
|
||||
printf1(TAG_GA,"GA_extensions\n");
|
||||
@ -807,7 +877,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
|
||||
case GA_options:
|
||||
printf1(TAG_GA,"CTAP_options\n");
|
||||
ret = parse_options(&map, &GA->rk, &GA->uv);
|
||||
ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up);
|
||||
check_retr(ret);
|
||||
break;
|
||||
case GA_pinAuth:
|
||||
@ -1033,10 +1103,11 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
|
||||
{
|
||||
ret = cbor_value_calculate_string_length(&map, &sz);
|
||||
check_ret(ret);
|
||||
if (sz > NEW_PIN_ENC_MAX_SIZE)
|
||||
if (sz > NEW_PIN_ENC_MAX_SIZE || sz < NEW_PIN_ENC_MIN_SIZE)
|
||||
{
|
||||
return CTAP1_ERR_OTHER;
|
||||
return CTAP2_ERR_PIN_POLICY_VIOLATION;
|
||||
}
|
||||
|
||||
CP->newPinEncSize = sz;
|
||||
sz = NEW_PIN_ENC_MAX_SIZE;
|
||||
ret = cbor_value_copy_byte_string(&map, CP->newPinEnc, &sz, NULL);
|
||||
@ -1078,5 +1149,3 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val);
|
||||
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len);
|
||||
uint8_t parse_rp_id(struct rpId * rp, CborValue * val);
|
||||
uint8_t parse_rp(struct rpId * rp, CborValue * val);
|
||||
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv);
|
||||
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up);
|
||||
|
||||
uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it);
|
||||
uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv);
|
||||
|
180
fido2/ctaphid.c
180
fido2/ctaphid.c
@ -43,6 +43,8 @@ typedef enum
|
||||
EMPTY = 0,
|
||||
BUFFERING,
|
||||
BUFFERED,
|
||||
HID_ERROR,
|
||||
HID_IGNORE,
|
||||
} CTAP_BUFFER_STATE;
|
||||
|
||||
|
||||
@ -341,7 +343,7 @@ static void send_init_response(uint32_t oldcid, uint32_t newcid, uint8_t * nonce
|
||||
|
||||
memmove(init_resp.nonce, nonce, 8);
|
||||
init_resp.cid = newcid;
|
||||
init_resp.protocol_version = 0;//?
|
||||
init_resp.protocol_version = CTAPHID_PROTOCOL_VERSION;
|
||||
init_resp.version_major = 0;//?
|
||||
init_resp.version_minor = 0;//?
|
||||
init_resp.build_version = 0;//?
|
||||
@ -367,8 +369,21 @@ void ctaphid_check_timeouts()
|
||||
|
||||
}
|
||||
|
||||
void ctaphid_update_status(int8_t status)
|
||||
{
|
||||
CTAPHID_WRITE_BUFFER wb;
|
||||
printf1(TAG_HID, "Send device update %d!\n",status);
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
|
||||
void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
wb.cid = buffer_cid();
|
||||
wb.cmd = CTAPHID_KEEPALIVE;
|
||||
wb.bcnt = 1;
|
||||
|
||||
ctaphid_write(&wb, &status, 1);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
}
|
||||
|
||||
static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * cid, int * len)
|
||||
{
|
||||
CTAPHID_PACKET * pkt = (CTAPHID_PACKET *)(pkt_raw);
|
||||
|
||||
@ -378,29 +393,25 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
if (!is_cont_pkt(pkt)) printf1(TAG_HID, " length: %d\n", ctaphid_packet_len(pkt));
|
||||
|
||||
int ret;
|
||||
uint8_t status;
|
||||
uint32_t oldcid;
|
||||
uint32_t newcid;
|
||||
static CTAPHID_WRITE_BUFFER wb;
|
||||
uint32_t active_cid;
|
||||
uint32_t t1,t2;
|
||||
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
|
||||
*cid = pkt->cid;
|
||||
|
||||
if (is_init_pkt(pkt))
|
||||
{
|
||||
if (ctaphid_packet_len(pkt) != 8)
|
||||
{
|
||||
printf2(TAG_ERR, "Error,invalid length field for init packet\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_INVALID_LENGTH;
|
||||
return HID_ERROR;
|
||||
}
|
||||
if (pkt->cid == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, invalid cid 0\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_CHANNEL);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_INVALID_CHANNEL;
|
||||
return HID_ERROR;
|
||||
}
|
||||
|
||||
ctaphid_init();
|
||||
@ -426,21 +437,21 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
if (ret == -1)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, not enough memory for new CID. return BUSY.\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_CHANNEL_BUSY;
|
||||
return HID_ERROR;
|
||||
}
|
||||
send_init_response(oldcid, newcid, pkt->pkt.init.payload);
|
||||
cid_del(newcid);
|
||||
|
||||
return;
|
||||
return HID_IGNORE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if matches existing CID
|
||||
if (pkt->cid == CTAPHID_BROADCAST_CID)
|
||||
{
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_CHANNEL);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_INVALID_CHANNEL;
|
||||
return HID_ERROR;
|
||||
}
|
||||
if (cid_exists(pkt->cid))
|
||||
{
|
||||
@ -450,14 +461,14 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
{
|
||||
printf2(TAG_ERR,"INVALID_SEQ\n");
|
||||
printf2(TAG_ERR,"Have %d/%d bytes\n", ctap_buffer_offset, ctap_buffer_bcnt);
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_SEQ);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_INVALID_SEQ;
|
||||
return HID_ERROR;
|
||||
}
|
||||
else if (pkt->cid != buffer_cid())
|
||||
{
|
||||
printf2(TAG_ERR,"BUSY with %08x\n", buffer_cid());
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_CHANNEL_BUSY;
|
||||
return HID_ERROR;
|
||||
}
|
||||
}
|
||||
if (! is_cont_pkt(pkt))
|
||||
@ -465,8 +476,8 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
|
||||
if (ctaphid_packet_len(pkt) > CTAPHID_BUFFER_SIZE)
|
||||
{
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_INVALID_LENGTH;
|
||||
return HID_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -474,14 +485,14 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
if (buffer_status() == EMPTY || pkt->cid != buffer_cid())
|
||||
{
|
||||
printf2(TAG_ERR,"ignoring random cont packet\n");
|
||||
return;
|
||||
return HID_IGNORE;
|
||||
}
|
||||
}
|
||||
if (buffer_packet(pkt) == SEQUENCE_ERROR)
|
||||
{
|
||||
printf2(TAG_ERR,"Buffering sequence error\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_SEQ);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_INVALID_SEQ;
|
||||
return HID_ERROR;
|
||||
}
|
||||
ret = cid_refresh(pkt->cid);
|
||||
if (ret != 0)
|
||||
@ -489,35 +500,63 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
printf2(TAG_ERR,"Error, refresh cid failed\n");
|
||||
exit(1);
|
||||
}
|
||||
active_cid = pkt->cid;
|
||||
}
|
||||
else if (is_cont_pkt(pkt))
|
||||
{
|
||||
printf2(TAG_ERR,"ignoring unwarranted cont packet\n");
|
||||
|
||||
// Ignore
|
||||
return;
|
||||
return HID_IGNORE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR,"BUSY\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
*cmd = CTAP1_ERR_CHANNEL_BUSY;
|
||||
return HID_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
*len = buffer_len();
|
||||
*cmd = buffer_cmd();
|
||||
return buffer_status();
|
||||
}
|
||||
|
||||
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint32_t cid;
|
||||
int len;
|
||||
int status;
|
||||
|
||||
switch(buffer_status())
|
||||
static uint8_t is_busy = 0;
|
||||
static CTAPHID_WRITE_BUFFER wb;
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
|
||||
uint32_t t1,t2;
|
||||
|
||||
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
|
||||
|
||||
if (bufstatus == HID_IGNORE)
|
||||
{
|
||||
case BUFFERING:
|
||||
printf1(TAG_HID,"BUFFERING\n");
|
||||
active_cid_timestamp = millis();
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case EMPTY:
|
||||
printf1(TAG_HID,"empty buffer!\n");
|
||||
case BUFFERED:
|
||||
switch(buffer_cmd())
|
||||
if (bufstatus == HID_ERROR)
|
||||
{
|
||||
cid_del(cid);
|
||||
buffer_reset();
|
||||
ctaphid_send_error(cid, cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bufstatus == BUFFERING)
|
||||
{
|
||||
active_cid_timestamp = millis();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
|
||||
case CTAPHID_INIT:
|
||||
@ -529,11 +568,11 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
printf1(TAG_HID,"CTAPHID_PING\n");
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = active_cid;
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_PING;
|
||||
wb.bcnt = buffer_len();
|
||||
wb.bcnt = len;
|
||||
t1 = millis();
|
||||
ctaphid_write(&wb, ctap_buffer, buffer_len());
|
||||
ctaphid_write(&wb, ctap_buffer, len);
|
||||
ctaphid_write(&wb, NULL,0);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"PING writeback: %d ms\n",(uint32_t)(t2-t1));
|
||||
@ -545,7 +584,7 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
|
||||
wb.cid = active_cid;
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_WINK;
|
||||
|
||||
ctaphid_write(&wb,NULL,0);
|
||||
@ -555,18 +594,25 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
#ifndef DISABLE_CTAPHID_CBOR
|
||||
case CTAPHID_CBOR:
|
||||
printf1(TAG_HID,"CTAPHID_CBOR\n");
|
||||
if (buffer_len() == 0)
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error,invalid 0 length field for cbor packet\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_busy)
|
||||
{
|
||||
printf1(TAG_HID,"Channel busy for CBOR\n");
|
||||
ctaphid_send_error(cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return 0;
|
||||
}
|
||||
is_busy = 1;
|
||||
ctap_response_init(&ctap_resp);
|
||||
status = ctap_request(ctap_buffer, buffer_len(), &ctap_resp);
|
||||
status = ctap_request(ctap_buffer, len, &ctap_resp);
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = active_cid;
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_CBOR;
|
||||
wb.bcnt = (ctap_resp.length+1);
|
||||
|
||||
@ -577,45 +623,51 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"CBOR writeback: %d ms\n",(uint32_t)(t2-t1));
|
||||
is_busy = 0;
|
||||
break;
|
||||
#endif
|
||||
case CTAPHID_MSG:
|
||||
|
||||
printf1(TAG_HID,"CTAPHID_MSG\n");
|
||||
if (buffer_len() == 0)
|
||||
if (len == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error,invalid 0 length field for MSG/U2F packet\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_busy)
|
||||
{
|
||||
printf1(TAG_HID,"Channel busy for MSG\n");
|
||||
ctaphid_send_error(cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return 0;
|
||||
}
|
||||
is_busy = 1;
|
||||
ctap_response_init(&ctap_resp);
|
||||
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = active_cid;
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_MSG;
|
||||
wb.bcnt = (ctap_resp.length);
|
||||
|
||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
is_busy = 0;
|
||||
break;
|
||||
case CTAPHID_CANCEL:
|
||||
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
||||
is_busy = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_COMMAND);
|
||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
||||
break;
|
||||
}
|
||||
cid_del(buffer_cid());
|
||||
cid_del(cid);
|
||||
buffer_reset();
|
||||
break;
|
||||
|
||||
default:
|
||||
printf2(TAG_ERR,"invalid buffer state; abort\n");
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_HID,"\n");
|
||||
if (!is_busy) return cmd;
|
||||
else return 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define CTAPHID_CBOR (TYPE_INIT | 0x10)
|
||||
#define CTAPHID_CANCEL (TYPE_INIT | 0x11)
|
||||
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
||||
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b)
|
||||
|
||||
#define ERR_INVALID_CMD 0x01
|
||||
#define ERR_INVALID_PAR 0x02
|
||||
@ -43,6 +44,11 @@
|
||||
#define ERR_MSG_TIMEOUT 0x05
|
||||
#define ERR_CHANNEL_BUSY 0x06
|
||||
|
||||
#define CTAPHID_PROTOCOL_VERSION 2
|
||||
|
||||
#define CTAPHID_STATUS_IDLE 0
|
||||
#define CTAPHID_STATUS_PROCESSING 1
|
||||
#define CTAPHID_STATUS_UPNEEDED 2
|
||||
|
||||
#define CTAPHID_INIT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-7)
|
||||
#define CTAPHID_CONT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-5)
|
||||
@ -91,10 +97,12 @@ typedef struct
|
||||
|
||||
void ctaphid_init();
|
||||
|
||||
void ctaphid_handle_packet(uint8_t * pkt_raw);
|
||||
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw);
|
||||
|
||||
void ctaphid_check_timeouts();
|
||||
|
||||
void ctaphid_update_status(int8_t status);
|
||||
|
||||
|
||||
#define ctaphid_packet_len(pkt) ((uint16_t)((pkt)->pkt.init.bcnth << 8) | ((pkt)->pkt.init.bcntl))
|
||||
|
||||
|
@ -56,8 +56,12 @@ void authenticator_write_state(AuthenticatorState *, int backup);
|
||||
// Called each main loop. Doesn't need to do anything.
|
||||
void device_manage();
|
||||
|
||||
// sets status that's uses for sending status updates ~100ms.
|
||||
// A timer should be set up to call `ctaphid_update_status`
|
||||
void device_set_status(int status);
|
||||
|
||||
// Test for user presence
|
||||
// Return 1 for user is present, 0 user not present
|
||||
// Return 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||
extern int ctap_user_presence_test();
|
||||
|
||||
// Generate @num bytes of random numbers to @dest
|
||||
|
27
fido2/main.c
27
fido2/main.c
@ -45,20 +45,20 @@ int main(int argc, char * argv[])
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
TAG_GEN|
|
||||
/*TAG_MC |*/
|
||||
/*TAG_GA |*/
|
||||
TAG_WALLET |
|
||||
// TAG_GEN|
|
||||
// TAG_MC |
|
||||
// TAG_GA |
|
||||
// TAG_WALLET |
|
||||
TAG_STOR |
|
||||
/*TAG_CP |*/
|
||||
// TAG_CP |
|
||||
TAG_CTAP|
|
||||
// TAG_HID|
|
||||
// TAG_HID|
|
||||
/*TAG_U2F|*/
|
||||
/*TAG_PARSE |*/
|
||||
// TAG_TIME|
|
||||
/*TAG_DUMP|*/
|
||||
/*TAG_GREEN|*/
|
||||
/*TAG_RED|*/
|
||||
// TAG_PARSE |
|
||||
//TAG_TIME|
|
||||
// TAG_DUMP|
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_ERR
|
||||
);
|
||||
|
||||
@ -89,12 +89,11 @@ int main(int argc, char * argv[])
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
printf1(TAG_DUMP,"%d>> ",count++); dump_hex1(TAG_DUMP, hidmsg,sizeof(hidmsg));
|
||||
t2 = millis();
|
||||
ctaphid_handle_packet(hidmsg);
|
||||
accum += millis() - t2;
|
||||
printf1(TAG_TIME,"accum: %d\n", (uint32_t)accum);
|
||||
printf1(TAG_TIME,"dt: %d\n", t2 - dt);
|
||||
// printf1(TAG_TIME,"accum: %d\n", (uint32_t)accum);
|
||||
// printf1(TAG_TIME,"dt: %d\n", t2 - dt);
|
||||
dt = t2;
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
}
|
||||
|
@ -39,8 +39,9 @@ typedef struct
|
||||
// Pin information
|
||||
uint8_t is_initialized;
|
||||
uint8_t is_pin_set;
|
||||
uint8_t pin_code[NEW_PIN_ENC_MAX_SIZE];
|
||||
uint8_t remaining_tries;
|
||||
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
|
||||
int pin_code_length;
|
||||
int8_t remaining_tries;
|
||||
|
||||
uint16_t key_lens[MAX_KEYS];
|
||||
uint8_t key_space[KEY_SPACE_BYTES];
|
||||
|
@ -40,6 +40,7 @@ HW=-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
|
||||
CHIP=STM32L442xx
|
||||
|
||||
DEFINES = -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER
|
||||
# DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1
|
||||
|
||||
CFLAGS=$(INC) -c $(DEFINES) -Os -Wall -fdata-sections -ffunction-sections $(HW)
|
||||
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys
|
||||
@ -68,6 +69,7 @@ clean:
|
||||
rm -f *.o src/*.o src/*.elf *.elf *.hex $(OBJ)
|
||||
|
||||
flash: $(TARGET).hex
|
||||
STM32_Programmer_CLI -c port=SWD -halt -e all
|
||||
STM32_Programmer_CLI -c port=SWD -halt -d $(TARGET).hex -rst
|
||||
sleep 0.5
|
||||
python dfuse-tool/dfuse-tool.py --leave
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util.h"
|
||||
#include "fifo.h"
|
||||
#include "log.h"
|
||||
#include "ctaphid.h"
|
||||
|
||||
|
||||
#define PAGE_SIZE 2048
|
||||
@ -34,18 +35,28 @@
|
||||
|
||||
#define AUTH_WORD_ADDR (flash_addr(APPLICATION_END_PAGE)-4)
|
||||
|
||||
uint32_t __65_seconds = 0;
|
||||
uint32_t __90_ms = CTAPHID_STATUS_IDLE;
|
||||
uint32_t __device_status = 0;
|
||||
uint32_t __last_update = 0;
|
||||
extern PCD_HandleTypeDef hpcd;
|
||||
|
||||
#define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||
|
||||
// Timer6 overflow handler
|
||||
// Timer6 overflow handler. happens every ~90ms.
|
||||
void TIM6_DAC_IRQHandler()
|
||||
{
|
||||
// timer is only 16 bits, so roll it over here
|
||||
TIM6->SR = 0;
|
||||
__65_seconds += 1;
|
||||
__90_ms += 1;
|
||||
if ((millis() - __last_update) > 5)
|
||||
{
|
||||
if (__device_status != CTAPHID_STATUS_IDLE)
|
||||
{
|
||||
ctaphid_update_status(__device_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Global USB interrupt handler
|
||||
void USB_IRQHandler(void)
|
||||
{
|
||||
@ -55,10 +66,21 @@ void USB_IRQHandler(void)
|
||||
|
||||
uint32_t millis()
|
||||
{
|
||||
return (((uint32_t)TIM6->CNT) | (__65_seconds<<16));
|
||||
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
||||
}
|
||||
|
||||
void device_set_status(int status)
|
||||
{
|
||||
__disable_irq();
|
||||
__last_update = millis();
|
||||
__enable_irq();
|
||||
|
||||
if (status != CTAPHID_STATUS_IDLE && __device_status != status)
|
||||
{
|
||||
ctaphid_update_status(status);
|
||||
}
|
||||
__device_status = status;
|
||||
}
|
||||
|
||||
|
||||
void delay(uint32_t ms)
|
||||
@ -75,7 +97,6 @@ void device_init()
|
||||
LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP);
|
||||
|
||||
printf1(TAG_GEN,"hello solo\r\n");
|
||||
|
||||
}
|
||||
|
||||
void usbhid_init()
|
||||
@ -86,7 +107,6 @@ 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);
|
||||
@ -188,9 +208,11 @@ uint32_t ctap_atomic_count(int sel)
|
||||
int offset = 0;
|
||||
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
||||
uint32_t erases = *(uint32_t *)flash_addr(COUNTER2_PAGE);
|
||||
static uint32_t sc = 0;
|
||||
if (erases == 0xffffffff)
|
||||
{
|
||||
erases = 1;
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||
}
|
||||
|
||||
@ -220,44 +242,54 @@ uint32_t ctap_atomic_count(int sel)
|
||||
|
||||
if (!lastc) // Happens on initialization as well.
|
||||
{
|
||||
printf("warning, power interrupted during previous count. Restoring.\r\n");
|
||||
printf2(TAG_ERR,"warning, power interrupted during previous count. Restoring. lastc==%lu, erases=%lu, offset=%d\r\n", lastc,erases,offset);
|
||||
// there are 32 counts per page
|
||||
lastc = erases * 32;
|
||||
lastc = erases * 256 + 1;
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
flash_write(flash_addr(COUNTER1_PAGE), (uint8_t*)&lastc, 4);
|
||||
|
||||
erases++;
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||
return lastc;
|
||||
}
|
||||
|
||||
lastc++;
|
||||
|
||||
if (lastc/32 > erases)
|
||||
if (lastc/256 > erases)
|
||||
{
|
||||
printf("warning, power interrupted, erases mark, restoring\r\n");
|
||||
erases = lastc/32 + 1;
|
||||
printf2(TAG_ERR,"warning, power interrupted, erases mark, restoring. lastc==%lu, erases=%lu\r\n", lastc,erases);
|
||||
erases = lastc/256;
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||
}
|
||||
|
||||
if (offset == PAGE_SIZE/4)
|
||||
{
|
||||
if (lastc/32 > erases)
|
||||
if (lastc/256 > erases)
|
||||
{
|
||||
printf("warning, power interrupted, erases mark, restoring\r\n");
|
||||
printf2(TAG_ERR,"warning, power interrupted, erases mark, restoring lastc==%lu, erases=%lu\r\n", lastc,erases);
|
||||
}
|
||||
erases = lastc/32 + 1;
|
||||
erases = lastc/256 + 1;
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
flash_write(flash_addr(COUNTER1_PAGE) + offset * 4, (uint8_t*)&lastc, 4);
|
||||
|
||||
if (lastc == sc)
|
||||
{
|
||||
printf1(TAG_RED,"no count detected: lastc==%lu, erases=%lu, offset=%d\r\n", lastc,erases,offset);
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
|
||||
sc = lastc;
|
||||
|
||||
return lastc;
|
||||
}
|
||||
|
||||
@ -284,10 +316,38 @@ void device_manage()
|
||||
#endif
|
||||
}
|
||||
|
||||
static int handle_packets()
|
||||
{
|
||||
static uint8_t hidmsg[HID_PACKET_SIZE];
|
||||
memset(hidmsg,0, sizeof(hidmsg));
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
if ( ctaphid_handle_packet(hidmsg) == CTAPHID_CANCEL)
|
||||
{
|
||||
printf1(TAG_GREEN, "CANCEL!\r\n");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctap_user_presence_test()
|
||||
{
|
||||
int oldstatus = __device_status;
|
||||
int ret;
|
||||
#if SKIP_BUTTON_CHECK
|
||||
return 1;
|
||||
int i=500;
|
||||
while(i--)
|
||||
{
|
||||
delay(1);
|
||||
ret = handle_packets();
|
||||
if (ret) return ret;
|
||||
}
|
||||
goto done;
|
||||
#endif
|
||||
|
||||
uint32_t t1 = millis();
|
||||
@ -297,15 +357,17 @@ int ctap_user_presence_test()
|
||||
delay(3000);
|
||||
led_rgb(0x001040);
|
||||
delay(50);
|
||||
return 1;
|
||||
goto done;
|
||||
#endif
|
||||
while (IS_BUTTON_PRESSED())
|
||||
{
|
||||
if (t1 + 5000 < millis())
|
||||
{
|
||||
printf1(TAG_GEN,"Button not pressed\n");
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
ret = handle_packets();
|
||||
if (ret) return ret;
|
||||
}
|
||||
|
||||
t1 = millis();
|
||||
@ -314,11 +376,13 @@ do
|
||||
{
|
||||
if (t1 + 5000 < millis())
|
||||
{
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
if (! IS_BUTTON_PRESSED())
|
||||
continue;
|
||||
delay(1);
|
||||
ret = handle_packets();
|
||||
if (ret) return ret;
|
||||
}
|
||||
while (! IS_BUTTON_PRESSED());
|
||||
|
||||
@ -326,7 +390,11 @@ led_rgb(0x001040);
|
||||
|
||||
delay(50);
|
||||
|
||||
done:
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
FIFO_CREATE(debug,1024,1)
|
||||
|
||||
FIFO_CREATE(hidmsg,100,100)
|
||||
FIFO_CREATE(hidmsg,100,64)
|
||||
|
||||
#if TEST_FIFO
|
||||
FIFO_CREATE(test,10,100)
|
||||
@ -24,23 +24,25 @@ void fifo_test()
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||
ret = fifo_test_add(data[i]);
|
||||
printf("%d\r\n",i);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("fifo_test_add fail\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||
ret = fifo_test_take(verif[i]);
|
||||
printf("%d\r\n",i );
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("fifo_test_take fail\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (memcmp(verif[i], data[i], 100) != 0)
|
||||
@ -48,17 +50,18 @@ void fifo_test()
|
||||
printf("fifo_test_take result fail\r\n");
|
||||
dump_hex(data[i],100);
|
||||
dump_hex(verif[i],100);
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||
ret = fifo_test_add(data[i]);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("fifo_test_add 2 fail\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,22 +69,25 @@ void fifo_test()
|
||||
if (ret == 0)
|
||||
{
|
||||
printf("fifo_test_add should have failed\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||
ret = fifo_test_take(verif[i]);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("fifo_test_take fail\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (memcmp(verif[i], data[i], 100) != 0)
|
||||
{
|
||||
printf("fifo_test_take result fail\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,12 +95,12 @@ void fifo_test()
|
||||
if (ret == 0)
|
||||
{
|
||||
printf("fifo_test_take should have failed\r\n");
|
||||
goto end;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printf("test pass!\r\n");
|
||||
|
||||
end:
|
||||
return ;
|
||||
fail:
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
#include "app.h"
|
||||
|
||||
#ifndef TEST_FIFO
|
||||
#define TEST_FIFO 0
|
||||
#endif
|
||||
|
||||
#define FIFO_CREATE(NAME,LENGTH,BYTES)\
|
||||
int __##NAME##_WRITE_PTR = 0;\
|
||||
@ -13,7 +15,7 @@ static uint8_t __##NAME##_WRITE_BUF[BYTES * LENGTH];\
|
||||
\
|
||||
int fifo_##NAME##_add(uint8_t * c)\
|
||||
{\
|
||||
if (__##NAME##_WRITE_PTR != __##NAME##_READ_PTR || !__##NAME##_SIZE)\
|
||||
if (__##NAME##_SIZE < LENGTH)\
|
||||
{\
|
||||
memmove(__##NAME##_WRITE_BUF + __##NAME##_WRITE_PTR * BYTES, c, BYTES);\
|
||||
__##NAME##_WRITE_PTR ++;\
|
||||
@ -28,7 +30,7 @@ int fifo_##NAME##_add(uint8_t * c)\
|
||||
int fifo_##NAME##_take(uint8_t * c)\
|
||||
{\
|
||||
memmove(c, __##NAME##_WRITE_BUF + __##NAME##_READ_PTR * BYTES, BYTES);\
|
||||
if (__##NAME##_READ_PTR != __##NAME##_WRITE_PTR || __##NAME##_SIZE)\
|
||||
if ( __##NAME##_SIZE > 0)\
|
||||
{\
|
||||
__##NAME##_READ_PTR ++;\
|
||||
if (__##NAME##_READ_PTR >= LENGTH)\
|
||||
@ -43,17 +45,27 @@ uint32_t fifo_##NAME##_size()\
|
||||
{\
|
||||
return (__##NAME##_SIZE);\
|
||||
}\
|
||||
uint32_t fifo_##NAME##_rhead()\
|
||||
{\
|
||||
return (__##NAME##_READ_PTR);\
|
||||
}\
|
||||
uint32_t fifo_##NAME##_whead()\
|
||||
{\
|
||||
return (__##NAME##_WRITE_PTR);\
|
||||
}\
|
||||
|
||||
#define FIFO_CREATE_H(NAME,LENGTH,BYTES)\
|
||||
#define FIFO_CREATE_H(NAME)\
|
||||
int fifo_##NAME##_add(uint8_t * c);\
|
||||
int fifo_##NAME##_take(uint8_t * c);\
|
||||
uint32_t fifo_##NAME##_size();\
|
||||
uint32_t fifo_##NAME##_rhead();\
|
||||
uint32_t fifo_##NAME##_whead();\
|
||||
|
||||
FIFO_CREATE_H(hidmsg,10,64)
|
||||
FIFO_CREATE_H(hidmsg)
|
||||
|
||||
FIFO_CREATE_H(debug,1024,1)
|
||||
FIFO_CREATE_H(debug)
|
||||
|
||||
FIFO_CREATE_H(test,100,100)
|
||||
FIFO_CREATE_H(test)
|
||||
|
||||
void fifo_test();
|
||||
|
||||
|
@ -18,6 +18,7 @@ static void flash_unlock()
|
||||
void flash_erase_page(uint8_t page)
|
||||
{
|
||||
__disable_irq();
|
||||
flash_unlock();
|
||||
// Wait if flash is busy
|
||||
while (FLASH->SR & (1<<16))
|
||||
;
|
||||
@ -71,9 +72,10 @@ void flash_write(uint32_t addr, uint8_t * data, size_t sz)
|
||||
{
|
||||
int i;
|
||||
uint8_t buf[8];
|
||||
flash_unlock();
|
||||
|
||||
// dword align
|
||||
addr &= ~(0x7);
|
||||
addr &= ~(0x07);
|
||||
|
||||
for(i = 0; i < sz; i+=8)
|
||||
{
|
||||
|
@ -337,10 +337,10 @@ static void MX_TIM6_Init(void)
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
|
||||
|
||||
// 48 MHz sys clock --> 6 MHz timer clock
|
||||
// 6 MHz / 6000 == 1000 Hz
|
||||
// 48 MHz / 48000 == 1000 Hz
|
||||
TIM_InitStruct.Prescaler = 48000;
|
||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||
TIM_InitStruct.Autoreload = 0xffff;
|
||||
TIM_InitStruct.Autoreload = 90;
|
||||
LL_TIM_Init(TIM6, &TIM_InitStruct);
|
||||
|
||||
LL_TIM_DisableARRPreload(TIM6);
|
||||
@ -356,6 +356,35 @@ static void MX_TIM6_Init(void)
|
||||
LL_TIM_EnableCounter(TIM6);
|
||||
}
|
||||
|
||||
/* TIM7 init function */
|
||||
// static void MX_TIM7_Init(void)
|
||||
// {
|
||||
//
|
||||
// LL_TIM_InitTypeDef TIM_InitStruct;
|
||||
//
|
||||
// /* Peripheral clock enable */
|
||||
// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
|
||||
//
|
||||
// // 48 MHz sys clock --> 6 MHz timer clock
|
||||
// // 6 MHz / 6000 == 1000 Hz
|
||||
// TIM_InitStruct.Prescaler = 48000;
|
||||
// TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||
// TIM_InitStruct.Autoreload = 0xffff;
|
||||
// LL_TIM_Init(TIM6, &TIM_InitStruct);
|
||||
//
|
||||
// LL_TIM_DisableARRPreload(TIM7);
|
||||
//
|
||||
// LL_TIM_SetTriggerOutput(TIM7, LL_TIM_TRGO_RESET);
|
||||
//
|
||||
// LL_TIM_DisableMasterSlaveMode(TIM7);
|
||||
//
|
||||
// // enable interrupt
|
||||
// TIM7->DIER |= 1;
|
||||
//
|
||||
// // Start immediately
|
||||
// LL_TIM_EnableCounter(TIM7);
|
||||
// }
|
||||
|
||||
/* RNG init function */
|
||||
static void MX_RNG_Init(void)
|
||||
{
|
||||
|
@ -27,9 +27,126 @@
|
||||
#include "device.h"
|
||||
#include "util.h"
|
||||
#include "fifo.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef TEST_SOLO_STM32
|
||||
#define Error_Handler() _Error_Handler(__FILE__,__LINE__)
|
||||
#define PAGE_SIZE 2048
|
||||
#define PAGES 128
|
||||
// Pages 119-127 are data
|
||||
#define COUNTER2_PAGE (PAGES - 4)
|
||||
#define COUNTER1_PAGE (PAGES - 3)
|
||||
#define STATE2_PAGE (PAGES - 2)
|
||||
#define STATE1_PAGE (PAGES - 1)
|
||||
|
||||
void test_atomic_counter()
|
||||
{
|
||||
// flash_erase_page(COUNTER1_PAGE);
|
||||
// flash_erase_page(COUNTER2_PAGE);
|
||||
int i;
|
||||
uint32_t c0 = ctap_atomic_count(0);
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
uint32_t c1 = ctap_atomic_count(0);
|
||||
if (c1 <= (c0 ))
|
||||
{
|
||||
printf("error, count failed %lu <= %lu\r\n",c1,c0);
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
printf("%lu\r\n", c1);
|
||||
c0 = c1;
|
||||
}
|
||||
|
||||
printf("test faults\r\n");
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER2_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
printf("%lu\r\n", ctap_atomic_count(0));
|
||||
|
||||
flash_erase_page(COUNTER1_PAGE);
|
||||
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@ -41,7 +158,24 @@ int main(void)
|
||||
uint8_t hidbuf[HID_PACKET_SIZE];
|
||||
|
||||
hw_init();
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
// TAG_GEN|
|
||||
TAG_MC |
|
||||
TAG_GA |
|
||||
// TAG_WALLET |
|
||||
TAG_STOR |
|
||||
TAG_CP |
|
||||
TAG_CTAP|
|
||||
// TAG_HID|
|
||||
/*TAG_U2F|*/
|
||||
TAG_PARSE |
|
||||
//TAG_TIME|
|
||||
// TAG_DUMP|
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_ERR
|
||||
);
|
||||
printf("hello solo\r\n");
|
||||
|
||||
// Test flash
|
||||
@ -50,6 +184,24 @@ int main(void)
|
||||
memmove(buf,(uint8_t*)flash_addr(60),sizeof(str));
|
||||
printf("flash: \"%s\"\r\n", buf);
|
||||
|
||||
// test_atomic_counter();
|
||||
|
||||
|
||||
// Note that 4 byte aligned addresses won't get written correctly.
|
||||
flash_erase_page(60);
|
||||
uint32_t count = 0;
|
||||
flash_write(flash_addr(60) + 0,(uint8_t*)&count,4);
|
||||
count += 1;
|
||||
flash_write(flash_addr(60) + 4,(uint8_t*)&count,4);
|
||||
count += 1;
|
||||
flash_write(flash_addr(60) + 8,(uint8_t*)&count,4);
|
||||
count += 1;
|
||||
flash_write(flash_addr(60) + 12,(uint8_t*)&count,4);
|
||||
count += 1;
|
||||
flash_write(flash_addr(60) + 16,(uint8_t*)&count,4);
|
||||
dump_hex((uint8_t *)flash_addr(60), 20);
|
||||
|
||||
|
||||
// test timer
|
||||
uint32_t t1 = millis();
|
||||
delay(100);
|
||||
@ -63,7 +215,7 @@ int main(void)
|
||||
|
||||
/*// Test PWM + weighting of RGB*/
|
||||
/*led_test_colors();*/
|
||||
|
||||
fifo_test();
|
||||
|
||||
|
||||
uint32_t t0 = millis();
|
||||
@ -91,15 +243,9 @@ int main(void)
|
||||
fifo_hidmsg_take(hidbuf);
|
||||
dump_hex(hidbuf, HID_PACKET_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _Error_Handler(char *file, int line)
|
||||
{
|
||||
printf("Error: %s: %d\r\n", file, line);
|
||||
while(1)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -41,7 +41,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 240K /* Leave out 16 Kb for data */
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 238K /* Leave out 18 Kb for data */
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
||||
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||
}
|
||||
|
@ -387,13 +387,13 @@ class Tester():
|
||||
def test_u2f(self,):
|
||||
pass
|
||||
|
||||
def test_fido2_simple(self):
|
||||
def test_fido2_simple(self, pin_token=None):
|
||||
creds = []
|
||||
exclude_list = []
|
||||
rp = {'id': 'examplo.org', 'name': 'ExaRP'}
|
||||
user = {'id': b'usee_od', 'name': 'AB User'}
|
||||
challenge = 'Y2hhbGxlbmdl'
|
||||
PIN = None
|
||||
PIN = pin_token
|
||||
|
||||
fake_id1 = array.array('B',[randint(0,255) for i in range(0,150)]).tostring()
|
||||
fake_id2 = array.array('B',[randint(0,255) for i in range(0,73)]).tostring()
|
||||
@ -488,6 +488,7 @@ class Tester():
|
||||
attest.verify(data.hash)
|
||||
cred = attest.auth_data.credential_data
|
||||
creds.append(cred)
|
||||
print(cred)
|
||||
print('PASS')
|
||||
|
||||
if PIN is not None:
|
||||
@ -511,14 +512,18 @@ class Tester():
|
||||
real_excl = [{'id': cred.credential_id, 'type': 'public-key'}]
|
||||
try:
|
||||
attest, data = self.client.make_credential(rp, user, challenge, pin = PIN, exclude_list = exclude_list + real_excl)
|
||||
raise RuntimeError('Exclude list did not return expected error')
|
||||
except CtapError as e:
|
||||
assert(e.code == CtapError.ERR.CREDENTIAL_EXCLUDED)
|
||||
except ClientError as e:
|
||||
assert(e.cause.code == CtapError.ERR.CREDENTIAL_EXCLUDED)
|
||||
print('PASS')
|
||||
|
||||
print('get assertion')
|
||||
allow_list = [{'id':creds[0].credential_id, 'type': 'public-key'}]
|
||||
for i, x in enumerate(creds):
|
||||
print('get assertion %d' % i)
|
||||
allow_list = [{'id':x.credential_id, 'type': 'public-key'}]
|
||||
assertions, client_data = self.client.get_assertion(rp['id'], challenge, allow_list, pin = PIN)
|
||||
assertions[0].verify(client_data.hash, creds[0].public_key)
|
||||
assertions[0].verify(client_data.hash, x.public_key)
|
||||
print('PASS')
|
||||
|
||||
if PIN is not None:
|
||||
@ -531,11 +536,16 @@ class Tester():
|
||||
assert(e.cause.code == CtapError.ERR.PIN_INVALID)
|
||||
print('PASS')
|
||||
|
||||
|
||||
print('get multiple assertions')
|
||||
allow_list = [{'id': x.credential_id, 'type': 'public-key'} for x in creds]
|
||||
assertions, client_data = self.client.get_assertion(rp['id'], challenge, allow_list, pin = PIN)
|
||||
|
||||
for ass,cred in zip(assertions, creds):
|
||||
i += 1
|
||||
|
||||
ass.verify(client_data.hash, cred.public_key)
|
||||
print('%d verified' % i)
|
||||
print('PASS')
|
||||
|
||||
print('Reset device')
|
||||
@ -573,6 +583,20 @@ class Tester():
|
||||
assert(e.code == CtapError.ERR.PIN_INVALID)
|
||||
print('PASS')
|
||||
|
||||
print('MC using wrong pin')
|
||||
try:
|
||||
self.test_fido2_simple('abcd3');
|
||||
except CtapError as e:
|
||||
assert(e.code == CtapError.ERR.PIN_INVALID)
|
||||
except ClientError as e:
|
||||
assert(e.cause.code == CtapError.ERR.PIN_INVALID)
|
||||
print('PASS')
|
||||
|
||||
print('Reboot device and hit enter')
|
||||
input()
|
||||
self.find_device()
|
||||
self.test_fido2_simple(PIN);
|
||||
|
||||
print('Re-run make_credential and get_assertion tests with pin code')
|
||||
test(self, PIN)
|
||||
|
||||
@ -583,7 +607,6 @@ class Tester():
|
||||
print('Warning, reset failed: ', e)
|
||||
print('PASS')
|
||||
|
||||
|
||||
def test_find_brute_force():
|
||||
i = 0
|
||||
while 1:
|
||||
@ -602,6 +625,6 @@ if __name__ == '__main__':
|
||||
# t.test_hid()
|
||||
# t.test_long_ping()
|
||||
t.test_fido2()
|
||||
#test_find_brute_force()
|
||||
# test_find_brute_force()
|
||||
#t.test_fido2_simple()
|
||||
#t.test_fido2_brute_force()
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
import base64
|
||||
"""
|
||||
cbytes.py
|
||||
|
||||
@ -39,4 +40,6 @@ print()
|
||||
print('code uint8_t __attest[] = \n%s;' % c_str)
|
||||
print('const uint16_t __attest_size = sizeof(__attest)-1;')
|
||||
|
||||
|
||||
b = base64.b64encode(buf)
|
||||
print('b64: ')
|
||||
print(b)
|
||||
|
22
tools/gencert/gen_intermediate.sh
Normal file
22
tools/gencert/gen_intermediate.sh
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
keyname=interkey.pem
|
||||
certname=intercert.pem
|
||||
smallcertname=intercert.der
|
||||
curve=prime256v1
|
||||
|
||||
[[ "$#" != 2 ]] && echo "usage: $0 <signing-key> <root-ca>" && exit 1
|
||||
|
||||
# generate EC private key
|
||||
openssl ecparam -genkey -name "$curve" -out "$keyname" -rand seed.txt
|
||||
|
||||
# generate a "signing request"
|
||||
openssl req -new -key "$keyname" -out "$keyname".csr -subj "/C=US/ST=Maryland/O=Solo Keys/OU=Authenticator Attestation/CN=solokeys.com/emailAddress=hello@solokeys.com"
|
||||
|
||||
# sign the request
|
||||
openssl x509 -req -days 18250 -in "$keyname".csr -extfile v3.ext -CA "$2" -CAkey "$1" -set_serial 01 -out "$certname" -sha256
|
||||
|
||||
# convert to smaller size format DER
|
||||
openssl x509 -in $certname -outform der -out $smallcertname
|
||||
|
||||
openssl x509 -in $certname -text -noout
|
@ -6,12 +6,13 @@ smallcertname=cert.der
|
||||
curve=prime256v1
|
||||
|
||||
# generate EC private key
|
||||
openssl ecparam -genkey -name "$curve" -out "$keyname"
|
||||
openssl ecparam -genkey -name "$curve" -out "$keyname" -rand seed.txt
|
||||
# generate a "signing request"
|
||||
openssl req -new -key "$keyname" -out "$keyname".csr
|
||||
openssl req -new -key "$keyname" -out "$keyname".csr -subj "/C=US/ST=Maryland/O=Solo Keys/OU=Root CA/CN=solokeys.com/emailAddress=hello@solokeys.com"
|
||||
# self sign the request
|
||||
openssl x509 -req -days 18250 -in "$keyname".csr -signkey "$keyname" -out "$certname"
|
||||
openssl x509 -trustout -req -days 18250 -in "$keyname".csr -signkey "$keyname" -out "$certname" -sha256
|
||||
|
||||
# convert to smaller size format DER
|
||||
openssl x509 -in $certname -outform der -out $smallcertname
|
||||
|
||||
openssl x509 -in $certname -text -noout
|
||||
|
16
tools/gencert/print_x_y.py
Normal file
16
tools/gencert/print_x_y.py
Normal file
@ -0,0 +1,16 @@
|
||||
import sys
|
||||
from ecdsa import SigningKey, NIST256p
|
||||
|
||||
sk = SigningKey.from_pem(open(sys.argv[1]).read())
|
||||
|
||||
|
||||
print('Private key in various formats:')
|
||||
print()
|
||||
print([c for c in sk.to_string()])
|
||||
print()
|
||||
print(''.join(['%02x'%c for c in sk.to_string()]))
|
||||
print()
|
||||
print('"\\x' + '\\x'.join(['%02x'%c for c in sk.to_string()]) + '"')
|
||||
print()
|
||||
|
||||
|
22
tools/gencert/verify_certs.sh
Normal file
22
tools/gencert/verify_certs.sh
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
# verify that the root CA/keypair and intermediate CA/keypairs are set up correctly.
|
||||
|
||||
[[ "$#" != 4 ]] && echo "usage: $0 <inter-key> <inter-cert> <root-key> <root-cert>" && exit 1
|
||||
|
||||
ikey=$1
|
||||
icert=$2
|
||||
|
||||
rkey=$3
|
||||
rcert=$4
|
||||
|
||||
echo 'challenge $RANDOM' > chal.txt
|
||||
|
||||
# check that they are actual key pairs
|
||||
openssl dgst -sha256 -sign "$ikey" -out sig.txt chal.txt
|
||||
openssl dgst -sha256 -verify <(openssl x509 -in "$icert" -pubkey -noout) -signature sig.txt chal.txt
|
||||
|
||||
openssl dgst -sha256 -sign "$rkey" -out sig.txt chal.txt
|
||||
openssl dgst -sha256 -verify <(openssl x509 -in "$rcert" -pubkey -noout) -signature sig.txt chal.txt
|
||||
|
||||
# Check they are a chain
|
||||
openssl verify -verbose -CAfile "$rcert" "$icert"
|
Loading…
x
Reference in New Issue
Block a user