Compare commits
16 Commits
ctap2_issu
...
key-backup
Author | SHA1 | Date | |
---|---|---|---|
279ab1b7f0 | |||
e67d05e3c1 | |||
03e0479f1a | |||
92aadb3da5 | |||
1493c6f131 | |||
ccb3753d2b | |||
1427c1d48e | |||
208d26be89 | |||
45293fe998 | |||
a1a42fec5c | |||
8c256298ae | |||
01b928c0ec | |||
018a4d394c | |||
7a75fba6d3 | |||
c61f15a090 | |||
f072561899 |
2
Makefile
2
Makefile
@ -39,7 +39,7 @@ INCLUDES += -I./crypto/cifra/src
|
|||||||
|
|
||||||
CFLAGS += $(INCLUDES)
|
CFLAGS += $(INCLUDES)
|
||||||
# for crypto/tiny-AES-c
|
# for crypto/tiny-AES-c
|
||||||
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\"
|
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\" -DSOLO_EXPERIMENTAL=1
|
||||||
|
|
||||||
name = main
|
name = main
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
2.5.2
|
2.5.3
|
||||||
|
@ -18,7 +18,7 @@ Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>.
|
|||||||
If you still need to setup a rule, a simple way to do it is:
|
If you still need to setup a rule, a simple way to do it is:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone git@github.com:solokeys/solo.git
|
git clone https://github.com/solokeys/solo.git
|
||||||
cd solo/udev
|
cd solo/udev
|
||||||
make setup
|
make setup
|
||||||
```
|
```
|
||||||
|
45
fido2/ctap.c
45
fido2/ctap.c
@ -438,7 +438,11 @@ static int ctap2_user_presence_test()
|
|||||||
{
|
{
|
||||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||||
int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||||
if ( ret > 0 )
|
if ( ret > 1 )
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PROCESSING;
|
||||||
|
}
|
||||||
|
else if ( ret > 0 )
|
||||||
{
|
{
|
||||||
return CTAP1_ERR_SUCCESS;
|
return CTAP1_ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -482,11 +486,19 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
int but;
|
int but;
|
||||||
|
|
||||||
but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||||
check_retr(but);
|
if (CTAP2_ERR_PROCESSING == but)
|
||||||
|
{
|
||||||
|
authData->head.flags = (0 << 0); // User presence disabled
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
check_retr(but);
|
||||||
|
authData->head.flags = (1 << 0); // User presence
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
|
|
||||||
authData->head.flags = (1 << 0); // User presence
|
|
||||||
authData->head.flags |= (ctap_is_pin_set() << 2);
|
authData->head.flags |= (ctap_is_pin_set() << 2);
|
||||||
|
|
||||||
|
|
||||||
@ -670,7 +682,16 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d
|
|||||||
switch(desc->type)
|
switch(desc->type)
|
||||||
{
|
{
|
||||||
case PUB_KEY_CRED_PUB_KEY:
|
case PUB_KEY_CRED_PUB_KEY:
|
||||||
make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(rp->id, rp->size);
|
||||||
|
crypto_sha256_final(rpIdHash);
|
||||||
|
|
||||||
|
printf1(TAG_RED,"rpId: %s\r\n", rp->id); dump_hex1(TAG_RED,rp->id, rp->size);
|
||||||
|
if (memcmp(desc->credential.id.rpIdHash, rpIdHash, 32) != 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
make_auth_tag(rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
||||||
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
||||||
break;
|
break;
|
||||||
case PUB_KEY_CRED_CTAP1:
|
case PUB_KEY_CRED_CTAP1:
|
||||||
@ -734,7 +755,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MC.up)
|
if (MC.up == 1 || MC.up == 0)
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_INVALID_OPTION;
|
return CTAP2_ERR_INVALID_OPTION;
|
||||||
}
|
}
|
||||||
@ -1227,8 +1248,9 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
device_disable_up(GA.up == 0);
|
||||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
|
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
|
||||||
|
device_disable_up(false);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
|
||||||
((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2);
|
((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2);
|
||||||
@ -1739,7 +1761,18 @@ static void ctap_state_init()
|
|||||||
|
|
||||||
printf1(TAG_STOR, "Generated PIN SALT: ");
|
printf1(TAG_STOR, "Generated PIN SALT: ");
|
||||||
dump_hex1(TAG_STOR, STATE.PIN_SALT, sizeof STATE.PIN_SALT);
|
dump_hex1(TAG_STOR, STATE.PIN_SALT, sizeof STATE.PIN_SALT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Overwrite master secret from external source.
|
||||||
|
* @param keybytes an array of KEY_SPACE_BYTES length.
|
||||||
|
*
|
||||||
|
* This function should only be called from a privilege mode.
|
||||||
|
*/
|
||||||
|
void ctap_load_external_keys(uint8_t * keybytes){
|
||||||
|
memmove(STATE.key_space, keybytes, KEY_SPACE_BYTES);
|
||||||
|
authenticator_write_state(&STATE, 0);
|
||||||
|
authenticator_write_state(&STATE, 1);
|
||||||
|
crypto_load_master_secret(STATE.key_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctap_init()
|
void ctap_init()
|
||||||
|
@ -361,4 +361,6 @@ extern uint8_t KEY_AGREEMENT_PUB[64];
|
|||||||
|
|
||||||
void lock_device_permanently();
|
void lock_device_permanently();
|
||||||
|
|
||||||
|
void ctap_load_external_keys(uint8_t * keybytes);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -715,6 +715,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
|||||||
CborValue it,map;
|
CborValue it,map;
|
||||||
|
|
||||||
memset(MC, 0, sizeof(CTAP_makeCredential));
|
memset(MC, 0, sizeof(CTAP_makeCredential));
|
||||||
|
MC->up = 0xff;
|
||||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
|
||||||
@ -1010,6 +1011,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
|||||||
|
|
||||||
memset(GA, 0, sizeof(CTAP_getAssertion));
|
memset(GA, 0, sizeof(CTAP_getAssertion));
|
||||||
GA->creds = getAssertionState.creds; // Save stack memory
|
GA->creds = getAssertionState.creds; // Save stack memory
|
||||||
|
GA->up = 0xff;
|
||||||
|
|
||||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
341
fido2/ctaphid.c
341
fido2/ctaphid.c
@ -16,6 +16,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "extensions.h"
|
#include "extensions.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
// move custom SHA512 command out,
|
// move custom SHA512 command out,
|
||||||
// and the following headers too
|
// and the following headers too
|
||||||
@ -538,11 +539,14 @@ extern void _check_ret(CborError ret, int line, const char * filename);
|
|||||||
#define check_hardcore(r) _check_ret(r,__LINE__, __FILE__);\
|
#define check_hardcore(r) _check_ret(r,__LINE__, __FILE__);\
|
||||||
if ((r) != CborNoError) exit(1);
|
if ((r) != CborNoError) exit(1);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb);
|
||||||
|
|
||||||
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||||
{
|
{
|
||||||
uint8_t cmd;
|
uint8_t cmd = 0;
|
||||||
uint32_t cid;
|
uint32_t cid;
|
||||||
int len;
|
int len = 0;
|
||||||
#ifndef DISABLE_CTAPHID_CBOR
|
#ifndef DISABLE_CTAPHID_CBOR
|
||||||
int status;
|
int status;
|
||||||
#endif
|
#endif
|
||||||
@ -552,6 +556,10 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
CTAP_RESPONSE ctap_resp;
|
CTAP_RESPONSE ctap_resp;
|
||||||
|
|
||||||
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
|
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = cmd;
|
||||||
|
|
||||||
if (bufstatus == HID_IGNORE)
|
if (bufstatus == HID_IGNORE)
|
||||||
{
|
{
|
||||||
@ -587,9 +595,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
case CTAPHID_PING:
|
case CTAPHID_PING:
|
||||||
printf1(TAG_HID,"CTAPHID_PING\n");
|
printf1(TAG_HID,"CTAPHID_PING\n");
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_PING;
|
|
||||||
wb.bcnt = len;
|
wb.bcnt = len;
|
||||||
timestamp();
|
timestamp();
|
||||||
ctaphid_write(&wb, ctap_buffer, len);
|
ctaphid_write(&wb, ctap_buffer, len);
|
||||||
@ -602,13 +607,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
case CTAPHID_WINK:
|
case CTAPHID_WINK:
|
||||||
printf1(TAG_HID,"CTAPHID_WINK\n");
|
printf1(TAG_HID,"CTAPHID_WINK\n");
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
|
|
||||||
device_wink();
|
device_wink();
|
||||||
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_WINK;
|
|
||||||
|
|
||||||
ctaphid_write(&wb,NULL,0);
|
ctaphid_write(&wb,NULL,0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -633,9 +634,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
status = ctap_request(ctap_buffer, len, &ctap_resp);
|
status = ctap_request(ctap_buffer, len, &ctap_resp);
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_CBOR;
|
|
||||||
wb.bcnt = (ctap_resp.length+1);
|
wb.bcnt = (ctap_resp.length+1);
|
||||||
|
|
||||||
|
|
||||||
@ -666,9 +664,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_MSG;
|
|
||||||
wb.bcnt = (ctap_resp.length);
|
wb.bcnt = (ctap_resp.length);
|
||||||
|
|
||||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||||
@ -679,209 +674,14 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
||||||
is_busy = 0;
|
is_busy = 0;
|
||||||
break;
|
break;
|
||||||
#if defined(IS_BOOTLOADER)
|
|
||||||
case CTAPHID_BOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_BOOT\n");
|
|
||||||
ctap_response_init(&ctap_resp);
|
|
||||||
u2f_set_writeback_buffer(&ctap_resp);
|
|
||||||
is_busy = bootloader_bridge(len, ctap_buffer);
|
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_BOOT;
|
|
||||||
wb.bcnt = (ctap_resp.length + 1);
|
|
||||||
ctaphid_write(&wb, &is_busy, 1);
|
|
||||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
|
||||||
ctaphid_write(&wb, NULL, 0);
|
|
||||||
is_busy = 0;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#if defined(SOLO_HACKER)
|
|
||||||
case CTAPHID_ENTERBOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
|
||||||
boot_solo_bootloader();
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_ENTERBOOT;
|
|
||||||
wb.bcnt = 0;
|
|
||||||
ctaphid_write(&wb, NULL, 0);
|
|
||||||
is_busy = 0;
|
|
||||||
break;
|
|
||||||
case CTAPHID_ENTERSTBOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
|
||||||
boot_st_bootloader();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#if !defined(IS_BOOTLOADER)
|
|
||||||
case CTAPHID_GETRNG:
|
|
||||||
printf1(TAG_HID,"CTAPHID_GETRNG\n");
|
|
||||||
ctap_response_init(&ctap_resp);
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_GETRNG;
|
|
||||||
wb.bcnt = ctap_buffer[0];
|
|
||||||
if (!wb.bcnt)
|
|
||||||
wb.bcnt = 57;
|
|
||||||
memset(ctap_buffer,0,wb.bcnt);
|
|
||||||
ctap_generate_rng(ctap_buffer, wb.bcnt);
|
|
||||||
ctaphid_write(&wb, &ctap_buffer, wb.bcnt);
|
|
||||||
ctaphid_write(&wb, NULL, 0);
|
|
||||||
is_busy = 0;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#if defined(SOLO_HACKER) && (DEBUG_LEVEL > 0) && (!IS_BOOTLOADER == 1)
|
|
||||||
case CTAPHID_PROBE:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Expects CBOR-serialized data of the form
|
|
||||||
* {"subcommand": "hash_type", "data": b"the_data"}
|
|
||||||
* with hash_type in SHA256, SHA512
|
|
||||||
*/
|
|
||||||
|
|
||||||
// some random logging
|
|
||||||
printf1(TAG_HID,"CTAPHID_PROBE\n");
|
|
||||||
// initialise CTAP response object
|
|
||||||
ctap_response_init(&ctap_resp);
|
|
||||||
// initialise write buffer
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_PROBE;
|
|
||||||
|
|
||||||
// prepare parsing (or halt)
|
|
||||||
int ret;
|
|
||||||
CborParser parser;
|
|
||||||
CborValue it, map;
|
|
||||||
ret = cbor_parser_init(
|
|
||||||
ctap_buffer, (size_t) buffer_len(),
|
|
||||||
// strictly speaking, CTAP is not RFC canonical...
|
|
||||||
CborValidateCanonicalFormat,
|
|
||||||
&parser, &it);
|
|
||||||
check_hardcore(ret);
|
|
||||||
|
|
||||||
CborType type = cbor_value_get_type(&it);
|
|
||||||
if (type != CborMapType) exit(1);
|
|
||||||
|
|
||||||
ret = cbor_value_enter_container(&it,&map);
|
|
||||||
check_hardcore(ret);
|
|
||||||
|
|
||||||
size_t map_length = 0;
|
|
||||||
ret = cbor_value_get_map_length(&it, &map_length);
|
|
||||||
if (map_length != 2) exit(1);
|
|
||||||
|
|
||||||
// parse subcommand (or halt)
|
|
||||||
CborValue val;
|
|
||||||
ret = cbor_value_map_find_value(&it, "subcommand", &val);
|
|
||||||
check_hardcore(ret);
|
|
||||||
if (!cbor_value_is_text_string(&val))
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
int sha_version = 0;
|
|
||||||
bool found = false;
|
|
||||||
if (!found) {
|
|
||||||
ret = cbor_value_text_string_equals(
|
|
||||||
&val, "SHA256", &found);
|
|
||||||
check_hardcore(ret);
|
|
||||||
if (found)
|
|
||||||
sha_version = 256;
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
ret = cbor_value_text_string_equals(
|
|
||||||
&val, "SHA512", &found);
|
|
||||||
check_hardcore(ret);
|
|
||||||
if (found)
|
|
||||||
sha_version = 512;
|
|
||||||
}
|
|
||||||
if (sha_version == 0)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
// parse data (or halt)
|
|
||||||
ret = cbor_value_map_find_value(&it, "data", &val);
|
|
||||||
check_hardcore(ret);
|
|
||||||
if (!cbor_value_is_byte_string(&val))
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
size_t data_length = 0;
|
|
||||||
ret = cbor_value_calculate_string_length(&val, &data_length);
|
|
||||||
check_hardcore(ret);
|
|
||||||
if (data_length > 6*1024)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
unsigned char data[6*1024];
|
|
||||||
ret = cbor_value_copy_byte_string (
|
|
||||||
&val, &data[0], &data_length, &val);
|
|
||||||
check_hardcore(ret);
|
|
||||||
|
|
||||||
// execute subcommand
|
|
||||||
if (sha_version == 256) {
|
|
||||||
// calculate hash
|
|
||||||
crypto_sha256_init();
|
|
||||||
crypto_sha256_update(data, data_length);
|
|
||||||
crypto_sha256_final(ctap_buffer);
|
|
||||||
// write output
|
|
||||||
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
|
|
||||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sha_version == 512) {
|
|
||||||
// calculate hash
|
|
||||||
crypto_sha512_init();
|
|
||||||
crypto_sha512_update(data, data_length);
|
|
||||||
crypto_sha512_final(ctap_buffer);
|
|
||||||
// write output
|
|
||||||
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
|
|
||||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
// finalize
|
|
||||||
ctaphid_write(&wb, NULL, 0);
|
|
||||||
is_busy = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
|
||||||
case CTAPHID_SHA256:
|
|
||||||
// some random logging
|
|
||||||
printf1(TAG_HID,"CTAPHID_SHA256\n");
|
|
||||||
// initialise CTAP response object
|
|
||||||
ctap_response_init(&ctap_resp);
|
|
||||||
// initialise write buffer
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_SHA256;
|
|
||||||
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
|
|
||||||
// calculate hash
|
|
||||||
crypto_sha256_init();
|
|
||||||
crypto_sha256_update(ctap_buffer, buffer_len());
|
|
||||||
crypto_sha256_final(ctap_buffer);
|
|
||||||
// copy to output
|
|
||||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
|
|
||||||
ctaphid_write(&wb, NULL, 0);
|
|
||||||
is_busy = 0;
|
|
||||||
break;
|
|
||||||
case CTAPHID_SHA512:
|
|
||||||
// some random logging
|
|
||||||
printf1(TAG_HID,"CTAPHID_SHA512\n");
|
|
||||||
// initialise CTAP response object
|
|
||||||
ctap_response_init(&ctap_resp);
|
|
||||||
// initialise write buffer
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = CTAPHID_SHA512;
|
|
||||||
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
|
|
||||||
// calculate hash
|
|
||||||
crypto_sha512_init();
|
|
||||||
crypto_sha512_update(ctap_buffer, buffer_len());
|
|
||||||
crypto_sha512_final(ctap_buffer);
|
|
||||||
// copy to output
|
|
||||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
|
|
||||||
ctaphid_write(&wb, NULL, 0);
|
|
||||||
is_busy = 0;
|
|
||||||
break;
|
|
||||||
*/
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
if (ctaphid_custom_command(len, &ctap_resp, &wb) != 0){
|
||||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
is_busy = 0;
|
||||||
break;
|
}else{
|
||||||
|
printf2(TAG_ERR, "error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||||
|
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cid_del(cid);
|
cid_del(cid);
|
||||||
buffer_reset();
|
buffer_reset();
|
||||||
@ -891,3 +691,112 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
else return 0;
|
else return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb)
|
||||||
|
{
|
||||||
|
ctap_response_init(ctap_resp);
|
||||||
|
|
||||||
|
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
||||||
|
uint32_t param;
|
||||||
|
#endif
|
||||||
|
#if defined(IS_BOOTLOADER)
|
||||||
|
uint8_t is_busy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(wb->cmd)
|
||||||
|
{
|
||||||
|
#if defined(IS_BOOTLOADER)
|
||||||
|
case CTAPHID_BOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_BOOT\n");
|
||||||
|
u2f_set_writeback_buffer(ctap_resp);
|
||||||
|
is_busy = bootloader_bridge(len, ctap_buffer);
|
||||||
|
|
||||||
|
ctaphid_write(wb, &is_busy, 1);
|
||||||
|
ctaphid_write(wb, ctap_resp->data, ctap_resp->length);
|
||||||
|
ctaphid_write(wb, NULL, 0);
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
#if defined(SOLO_HACKER)
|
||||||
|
case CTAPHID_ENTERBOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||||
|
boot_solo_bootloader();
|
||||||
|
wb->bcnt = 0;
|
||||||
|
ctaphid_write(wb, NULL, 0);
|
||||||
|
return 1;
|
||||||
|
case CTAPHID_ENTERSTBOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||||
|
boot_st_bootloader();
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(IS_BOOTLOADER)
|
||||||
|
case CTAPHID_GETRNG:
|
||||||
|
printf1(TAG_HID,"CTAPHID_GETRNG\n");
|
||||||
|
wb->bcnt = ctap_buffer[0];
|
||||||
|
if (!wb->bcnt)
|
||||||
|
wb->bcnt = 57;
|
||||||
|
memset(ctap_buffer,0,wb->bcnt);
|
||||||
|
ctap_generate_rng(ctap_buffer, wb->bcnt);
|
||||||
|
ctaphid_write(wb, ctap_buffer, wb->bcnt);
|
||||||
|
ctaphid_write(wb, NULL, 0);
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case CTAPHID_GETVERSION:
|
||||||
|
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
|
||||||
|
wb->bcnt = 3;
|
||||||
|
ctap_buffer[0] = SOLO_VERSION_MAJ;
|
||||||
|
ctap_buffer[1] = SOLO_VERSION_MIN;
|
||||||
|
ctap_buffer[2] = SOLO_VERSION_PATCH;
|
||||||
|
ctaphid_write(wb, ctap_buffer, 3);
|
||||||
|
ctaphid_write(wb, NULL, 0);
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
||||||
|
case CTAPHID_LOADKEY:
|
||||||
|
/**
|
||||||
|
* Load external key. Useful for enabling backups.
|
||||||
|
* bytes: 4 96
|
||||||
|
* payload: | counter_increase (BE) | master_key |
|
||||||
|
*
|
||||||
|
* Counter should be increased by a large amount, e.g. (0x10000000)
|
||||||
|
* to outdo any previously lost/broken keys.
|
||||||
|
*/
|
||||||
|
printf1(TAG_HID,"CTAPHID_LOADKEY\n");
|
||||||
|
if (len != 100)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"Error, invalid length.\n");
|
||||||
|
ctaphid_send_error(wb->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask for THREE button presses
|
||||||
|
if (ctap_user_presence_test(8000) > 0)
|
||||||
|
if (ctap_user_presence_test(8000) > 0)
|
||||||
|
if (ctap_user_presence_test(8000) > 0)
|
||||||
|
{
|
||||||
|
ctap_load_external_keys(ctap_buffer + 4);
|
||||||
|
param = ctap_buffer[3];
|
||||||
|
param |= ctap_buffer[2] << 8;
|
||||||
|
param |= ctap_buffer[1] << 16;
|
||||||
|
param |= ctap_buffer[0] << 24;
|
||||||
|
ctap_atomic_count(param);
|
||||||
|
|
||||||
|
wb->bcnt = 0;
|
||||||
|
|
||||||
|
ctaphid_write(wb, NULL, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf2(TAG_ERR, "Error, invalid length.\n");
|
||||||
|
ctaphid_send_error(wb->cid, CTAP2_ERR_OPERATION_DENIED);
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -28,6 +28,8 @@
|
|||||||
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
|
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
|
||||||
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
|
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
|
||||||
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
|
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
|
||||||
|
#define CTAPHID_GETVERSION (TYPE_INIT | 0x61)
|
||||||
|
#define CTAPHID_LOADKEY (TYPE_INIT | 0x62)
|
||||||
// reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0
|
// reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0
|
||||||
#define CTAPHID_PROBE (TYPE_INIT | 0x70)
|
#define CTAPHID_PROBE (TYPE_INIT | 0x70)
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ void device_set_status(uint32_t status);
|
|||||||
int device_is_button_pressed();
|
int device_is_button_pressed();
|
||||||
|
|
||||||
// Test for user presence
|
// Test for user presence
|
||||||
// Return 1 for user is present, 0 user not present, -1 if cancel is requested.
|
// Return 2 for disabled, 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||||
int ctap_user_presence_test(uint32_t delay);
|
int ctap_user_presence_test(uint32_t delay);
|
||||||
|
|
||||||
// Generate @num bytes of random numbers to @dest
|
// Generate @num bytes of random numbers to @dest
|
||||||
@ -61,8 +61,8 @@ int ctap_user_presence_test(uint32_t delay);
|
|||||||
int ctap_generate_rng(uint8_t * dst, size_t num);
|
int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||||
|
|
||||||
// Increment atomic counter and return it.
|
// Increment atomic counter and return it.
|
||||||
// Must support two counters, @sel selects counter0 or counter1.
|
// @param amount the amount to increase the counter by.
|
||||||
uint32_t ctap_atomic_count(int sel);
|
uint32_t ctap_atomic_count(uint32_t amount);
|
||||||
|
|
||||||
// Verify the user
|
// Verify the user
|
||||||
// return 1 if user is verified, 0 if not
|
// return 1 if user is verified, 0 if not
|
||||||
@ -106,7 +106,7 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param);
|
|||||||
#define NFC_IS_AVAILABLE 2
|
#define NFC_IS_AVAILABLE 2
|
||||||
int device_is_nfc();
|
int device_is_nfc();
|
||||||
|
|
||||||
void request_from_nfc(bool request_active);
|
void device_disable_up(bool request_active);
|
||||||
|
|
||||||
void device_init_button();
|
void device_init_button();
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@ void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONS
|
|||||||
if (!header)
|
if (!header)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
request_from_nfc(true); // disable presence test
|
device_disable_up(true); // disable presence test
|
||||||
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
||||||
request_from_nfc(false); // enable presence test
|
device_disable_up(false); // enable presence test
|
||||||
}
|
}
|
||||||
|
|
||||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||||
|
25
pc/device.c
25
pc/device.c
@ -26,6 +26,7 @@
|
|||||||
#define RK_NUM 50
|
#define RK_NUM 50
|
||||||
|
|
||||||
bool use_udp = true;
|
bool use_udp = true;
|
||||||
|
static bool _up_disabled = false;
|
||||||
|
|
||||||
struct ResidentKeyStore {
|
struct ResidentKeyStore {
|
||||||
CTAP_residentKey rks[RK_NUM];
|
CTAP_residentKey rks[RK_NUM];
|
||||||
@ -299,6 +300,10 @@ void ctaphid_write_block(uint8_t * data)
|
|||||||
|
|
||||||
int ctap_user_presence_test(uint32_t d)
|
int ctap_user_presence_test(uint32_t d)
|
||||||
{
|
{
|
||||||
|
if (_up_disabled)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,20 +313,11 @@ int ctap_user_verification(uint8_t arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t ctap_atomic_count(int sel)
|
uint32_t ctap_atomic_count(uint32_t amount)
|
||||||
{
|
{
|
||||||
static uint32_t counter1 = 25;
|
static uint32_t counter1 = 25;
|
||||||
/*return 713;*/
|
counter1 += amount;
|
||||||
if (sel == 0)
|
return counter1;
|
||||||
{
|
|
||||||
printf1(TAG_RED,"counter1: %d\n", counter1);
|
|
||||||
return counter1++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf2(TAG_ERR,"counter2 not imple\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ctap_generate_rng(uint8_t * dst, size_t num)
|
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||||
@ -633,10 +629,9 @@ int device_is_nfc()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void device_disable_up(bool disable)
|
||||||
void request_from_nfc(bool request_active)
|
|
||||||
{
|
{
|
||||||
|
_up_disabled = disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
||||||
|
@ -45,7 +45,7 @@ uint32_t __last_update = 0;
|
|||||||
extern PCD_HandleTypeDef hpcd;
|
extern PCD_HandleTypeDef hpcd;
|
||||||
static int _NFC_status = 0;
|
static int _NFC_status = 0;
|
||||||
static bool isLowFreq = 0;
|
static bool isLowFreq = 0;
|
||||||
static bool _RequestComeFromNFC = false;
|
static bool _up_disabled = false;
|
||||||
|
|
||||||
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||||
static int is_physical_button_pressed()
|
static int is_physical_button_pressed()
|
||||||
@ -92,8 +92,8 @@ static void edge_detect_touch_button()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void request_from_nfc(bool request_active) {
|
void device_disable_up(bool disable) {
|
||||||
_RequestComeFromNFC = request_active;
|
_up_disabled = disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer6 overflow handler. happens every ~90ms.
|
// Timer6 overflow handler. happens every ~90ms.
|
||||||
@ -407,7 +407,7 @@ void authenticator_write_state(AuthenticatorState * a, int backup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ctap_atomic_count(int sel)
|
uint32_t ctap_atomic_count(uint32_t amount)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
||||||
@ -422,10 +422,12 @@ uint32_t ctap_atomic_count(int sel)
|
|||||||
|
|
||||||
uint32_t lastc = 0;
|
uint32_t lastc = 0;
|
||||||
|
|
||||||
if (sel != 0)
|
if (amount == 0)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"counter2 not imple\n");
|
// Use a random count [1-16].
|
||||||
exit(1);
|
uint8_t rng[1];
|
||||||
|
ctap_generate_rng(rng, 1);
|
||||||
|
amount = (rng[0] & 0x0f) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (offset = 0; offset < PAGE_SIZE/4; offset += 2) // wear-level the flash
|
for (offset = 0; offset < PAGE_SIZE/4; offset += 2) // wear-level the flash
|
||||||
@ -458,7 +460,7 @@ uint32_t ctap_atomic_count(int sel)
|
|||||||
return lastc;
|
return lastc;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastc++;
|
lastc += amount;
|
||||||
|
|
||||||
if (lastc/256 > erases)
|
if (lastc/256 > erases)
|
||||||
{
|
{
|
||||||
@ -582,11 +584,17 @@ static int wait_for_button_release(uint32_t wait)
|
|||||||
int ctap_user_presence_test(uint32_t up_delay)
|
int ctap_user_presence_test(uint32_t up_delay)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
|
|
||||||
|
if (device_is_nfc() == NFC_IS_ACTIVE)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_up_disabled)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
||||||
int i=500;
|
int i=500;
|
||||||
while(i--)
|
while(i--)
|
||||||
|
@ -731,10 +731,10 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
|||||||
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
||||||
|
|
||||||
// WTX_on(WTX_TIME_DEFAULT);
|
// WTX_on(WTX_TIME_DEFAULT);
|
||||||
request_from_nfc(true);
|
device_disable_up(true);
|
||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
status = ctap_request(apdu->data, apdu->lc, &ctap_resp);
|
status = ctap_request(apdu->data, apdu->lc, &ctap_resp);
|
||||||
request_from_nfc(false);
|
device_disable_up(false);
|
||||||
// if (!WTX_off())
|
// if (!WTX_off())
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user