Compare commits
14 Commits
rgerganov-
...
master-old
Author | SHA1 | Date | |
---|---|---|---|
3de4d0155e
|
|||
5f9537bccc
|
|||
967e35472f
|
|||
78f7a7a979
|
|||
72063049a7
|
|||
4743fd2326
|
|||
299e91b91b | |||
cbf40f4ec7 | |||
8d93f88631 | |||
5f8a9a44fc | |||
8aa1f4ad01 | |||
04cffb6509 | |||
f002d08071 | |||
e53b83257d |
@ -1 +1 @@
|
||||
3.2.0
|
||||
4.0.0
|
||||
|
24
default.nix
Normal file
24
default.nix
Normal file
@ -0,0 +1,24 @@
|
||||
let
|
||||
pkgs = import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/20.03.tar.gz"; sha256 = "0182ys095dfx02vl2a20j1hz92dx3mfgz2a6fhn31bqlp1wa8hlq"; }) {};
|
||||
pyPackages = (python-packages: with python-packages; ([
|
||||
solo-python pytest
|
||||
] ++ (with builtins; map (d: getAttr d python-packages) (filter (d: stringLength d > 0) (pkgs.lib.splitString "\n" (builtins.readFile ./tools/requirements.txt))))));
|
||||
python-with-my-packages = pkgs.python3.withPackages pyPackages;
|
||||
src = ./.;
|
||||
in
|
||||
with pkgs; stdenv.mkDerivation {
|
||||
name = "solo";
|
||||
outputs = [ "out" ];
|
||||
src = with lib; builtins.filterSource (path: type: !(hasSuffix path "hex" || hasSuffix path "sha256")) src;
|
||||
buildInputs = [ gnumake gcc gcc-arm-embedded-8 git python-with-my-packages ];
|
||||
phases = [ "unpackPhase" "configurePhase" "buildPhase" "installPhase" ];
|
||||
installPhase = ''
|
||||
mkdir -p $out/firmware $out
|
||||
cd targets/stm32l432
|
||||
make cbor
|
||||
make build-hacker
|
||||
cp *.hex *.sha256 *.elf cubeconfig_stm32l442.ioc $out/firmware/
|
||||
'';
|
||||
keepDebugInfo = true;
|
||||
}
|
||||
|
316
fido2/ctap.c
316
fido2/ctap.c
@ -461,6 +461,10 @@ static int ctap_make_extensions(CTAP_extensions * ext, uint8_t * ext_encoder_buf
|
||||
// Generate credRandom
|
||||
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY2, 0, credRandom);
|
||||
crypto_sha256_update((uint8_t*)&ext->hmac_secret.credential->id, sizeof(CredentialId));
|
||||
// using user_verified as len means it won't be included when false
|
||||
if (getAssertionState.user_verified == 1) {
|
||||
crypto_sha256_update(&getAssertionState.user_verified, 1);
|
||||
}
|
||||
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY2, 0, credRandom);
|
||||
|
||||
// Decrypt saltEnc
|
||||
@ -565,10 +569,10 @@ static unsigned int get_credential_id_size(int type)
|
||||
return sizeof(CredentialId);
|
||||
}
|
||||
|
||||
static int ctap2_user_presence_test()
|
||||
static int ctap2_user_presence_test(uint32_t colour)
|
||||
{
|
||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||
int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||
int ret = ctap_user_presence_test_colour(CTAP2_UP_DELAY_MS, colour);
|
||||
if ( ret > 1 )
|
||||
{
|
||||
return CTAP2_ERR_PROCESSING;
|
||||
@ -586,6 +590,33 @@ static int ctap2_user_presence_test()
|
||||
return CTAP2_ERR_ACTION_TIMEOUT;
|
||||
}
|
||||
}
|
||||
static uint32_t ctap_assertion_led_colour(uint8_t * seed, uint32_t slen)
|
||||
{
|
||||
uint8_t hmac[32];
|
||||
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 32, hmac);
|
||||
crypto_sha256_hmac_final(seed, slen, hmac);
|
||||
uint32_t colour = 0;
|
||||
uint32_t backlist[] = {0x00FF00};
|
||||
int dist = 0;
|
||||
int min_dist = 50*50*3;
|
||||
for(int i=0; i<32-3 && (dist < min_dist || i == 0);i++) {
|
||||
uint8_t* rgb = &hmac[i];
|
||||
colour = ((uint32_t*) rgb)[0] & 0x0000ffffff;
|
||||
int r, g, b = 0;
|
||||
r = colour & 0x0000ff0000 >> 16;
|
||||
g = colour & 0x000000ff00 >> 8;
|
||||
b = colour & 0x00000000ff;
|
||||
for(int j=0; j < 1 && dist < min_dist; j++) {
|
||||
int br, bg, bb = 0;
|
||||
br = backlist[j] & 0x0000ff0000 >> 16;
|
||||
bg = backlist[j] & 0x000000ff00 >> 8;
|
||||
bb = backlist[j] & 0x00000000ff;
|
||||
dist = ((int) r - br)*(r - br) + ((int)g - bg)*((int)g - bg) + ((int)b - bb)*((int)b - bb);
|
||||
}
|
||||
|
||||
}
|
||||
return colour;
|
||||
}
|
||||
|
||||
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo, CTAP_extensions * extensions)
|
||||
{
|
||||
@ -616,7 +647,7 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
|
||||
int but;
|
||||
|
||||
but = ctap2_user_presence_test();
|
||||
but = ctap2_user_presence_test(ctap_assertion_led_colour(authData->head.rpIdHash, 32));
|
||||
if (CTAP2_ERR_PROCESSING == but)
|
||||
{
|
||||
authData->head.flags = (0 << 0); // User presence disabled
|
||||
@ -879,7 +910,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
}
|
||||
if (MC.pinAuthEmpty)
|
||||
{
|
||||
ret = ctap2_user_presence_test();
|
||||
ret = ctap2_user_presence_test(0);
|
||||
check_retr(ret);
|
||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||
}
|
||||
@ -924,7 +955,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
{
|
||||
if ( check_credential_metadata(&excl_cred->credential.id, MC.pinAuthPresent, 1) == 0)
|
||||
{
|
||||
ret = ctap2_user_presence_test();
|
||||
ret = ctap2_user_presence_test(0);
|
||||
check_retr(ret);
|
||||
printf1(TAG_MC, "Cred %d failed!\r\n",i);
|
||||
return CTAP2_ERR_CREDENTIAL_EXCLUDED;
|
||||
@ -1034,29 +1065,30 @@ uint8_t ctap_add_user_entity(CborEncoder * map, CTAP_userEntity * user, int is_v
|
||||
CborEncoder entity;
|
||||
int dispname = (user->name[0] != 0) && is_verified;
|
||||
int ret;
|
||||
int map_size = 1;
|
||||
|
||||
if (dispname)
|
||||
ret = cbor_encoder_create_map(map, &entity, 4);
|
||||
else
|
||||
ret = cbor_encoder_create_map(map, &entity, 1);
|
||||
{
|
||||
map_size = strlen((const char *)user->icon) > 0 ? 4 : 3;
|
||||
}
|
||||
ret = cbor_encoder_create_map(map, &entity, map_size);
|
||||
check_ret(ret);
|
||||
|
||||
{
|
||||
ret = cbor_encode_text_string(&entity, "id", 2);
|
||||
check_ret(ret);
|
||||
ret = cbor_encode_text_string(&entity, "id", 2);
|
||||
check_ret(ret);
|
||||
|
||||
ret = cbor_encode_byte_string(&entity, user->id, user->id_size);
|
||||
check_ret(ret);
|
||||
}
|
||||
ret = cbor_encode_byte_string(&entity, user->id, user->id_size);
|
||||
check_ret(ret);
|
||||
|
||||
if (dispname)
|
||||
{
|
||||
|
||||
ret = cbor_encode_text_string(&entity, "icon", 4);
|
||||
check_ret(ret);
|
||||
|
||||
ret = cbor_encode_text_stringz(&entity, (const char *)user->icon);
|
||||
check_ret(ret);
|
||||
if (strlen((const char *)user->icon) > 0)
|
||||
{
|
||||
ret = cbor_encode_text_string(&entity, "icon", 4);
|
||||
check_ret(ret);
|
||||
ret = cbor_encode_text_stringz(&entity, (const char *)user->icon);
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
ret = cbor_encode_text_string(&entity, "name", 4);
|
||||
check_ret(ret);
|
||||
@ -1374,7 +1406,7 @@ uint8_t ctap_cred_metadata(CborEncoder * encoder)
|
||||
uint8_t ctap_cred_rp(CborEncoder * encoder, int rk_ind, int rp_count)
|
||||
{
|
||||
CTAP_residentKey rk;
|
||||
load_nth_valid_rk(rk_ind, &rk);
|
||||
ctap_load_rk(rk_ind, &rk);
|
||||
|
||||
CborEncoder map;
|
||||
size_t map_size = rp_count > 0 ? 3 : 2;
|
||||
@ -1423,7 +1455,7 @@ uint8_t ctap_cred_rp(CborEncoder * encoder, int rk_ind, int rp_count)
|
||||
uint8_t ctap_cred_rk(CborEncoder * encoder, int rk_ind, int rk_count)
|
||||
{
|
||||
CTAP_residentKey rk;
|
||||
load_nth_valid_rk(rk_ind, &rk);
|
||||
ctap_load_rk(rk_ind, &rk);
|
||||
|
||||
uint32_t cred_protect = read_metadata_from_masked_credential(&rk.id);
|
||||
if ( cred_protect == 0 || cred_protect > 3 )
|
||||
@ -1523,62 +1555,106 @@ static int credentialId_to_rk_index(CredentialId * credId){
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return 1 if Left(rpIdHash, 16) has been counted in rpHashes.
|
||||
static int8_t _rk_counted(uint8_t rpHashes [50][16], uint8_t * hash, int unique_count)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < unique_count; i++)
|
||||
// Load the next valid resident key of a different rpIdHash
|
||||
static int scan_for_next_rp(int index){
|
||||
CTAP_residentKey rk;
|
||||
uint8_t nextRpIdHash[32];
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
if (memcmp(rpHashes[i], hash, 16) == 0) {
|
||||
return 1;
|
||||
ctap_load_rk(0, &rk);
|
||||
if (ctap_rk_is_valid(&rk))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t count_unique_rks()
|
||||
{
|
||||
CTAP_residentKey rk;
|
||||
unsigned int unique_count = 0;
|
||||
unsigned int i;
|
||||
uint8_t rpHashes [50][16];
|
||||
memset(rpHashes, 0, sizeof(rpHashes));
|
||||
int occurs_previously;
|
||||
do {
|
||||
occurs_previously = 0;
|
||||
|
||||
for(i = 0; i < ctap_rk_size(); i++)
|
||||
{
|
||||
ctap_load_rk(i, &rk);
|
||||
if ( ctap_rk_is_valid(&rk) )
|
||||
index++;
|
||||
if ((unsigned int)index >= ctap_rk_size())
|
||||
{
|
||||
if (! _rk_counted(rpHashes, rk.id.rpIdHash, unique_count))
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctap_load_rk(index, &rk);
|
||||
memmove(nextRpIdHash, rk.id.rpIdHash, 32);
|
||||
|
||||
if (!ctap_rk_is_valid(&rk))
|
||||
{
|
||||
occurs_previously = 1;
|
||||
continue;
|
||||
} else {
|
||||
}
|
||||
|
||||
// Check if we have scanned the rpIdHash before.
|
||||
int i;
|
||||
for (i = 0; i < index; i++)
|
||||
{
|
||||
ctap_load_rk(i, &rk);
|
||||
if (memcmp(rk.id.rpIdHash, nextRpIdHash, 32) == 0)
|
||||
{
|
||||
memmove(rpHashes[unique_count], rk.id.rpIdHash, 16);
|
||||
unique_count += 1;
|
||||
if (unique_count >= ctap_rk_size())
|
||||
{
|
||||
return unique_count;
|
||||
}
|
||||
occurs_previously = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return unique_count;
|
||||
|
||||
} while (occurs_previously);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Load the next valid resident key of the same rpIdHash
|
||||
static int scan_for_next_rk(int index, uint8_t * initialRpIdHash){
|
||||
CTAP_residentKey rk;
|
||||
uint8_t lastRpIdHash[32];
|
||||
|
||||
if (initialRpIdHash != NULL) {
|
||||
memmove(lastRpIdHash, initialRpIdHash, 32);
|
||||
index = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctap_load_rk(index, &rk);
|
||||
memmove(lastRpIdHash, rk.id.rpIdHash, 32);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
index++;
|
||||
if ((unsigned int)index >= ctap_rk_size())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ctap_load_rk(index, &rk);
|
||||
}
|
||||
while ( memcmp( rk.id.rpIdHash, lastRpIdHash, 32 ) != 0 );
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length)
|
||||
{
|
||||
CTAP_credMgmt CM;
|
||||
CTAP_residentKey rk;
|
||||
int i = 0;
|
||||
// use the same index for both RP and RK commands, it make things simpler
|
||||
|
||||
// RP / RK pointers
|
||||
static int curr_rp_ind = 0;
|
||||
static int curr_rk_ind = 0;
|
||||
// keep the rpIdHash specified in CM_cmdRKBegin cause it's not present in CM_cmdRKNext
|
||||
static uint8_t rpIdHash[32];
|
||||
// flag that authenticated RPBegin was received
|
||||
|
||||
// flags that authenticate whether *Begin was before *Next
|
||||
static bool rp_auth = false;
|
||||
// flag that authenticated RKBegin was received
|
||||
static bool rk_auth = false;
|
||||
// number of stored RPs
|
||||
|
||||
int rp_count = 0;
|
||||
// number of RKs with the specified rpIdHash
|
||||
int rk_count = 0;
|
||||
|
||||
int ret = ctap_parse_cred_mgmt(&CM, request, length);
|
||||
@ -1592,78 +1668,51 @@ uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length)
|
||||
if (STATE.rk_stored == 0 && CM.cmd != CM_cmdMetadata)
|
||||
{
|
||||
printf2(TAG_ERR,"No resident keys\n");
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
return 0;
|
||||
}
|
||||
if (CM.cmd == CM_cmdRPBegin)
|
||||
{
|
||||
curr_rk_ind = 0;
|
||||
rp_count = count_unique_rks();
|
||||
curr_rk_ind = -1;
|
||||
rp_auth = true;
|
||||
rk_auth = false;
|
||||
curr_rp_ind = scan_for_next_rp(-1);
|
||||
|
||||
// Count total unique RP's
|
||||
while (curr_rp_ind >= 0)
|
||||
{
|
||||
curr_rp_ind = scan_for_next_rp(curr_rp_ind);
|
||||
rp_count++;
|
||||
}
|
||||
|
||||
// Reset scan
|
||||
curr_rp_ind = scan_for_next_rp(-1);
|
||||
|
||||
printf1(TAG_MC, "RP Begin @%d. %d total.\n", curr_rp_ind, rp_count);
|
||||
}
|
||||
else if (CM.cmd == CM_cmdRKBegin)
|
||||
{
|
||||
curr_rk_ind = 0;
|
||||
curr_rk_ind = scan_for_next_rk(0, CM.subCommandParams.rpIdHash);
|
||||
rk_auth = true;
|
||||
rp_auth = false;
|
||||
// store the specified hash, we will need it for CM_cmdRKNext
|
||||
memcpy(rpIdHash, CM.subCommandParams.rpIdHash, 32);
|
||||
// count how many RKs have this hash
|
||||
printf1(TAG_GREEN, "There are %d total creds\n", STATE.rk_stored);
|
||||
printf1(TAG_GREEN, "true rpidHash:"); dump_hex1(TAG_GREEN, rpIdHash, 32);
|
||||
for (i = 0; i < STATE.rk_stored; i++)
|
||||
|
||||
// Count total RK's associated to RP
|
||||
while (curr_rk_ind >= 0)
|
||||
{
|
||||
load_nth_valid_rk(i, &rk);
|
||||
if (memcmp(rk.id.rpIdHash, rpIdHash, 32) == 0)
|
||||
{
|
||||
rk_count++;
|
||||
}
|
||||
curr_rk_ind = scan_for_next_rk(curr_rk_ind, NULL);
|
||||
rk_count++;
|
||||
}
|
||||
|
||||
// Reset scan
|
||||
curr_rk_ind = scan_for_next_rk(0, CM.subCommandParams.rpIdHash);
|
||||
printf1(TAG_MC, "Cred Begin @%d. %d total.\n", curr_rk_ind, rk_count);
|
||||
}
|
||||
else if (CM.cmd != CM_cmdRKNext && CM.cmd != CM_cmdRPNext)
|
||||
{
|
||||
rk_auth = false;
|
||||
rp_auth = false;
|
||||
curr_rk_ind = 0;
|
||||
curr_rk_ind = -1;
|
||||
curr_rp_ind = -1;
|
||||
}
|
||||
|
||||
printf1(TAG_GREEN, "(0x%02x) CHECK %d\n", CM.cmd, curr_rk_ind);
|
||||
if (load_nth_valid_rk(curr_rk_ind, &rk) < 0)
|
||||
{
|
||||
printf2(TAG_ERR,"No more resident keys\n");
|
||||
rk_auth = false;
|
||||
rp_auth = false;
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
if (CM.cmd == CM_cmdRPNext && !rp_auth)
|
||||
{
|
||||
printf2(TAG_ERR, "RPNext without RPBegin\n");
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
if (CM.cmd == CM_cmdRKNext && !rk_auth)
|
||||
{
|
||||
printf2(TAG_ERR, "RKNext without RKBegin\n");
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
if (CM.cmd == CM_cmdRKBegin || CM.cmd == CM_cmdRKNext)
|
||||
{
|
||||
load_nth_valid_rk(curr_rk_ind, &rk);
|
||||
// skip resident keys with different rpIdHash
|
||||
while (memcmp(rk.id.rpIdHash, rpIdHash, 32) != 0)
|
||||
{
|
||||
curr_rk_ind++;
|
||||
if (load_nth_valid_rk(curr_rk_ind, &rk) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curr_rk_ind == STATE.rk_stored)
|
||||
{
|
||||
printf2(TAG_ERR,"No more resident keys with this rpIdHash\n");
|
||||
rk_auth = false;
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
}
|
||||
switch (CM.cmd)
|
||||
{
|
||||
case CM_cmdMetadata:
|
||||
@ -1673,17 +1722,32 @@ uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length)
|
||||
break;
|
||||
case CM_cmdRPBegin:
|
||||
case CM_cmdRPNext:
|
||||
printf1(TAG_CM, "CM_cmdRPBegin %d/%d\n", curr_rk_ind, rp_count);
|
||||
ret = ctap_cred_rp(encoder, curr_rk_ind, rp_count);
|
||||
printf1(TAG_CM, "Get RP %d\n", curr_rp_ind);
|
||||
if (curr_rp_ind < 0 || !rp_auth) {
|
||||
rp_auth = false;
|
||||
rk_auth = false;
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
ret = ctap_cred_rp(encoder, curr_rp_ind, rp_count);
|
||||
check_ret(ret);
|
||||
curr_rk_ind++;
|
||||
curr_rp_ind = scan_for_next_rp(curr_rp_ind);
|
||||
|
||||
break;
|
||||
case CM_cmdRKBegin:
|
||||
case CM_cmdRKNext:
|
||||
printf1(TAG_CM, "CM_cmdRKBegin %d/%d\n", curr_rk_ind, rp_count);
|
||||
printf1(TAG_CM, "Get Cred %d\n", curr_rk_ind);
|
||||
if (curr_rk_ind < 0 || !rk_auth) {
|
||||
rp_auth = false;
|
||||
rk_auth = false;
|
||||
return CTAP2_ERR_NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
ret = ctap_cred_rk(encoder, curr_rk_ind, rk_count);
|
||||
check_ret(ret);
|
||||
curr_rk_ind++;
|
||||
|
||||
curr_rk_ind = scan_for_next_rk(curr_rk_ind, NULL);
|
||||
|
||||
break;
|
||||
case CM_cmdRKDelete:
|
||||
printf1(TAG_CM, "CM_cmdRKDelete\n");
|
||||
@ -1704,6 +1768,7 @@ uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
{
|
||||
CTAP_getAssertion GA;
|
||||
@ -1718,7 +1783,8 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
|
||||
if (GA.pinAuthEmpty)
|
||||
{
|
||||
ret = ctap2_user_presence_test();
|
||||
uint32_t colour = ctap_assertion_led_colour(GA.clientDataHash, 32);
|
||||
ret = ctap2_user_presence_test(colour);
|
||||
check_retr(ret);
|
||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||
}
|
||||
@ -2192,6 +2258,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
{
|
||||
case CTAP_MAKE_CREDENTIAL:
|
||||
case CTAP_GET_ASSERTION:
|
||||
case CTAP_CBOR_CRED_MGMT:
|
||||
case CTAP_CBOR_CRED_MGMT_PRE:
|
||||
if (ctap_device_locked())
|
||||
{
|
||||
@ -2250,7 +2317,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
break;
|
||||
case CTAP_RESET:
|
||||
printf1(TAG_CTAP,"CTAP_RESET\n");
|
||||
status = ctap2_user_presence_test();
|
||||
status = ctap2_user_presence_test(0);
|
||||
if (status == CTAP1_ERR_SUCCESS)
|
||||
{
|
||||
ctap_reset();
|
||||
@ -2274,6 +2341,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
status = CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
break;
|
||||
case CTAP_CBOR_CRED_MGMT:
|
||||
case CTAP_CBOR_CRED_MGMT_PRE:
|
||||
printf1(TAG_CTAP,"CTAP_CBOR_CRED_MGMT_PRE\n");
|
||||
status = ctap_cred_mgmt(&encoder, pkt_raw, length);
|
||||
@ -2282,6 +2350,9 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
|
||||
dump_hex1(TAG_DUMP,buf, resp->length);
|
||||
break;
|
||||
case CTAP_VENDOR_LOAD:
|
||||
//TODO: load secret
|
||||
break;
|
||||
default:
|
||||
status = CTAP1_ERR_INVALID_COMMAND;
|
||||
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd);
|
||||
@ -2407,6 +2478,11 @@ uint8_t ctap_is_pin_set()
|
||||
*/
|
||||
void ctap_update_pin(uint8_t * pin, int len)
|
||||
{
|
||||
if(len == 0 || strncmp(pin, "4321", len) == 0) {
|
||||
STATE.is_pin_set = 0;
|
||||
authenticator_write_state(&STATE);
|
||||
return;
|
||||
}
|
||||
if (len >= NEW_PIN_ENC_MIN_SIZE || len < 4)
|
||||
{
|
||||
printf2(TAG_ERR, "Update pin fail length\n");
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define CTAP_CLIENT_PIN 0x06
|
||||
#define CTAP_RESET 0x07
|
||||
#define GET_NEXT_ASSERTION 0x08
|
||||
#define CTAP_CBOR_CRED_MGMT 0x0A
|
||||
#define CTAP_VENDOR_FIRST 0x40
|
||||
#define CTAP_CBOR_CRED_MGMT_PRE 0x41
|
||||
#define CTAP_VENDOR_LAST 0xBF
|
||||
|
@ -1103,7 +1103,7 @@ uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length)
|
||||
ret = cbor_value_get_map_length(&it, &map_length);
|
||||
check_ret(ret);
|
||||
|
||||
printf1(TAG_CM, "CM map has %d elements\n", map_length);
|
||||
printf1(TAG_PARSE, "CM map has %d elements\n", map_length);
|
||||
|
||||
for (i = 0; i < map_length; i++)
|
||||
{
|
||||
@ -1122,7 +1122,7 @@ uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length)
|
||||
switch(key)
|
||||
{
|
||||
case CM_cmd:
|
||||
printf1(TAG_CM, "CM_cmd\n");
|
||||
printf1(TAG_PARSE, "CM_cmd\n");
|
||||
if (cbor_value_get_type(&map) == CborIntegerType)
|
||||
{
|
||||
ret = cbor_value_get_int_checked(&map, &CM->cmd);
|
||||
@ -1135,12 +1135,12 @@ uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length)
|
||||
}
|
||||
break;
|
||||
case CM_subCommandParams:
|
||||
printf1(TAG_CM, "CM_subCommandParams\n");
|
||||
printf1(TAG_PARSE, "CM_subCommandParams\n");
|
||||
ret = parse_cred_mgmt_subcommandparams(&map, CM);
|
||||
check_ret(ret);
|
||||
break;
|
||||
case CM_pinProtocol:
|
||||
printf1(TAG_CM, "CM_pinProtocol\n");
|
||||
printf1(TAG_PARSE, "CM_pinProtocol\n");
|
||||
if (cbor_value_get_type(&map) == CborIntegerType)
|
||||
{
|
||||
ret = cbor_value_get_int_checked(&map, &CM->pinProtocol);
|
||||
@ -1152,7 +1152,7 @@ uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length)
|
||||
}
|
||||
break;
|
||||
case CM_pinAuth:
|
||||
printf1(TAG_CM, "CM_pinAuth\n");
|
||||
printf1(TAG_PARSE, "CM_pinAuth\n");
|
||||
ret = parse_fixed_byte_string(&map, CM->pinAuth, 16);
|
||||
check_retr(ret);
|
||||
CM->pinAuthPresent = 1;
|
||||
|
@ -87,6 +87,24 @@ int device_is_button_pressed();
|
||||
*/
|
||||
int ctap_user_presence_test(uint32_t delay);
|
||||
|
||||
//
|
||||
// Return 2 for disabled, 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||
/** Test for user presence.
|
||||
* Perform test that user is present. Returns status on user presence. This is used by FIDO and U2F layer
|
||||
* to check if an operation should continue, or if the UP flag should be set.
|
||||
*
|
||||
* @param delay number of milliseconds to delay waiting for user before timeout.
|
||||
* @param button_confirm_colour LED colour while waiting for confirmation.
|
||||
*
|
||||
* @return 2 - User presence is disabled. Operation should continue, but UP flag not set.
|
||||
* 1 - User presence confirmed. Operation should continue, and UP flag is set.
|
||||
* 0 - User presence is not confirmed. Operation should be denied.
|
||||
* -1 - Operation was canceled. Do not continue, reset transaction state.
|
||||
*
|
||||
* *Optional*, the default implementation will return 1, unless a FIDO2 operation calls for no UP, where this will then return 2.
|
||||
*/
|
||||
int ctap_user_presence_test_colour(uint32_t delay, uint32_t button_confirm_colour);
|
||||
|
||||
/** Disable the next user presence test. This is called by FIDO2 layer when a transaction
|
||||
* requests UP to be disabled. The next call to ctap_user_presence_test should return 2,
|
||||
* and then UP should be enabled again.
|
||||
|
13
shell.nix
Normal file
13
shell.nix
Normal file
@ -0,0 +1,13 @@
|
||||
let
|
||||
nixpkgs_tar = fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/20.03.tar.gz"; sha256 = "0182ys095dfx02vl2a20j1hz92dx3mfgz2a6fhn31bqlp1wa8hlq"; };
|
||||
pkgs = import "${nixpkgs_tar}" {};
|
||||
pyPackages = (python-packages: with python-packages; ([
|
||||
solo-python pytest
|
||||
] ++ (with builtins; map (d: getAttr d python-packages) (filter (d: stringLength d > 0) (pkgs.lib.splitString "\n" (builtins.readFile ./tools/requirements.txt))))));
|
||||
python-with-my-packages = pkgs.python3.withPackages pyPackages;
|
||||
in
|
||||
with pkgs;
|
||||
stdenv.mkDerivation {
|
||||
name = "solo";
|
||||
buildInputs = [ gnumake gcc gcc-arm-embedded-8 python-with-my-packages ];
|
||||
}
|
@ -704,6 +704,10 @@ static int wait_for_button_release(uint32_t wait)
|
||||
}
|
||||
|
||||
int ctap_user_presence_test(uint32_t up_delay)
|
||||
{
|
||||
return ctap_user_presence_test_colour(up_delay, 0);
|
||||
}
|
||||
int ctap_user_presence_test_colour(uint32_t up_delay, uint32_t button_confirm_colour)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -741,8 +745,7 @@ int ctap_user_presence_test(uint32_t up_delay)
|
||||
}
|
||||
|
||||
// Set LED status and wait.
|
||||
led_rgb(0xff3520);
|
||||
|
||||
led_rgb(button_confirm_colour==0?0xff3520:button_confirm_colour);
|
||||
// Block and wait for some time.
|
||||
ret = wait_for_button_activate(up_delay);
|
||||
if (ret) return ret;
|
||||
|
Reference in New Issue
Block a user