Compare commits

...

41 Commits

Author SHA1 Message Date
3de4d0155e build 2020-10-30 15:43:25 +01:00
5f9537bccc build 2020-10-30 13:58:59 +01:00
967e35472f shell 2020-09-22 15:26:43 +02:00
78f7a7a979 allow pin removal
either change to PIN to an empty one or "4321"
2020-08-30 17:02:35 +02:00
72063049a7 use bit shifts 2020-06-14 16:49:43 +02:00
4743fd2326 make led colour depend on credential 2020-06-12 23:23:59 +02:00
299e91b91b dont return index >= ctap_rk_size()
Fixes issue found by @My1: https://github.com/solokeys/solo/issues/407
2020-03-28 15:45:16 -04:00
cbf40f4ec7 hmac-secret should be different when UV=1 2020-03-28 12:28:05 -04:00
8d93f88631 Update STABLE_VERSION 2020-03-27 11:29:11 -04:00
5f8a9a44fc refactor credmgmt 2020-03-27 10:56:51 -04:00
8aa1f4ad01 change parsing TAG_CM to TAG_PARSE 2020-03-27 10:56:51 -04:00
04cffb6509 allow depth-first-search and account for interleaved RK's 2020-03-27 10:56:51 -04:00
f002d08071 Add support for the security manager in Google Chrome
This patch fixes the following issues to make Google Chrome happy:
1. Adds CTAP_CBOR_CRED_MGMT(0x0A) which is an alias to CTAP_CBOR_CRED_MGMT_PRE(0x41)
2. Returns success instead of NO_CREDENTIALS when there are no RKs
3. Skip the "icon" property if it's empty

Tested with Google Chrome Version 80.0.3987.149
2020-03-27 00:22:28 -04:00
e53b83257d Do not return NO_CREDENTIALS if there are no RKs and meta is requested
Fixes-issue: #403
2020-03-27 00:22:28 -04:00
05e149fb17 Update STABLE_VERSION 2020-03-25 15:16:14 -04:00
530e175ad1 cleanup 2020-03-25 14:57:39 -04:00
6cd3873b37 add reboot command for better testing 2020-03-25 14:57:39 -04:00
241f58657b consider credProtect with exclude list, and also check user presence 2020-03-25 14:57:39 -04:00
3b42289cce add rpId to RK's, fix counting of unique RP's 2020-03-25 14:57:39 -04:00
b3712b57fc refactor to reuse more code 2020-03-25 14:57:39 -04:00
37769bb735 to support deleted credentials, need to scan all rk slots since it's no longer continuous 2020-03-25 14:57:39 -04:00
d677f8c346 add rk delete implementations 2020-03-25 14:57:39 -04:00
98bcf647c4 implement rk delete command for cred mgmt 2020-03-25 14:57:39 -04:00
682a443f4e refactor credMgmt to parse as subCommandParams, and get ready for delete command 2020-03-25 14:57:39 -04:00
a28a05673f definitely need to update rpIdHash 2020-03-25 14:57:39 -04:00
3a70ee0ec6 refactor authData and extension handling to work for getNextAssertion 2020-03-25 14:57:39 -04:00
872a320abc Fix credential order: need to start with most recent 2020-03-25 14:57:39 -04:00
3cbf7ec451 move credProtect checking to credential filtering step 2020-03-25 14:57:39 -04:00
748c552eea fix overflow error for 5th resident key 2020-03-25 14:57:39 -04:00
98f996fcfe save some ram 2020-03-25 14:57:39 -04:00
97eb6bba8a bug fix 2020-03-25 14:57:39 -04:00
fdc5a68fcd update info/feature detection details 2020-03-25 14:57:39 -04:00
1c1005a0e8 add credprotect parameter to output 2020-03-25 14:57:39 -04:00
4831410111 add credProtect extension 2020-03-25 14:57:39 -04:00
05bc8bee55 Check return values when parsing CTAP commands 2020-03-21 12:49:05 -04:00
7112633779 Fix user presence test when pinAuth is empty
The check_retr macro is evaluating its argument twice, so when we do:

    check_retr( ctap2_user_presence_test(...) )

the user presence function is called twice and the user has to press the
button twice. This is regression introduced with commit 3b53537.
2020-03-21 12:48:05 -04:00
79b43a90fd Implement commands for management of resident keys
Implement command 0x41 which is used by OpenSSH for reading RKs. It has
the following subcommands:
 * CMD_CRED_METADATA - get number of saved/remaining RKs
 * CMD_RP_BEGIN/CMD_RP_NEXT - iterate over the saved RPs
 * CMD_RK_BEGIN/CMD_RK_NEXT - iterate over the RKs for a given RP

Fixes issue #374 and issue #314
2020-03-21 11:59:22 -04:00
ec7a6fd740 Update STABLE_VERSION 2020-03-16 15:04:45 -04:00
f2d6698066 Update version.c 2020-03-16 14:59:01 -04:00
3c9315e34c Update README.md
Basic steps how to apply updates
2020-03-09 12:06:39 -04:00
8ed7157bfe bump 3.1.2 2020-02-27 15:50:46 -05:00
19 changed files with 1136 additions and 176 deletions

View File

@ -61,9 +61,11 @@ git checkout ${VERSION_TO_BUILD}
git submodule update --init --recursive git submodule update --init --recursive
``` ```
## Installing the toolchain ## Installing the toolchain and applying updates
In order to compile ARM code, you need the ARM compiler and other things like bundling bootloader and firmware require the `solo-python` python package. Check our [documentation](https://docs.solokeys.io/solo/) for details In order to compile ARM code, you need the ARM compiler and other things like bundling bootloader and firmware require the [solo-python](https://github.com/solokeys/solo-python) python package. Check our [documentation](https://docs.solokeys.io/solo/) for details.
You can update your solokey after running `pip3 install solo-python` with `solo key update` for the latest version. To apply a custom image use `solo program bootloader <file>(.json|.hex)`.
## Installing the toolkit and compiling in Docker ## Installing the toolkit and compiling in Docker
Alternatively, you can use Docker to create a container with the toolchain. Alternatively, you can use Docker to create a container with the toolchain.

View File

@ -1 +1 @@
3.1.1 4.0.0

24
default.nix Normal file
View 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,9 @@
#define CTAP_CLIENT_PIN 0x06 #define CTAP_CLIENT_PIN 0x06
#define CTAP_RESET 0x07 #define CTAP_RESET 0x07
#define GET_NEXT_ASSERTION 0x08 #define GET_NEXT_ASSERTION 0x08
#define CTAP_CBOR_CRED_MGMT 0x0A
#define CTAP_VENDOR_FIRST 0x40 #define CTAP_VENDOR_FIRST 0x40
#define CTAP_CBOR_CRED_MGMT_PRE 0x41
#define CTAP_VENDOR_LAST 0xBF #define CTAP_VENDOR_LAST 0xBF
#define MC_clientDataHash 0x01 #define MC_clientDataHash 0x01
@ -37,6 +39,19 @@
#define GA_pinAuth 0x06 #define GA_pinAuth 0x06
#define GA_pinProtocol 0x07 #define GA_pinProtocol 0x07
#define CM_cmd 0x01
#define CM_cmdMetadata 0x01
#define CM_cmdRPBegin 0x02
#define CM_cmdRPNext 0x03
#define CM_cmdRKBegin 0x04
#define CM_cmdRKNext 0x05
#define CM_cmdRKDelete 0x06
#define CM_subCommandParams 0x02
#define CM_subCommandRpId 0x01
#define CM_subCommandCred 0x02
#define CM_pinProtocol 0x03
#define CM_pinAuth 0x04
#define CP_pinProtocol 0x01 #define CP_pinProtocol 0x01
#define CP_subCommand 0x02 #define CP_subCommand 0x02
#define CP_cmdGetRetries 0x01 #define CP_cmdGetRetries 0x01
@ -58,6 +73,11 @@
#define EXT_HMAC_SECRET_REQUESTED 0x01 #define EXT_HMAC_SECRET_REQUESTED 0x01
#define EXT_HMAC_SECRET_PARSED 0x02 #define EXT_HMAC_SECRET_PARSED 0x02
#define EXT_CRED_PROTECT_INVALID 0x00
#define EXT_CRED_PROTECT_OPTIONAL 0x01
#define EXT_CRED_PROTECT_OPTIONAL_WITH_CREDID 0x02
#define EXT_CRED_PROTECT_REQUIRED 0x03
#define RESP_versions 0x1 #define RESP_versions 0x1
#define RESP_extensions 0x2 #define RESP_extensions 0x2
#define RESP_aaguid 0x3 #define RESP_aaguid 0x3
@ -141,16 +161,29 @@ typedef struct
typedef struct { typedef struct {
uint8_t tag[CREDENTIAL_TAG_SIZE]; uint8_t tag[CREDENTIAL_TAG_SIZE];
uint8_t nonce[CREDENTIAL_NONCE_SIZE]; union {
uint8_t nonce[CREDENTIAL_NONCE_SIZE];
struct {
uint8_t _pad[CREDENTIAL_NONCE_SIZE - 4];
uint32_t value;
}__attribute__((packed)) metadata;
}__attribute__((packed)) entropy;
uint8_t rpIdHash[32]; uint8_t rpIdHash[32];
uint32_t count; uint32_t count;
}__attribute__((packed)) CredentialId; }__attribute__((packed)) CredentialId;
struct Credential { struct __attribute__((packed)) Credential {
CredentialId id; CredentialId id;
CTAP_userEntity user; CTAP_userEntity user;
}; };
typedef struct Credential CTAP_residentKey; typedef struct {
CredentialId id;
CTAP_userEntity user;
// Maximum amount of "extra" space in resident key.
uint8_t rpId[48];
uint8_t rpIdSize;
} __attribute__((packed)) CTAP_residentKey;
typedef struct typedef struct
{ {
@ -217,6 +250,7 @@ typedef struct
{ {
uint8_t hmac_secret_present; uint8_t hmac_secret_present;
CTAP_hmac_secret hmac_secret; CTAP_hmac_secret hmac_secret;
uint32_t cred_protect;
} CTAP_extensions; } CTAP_extensions;
typedef struct typedef struct
@ -285,6 +319,26 @@ typedef struct
} CTAP_getAssertion; } CTAP_getAssertion;
typedef struct
{
int cmd;
struct {
uint8_t rpIdHash[32];
CTAP_credentialDescriptor credentialDescriptor;
} subCommandParams;
struct {
uint8_t cmd;
uint8_t subCommandParamsCborCopy[sizeof(CTAP_credentialDescriptor) + 16];
} hashed;
uint32_t subCommandParamsCborSize;
uint8_t pinAuth[16];
uint8_t pinAuthPresent;
int pinProtocol;
} CTAP_credMgmt;
typedef struct typedef struct
{ {
int pinProtocol; int pinProtocol;
@ -303,7 +357,12 @@ typedef struct
struct _getAssertionState { struct _getAssertionState {
CTAP_authDataHeader authData; // Room for both authData struct and extensions
struct {
CTAP_authDataHeader authData;
uint8_t extensions[80];
} __attribute__((packed)) buf;
CTAP_extensions extensions;
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE]; uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE]; CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
uint8_t lastcmd; uint8_t lastcmd;

View File

@ -698,6 +698,14 @@ uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext)
printf1(TAG_RED, "warning: hmac_secret request ignored for being wrong type\r\n"); printf1(TAG_RED, "warning: hmac_secret request ignored for being wrong type\r\n");
} }
} }
else if (strncmp(key, "credProtect",11) == 0) {
if (cbor_value_get_type(&map) == CborIntegerType) {
ret = cbor_value_get_int(&map, (int*)&ext->cred_protect);
check_ret(ret);
} else {
printf1(TAG_RED, "warning: credProtect request ignored for being wrong type\r\n");
}
}
ret = cbor_value_advance(&map); ret = cbor_value_advance(&map);
check_ret(ret); check_ret(ret);
@ -871,7 +879,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
{ {
return ret; return ret;
} }
cbor_value_advance(&map); ret = cbor_value_advance(&map);
check_ret(ret); check_ret(ret);
} }
@ -999,6 +1007,163 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it)
return 0; return 0;
} }
static uint8_t parse_cred_mgmt_subcommandparams(CborValue * val, CTAP_credMgmt * CM)
{
size_t map_length;
int key;
int ret;
unsigned int i;
CborValue map;
size_t sz = 32;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(val,&map);
check_ret(ret);
const uint8_t * start_byte = cbor_value_get_next_byte(&map) - 1;
ret = cbor_value_get_map_length(val, &map_length);
check_ret(ret);
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting integer type for map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
switch(key)
{
case CM_subCommandRpId:
ret = cbor_value_copy_byte_string(&map, CM->subCommandParams.rpIdHash, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, map key is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
check_ret(ret);
break;
case CM_subCommandCred:
ret = parse_credential_descriptor(&map, &CM->subCommandParams.credentialDescriptor);
check_ret(ret);;
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
const uint8_t * end_byte = cbor_value_get_next_byte(&map);
uint32_t length = (uint32_t)end_byte - (uint32_t)start_byte;
if (length > sizeof(CM->hashed.subCommandParamsCborCopy))
{
return CTAP2_ERR_LIMIT_EXCEEDED;
}
// Copy the details that were hashed so they can be verified later.
memmove(CM->hashed.subCommandParamsCborCopy, start_byte, length);
CM->subCommandParamsCborSize = length;
return 0;
}
uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length)
{
int ret;
unsigned int i;
int key;
size_t map_length;
CborParser parser;
CborValue it,map;
memset(CM, 0, sizeof(CTAP_credMgmt));
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret);
CborType type = cbor_value_get_type(&it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(&it,&map);
check_ret(ret);
ret = cbor_value_get_map_length(&it, &map_length);
check_ret(ret);
printf1(TAG_PARSE, "CM map has %d elements\n", map_length);
for (i = 0; i < map_length; i++)
{
type = cbor_value_get_type(&map);
if (type != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
switch(key)
{
case CM_cmd:
printf1(TAG_PARSE, "CM_cmd\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, &CM->cmd);
check_ret(ret);
CM->hashed.cmd = CM->cmd;
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CM_subCommandParams:
printf1(TAG_PARSE, "CM_subCommandParams\n");
ret = parse_cred_mgmt_subcommandparams(&map, CM);
check_ret(ret);
break;
case CM_pinProtocol:
printf1(TAG_PARSE, "CM_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, &CM->pinProtocol);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CM_pinAuth:
printf1(TAG_PARSE, "CM_pinAuth\n");
ret = parse_fixed_byte_string(&map, CM->pinAuth, 16);
check_retr(ret);
CM->pinAuthPresent = 1;
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}
uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length) uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length)
{ {
@ -1132,7 +1297,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
return ret; return ret;
} }
cbor_value_advance(&map); ret = cbor_value_advance(&map);
check_ret(ret); check_ret(ret);
} }

View File

@ -35,6 +35,7 @@ uint8_t parse_cose_key(CborValue * it, COSE_key * cose);
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length); uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length);
uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length); uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length);
uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length);
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length); uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length);
uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred); uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred);

View File

@ -734,6 +734,11 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
ctaphid_write(wb, NULL, 0); ctaphid_write(wb, NULL, 0);
return 1; return 1;
#endif #endif
#if defined(SOLO)
case CTAPHID_REBOOT:
device_reboot();
return 1;
#endif
#if !defined(IS_BOOTLOADER) #if !defined(IS_BOOTLOADER)
case CTAPHID_GETRNG: case CTAPHID_GETRNG:

View File

@ -27,6 +27,7 @@
#define CTAPHID_BOOT (TYPE_INIT | 0x50) #define CTAPHID_BOOT (TYPE_INIT | 0x50)
#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_REBOOT (TYPE_INIT | 0x53)
#define CTAPHID_GETRNG (TYPE_INIT | 0x60) #define CTAPHID_GETRNG (TYPE_INIT | 0x60)
#define CTAPHID_GETVERSION (TYPE_INIT | 0x61) #define CTAPHID_GETVERSION (TYPE_INIT | 0x61)
#define CTAPHID_LOADKEY (TYPE_INIT | 0x62) #define CTAPHID_LOADKEY (TYPE_INIT | 0x62)

View File

@ -185,6 +185,22 @@ __attribute__((weak)) void ctap_store_rk(int index, CTAP_residentKey * rk)
} }
__attribute__((weak)) void ctap_delete_rk(int index)
{
CTAP_residentKey rk;
memset(&rk, 0xff, sizeof(CTAP_residentKey));
if (index < RK_NUM)
{
memmove(RK_STORE.rks + index, &rk, sizeof(CTAP_residentKey));
}
else
{
printf1(TAG_ERR,"Out of bounds for delete_rk\r\n");
}
}
__attribute__((weak)) void ctap_load_rk(int index, CTAP_residentKey * rk) __attribute__((weak)) void ctap_load_rk(int index, CTAP_residentKey * rk)
{ {
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey)); memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));

View File

@ -87,6 +87,24 @@ int device_is_button_pressed();
*/ */
int ctap_user_presence_test(uint32_t delay); 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 /** 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, * requests UP to be disabled. The next call to ctap_user_presence_test should return 2,
* and then UP should be enabled again. * and then UP should be enabled again.
@ -140,6 +158,13 @@ uint32_t ctap_rk_size();
*/ */
void ctap_store_rk(int index,CTAP_residentKey * rk); void ctap_store_rk(int index,CTAP_residentKey * rk);
/** Delete a resident key from an index.
* @param index to delete resident key from. Has no effect if no RK exists at index.
*
* *Optional*, if not implemented, operates on non-persistant RK's.
*/
void ctap_delete_rk(int index);
/** Read a resident key from an index into memory /** Read a resident key from an index into memory
* @param index to read resident key from. * @param index to read resident key from.
* @param rk pointer to resident key structure to write into with RK. * @param rk pointer to resident key structure to write into with RK.

View File

@ -51,6 +51,7 @@ struct logtag tagtable[] = {
{TAG_NFC,"NFC"}, {TAG_NFC,"NFC"},
{TAG_NFC_APDU, "NAPDU"}, {TAG_NFC_APDU, "NAPDU"},
{TAG_CCID, "CCID"}, {TAG_CCID, "CCID"},
{TAG_CM, "CRED_MGMT"},
}; };

View File

@ -48,6 +48,7 @@ typedef enum
TAG_NFC = (1 << 19), TAG_NFC = (1 << 19),
TAG_NFC_APDU = (1 << 20), TAG_NFC_APDU = (1 << 20),
TAG_CCID = (1 << 21), TAG_CCID = (1 << 21),
TAG_CM = (1 << 22),
TAG_NO_TAG = (1UL << 30), TAG_NO_TAG = (1UL << 30),
TAG_FILENO = (1UL << 31) TAG_FILENO = (1UL << 31)

View File

@ -204,7 +204,7 @@ int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t key_handl
printf1(TAG_U2F, "APPID does not match rpIdHash.\n"); printf1(TAG_U2F, "APPID does not match rpIdHash.\n");
return 0; return 0;
} }
make_auth_tag(appid, cred->nonce, cred->count, tag); make_auth_tag(appid, (uint8_t*)&cred->entropy, cred->count, tag);
if (memcmp(cred->tag, tag, CREDENTIAL_TAG_SIZE) == 0){ if (memcmp(cred->tag, tag, CREDENTIAL_TAG_SIZE) == 0){
return 1; return 1;

View File

@ -1,4 +1,5 @@
#include "version.h" #include "version.h"
#include "app.h"
const version_t firmware_version const version_t firmware_version
#ifdef SOLO #ifdef SOLO

View File

@ -449,6 +449,12 @@ void ctap_store_rk(int index, CTAP_residentKey * rk)
} }
void ctap_delete_rk(int index)
{
CTAP_residentKey rk;
memset(&rk, 0xff, sizeof(CTAP_residentKey));
memmove(RK_STORE.rks + index, &rk, sizeof(CTAP_residentKey));
}
void ctap_load_rk(int index, CTAP_residentKey * rk) void ctap_load_rk(int index, CTAP_residentKey * rk)
{ {

13
shell.nix Normal file
View 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 ];
}

View File

@ -61,7 +61,7 @@ SECTIONS
*(.data*) *(.data*)
. = ALIGN(8); . = ALIGN(8);
_edata = .; _edata = .;
} >ram AT> flash } >sram2 AT> flash
.flag : .flag :
{ {

View File

@ -703,7 +703,11 @@ static int wait_for_button_release(uint32_t wait)
return 0; return 0;
} }
int ctap_user_presence_test(uint32_t up_delay) 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; int ret;
@ -741,8 +745,7 @@ int ctap_user_presence_test(uint32_t up_delay)
} }
// Set LED status and wait. // Set LED status and wait.
led_rgb(0xff3520); led_rgb(button_confirm_colour==0?0xff3520:button_confirm_colour);
// Block and wait for some time. // Block and wait for some time.
ret = wait_for_button_activate(up_delay); ret = wait_for_button_activate(up_delay);
if (ret) return ret; if (ret) return ret;
@ -790,33 +793,28 @@ uint32_t ctap_rk_size(void)
void ctap_store_rk(int index,CTAP_residentKey * rk) void ctap_store_rk(int index,CTAP_residentKey * rk)
{ {
int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE; ctap_overwrite_rk(index, rk);
uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + ((sizeof(CTAP_residentKey)*index) % PAGE_SIZE); }
printf1(TAG_GREEN, "storing RK %d @ %04x\r\n", index,addr); void ctap_delete_rk(int index)
{
if (page_offset < RK_NUM_PAGES) CTAP_residentKey rk;
{ memset(&rk, 0xff, sizeof(CTAP_residentKey));
flash_write(addr, (uint8_t*)rk, sizeof(CTAP_residentKey)); ctap_overwrite_rk(index, &rk);
//dump_hex1(TAG_GREEN,rk,sizeof(CTAP_residentKey));
}
else
{
printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index);
}
} }
void ctap_load_rk(int index,CTAP_residentKey * rk) void ctap_load_rk(int index,CTAP_residentKey * rk)
{ {
int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE; int byte_offset_into_page = (sizeof(CTAP_residentKey) * (index % (PAGE_SIZE/sizeof(CTAP_residentKey))));
uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + ((sizeof(CTAP_residentKey)*index) % PAGE_SIZE); int page_offset = (index)/(PAGE_SIZE/sizeof(CTAP_residentKey));
uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + byte_offset_into_page;
printf1(TAG_GREEN, "reading RK %d @ %04x\r\n", index, addr); printf1(TAG_GREEN, "reading RK %d @ %04x\r\n", index, addr);
if (page_offset < RK_NUM_PAGES) if (page_offset < RK_NUM_PAGES)
{ {
uint32_t * ptr = (uint32_t *)addr; uint32_t * ptr = (uint32_t *)addr;
memmove((uint8_t*)rk,ptr,sizeof(CTAP_residentKey)); memmove((uint8_t*)rk,ptr,sizeof(CTAP_residentKey));
//dump_hex1(TAG_GREEN,rk,sizeof(CTAP_residentKey));
} }
else else
{ {
@ -827,22 +825,28 @@ void ctap_load_rk(int index,CTAP_residentKey * rk)
void ctap_overwrite_rk(int index,CTAP_residentKey * rk) void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
{ {
uint8_t tmppage[PAGE_SIZE]; uint8_t tmppage[PAGE_SIZE];
int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE;
int page = page_offset + RK_START_PAGE;
printf1(TAG_GREEN, "overwriting RK %d\r\n", index); int byte_offset_into_page = (sizeof(CTAP_residentKey) * (index % (PAGE_SIZE/sizeof(CTAP_residentKey))));
int page_offset = (index)/(PAGE_SIZE/sizeof(CTAP_residentKey));
printf1(TAG_GREEN, "overwriting RK %d @ page %d @ addr 0x%08x-0x%08x\r\n",
index, RK_START_PAGE + page_offset,
flash_addr(RK_START_PAGE + page_offset) + byte_offset_into_page,
flash_addr(RK_START_PAGE + page_offset) + byte_offset_into_page + sizeof(CTAP_residentKey)
);
if (page_offset < RK_NUM_PAGES) if (page_offset < RK_NUM_PAGES)
{ {
memmove(tmppage, (uint8_t*)flash_addr(page), PAGE_SIZE); memmove(tmppage, (uint8_t*)flash_addr(RK_START_PAGE + page_offset), PAGE_SIZE);
memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey)); memmove(tmppage + byte_offset_into_page, rk, sizeof(CTAP_residentKey));
flash_erase_page(page); flash_erase_page(RK_START_PAGE + page_offset);
flash_write(flash_addr(page), tmppage, PAGE_SIZE); flash_write(flash_addr(RK_START_PAGE + page_offset), tmppage, PAGE_SIZE);
} }
else else
{ {
printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index); printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index);
} }
printf1(TAG_GREEN, "4\r\n");
} }
void boot_st_bootloader(void) void boot_st_bootloader(void)