Compare commits
59 Commits
Author | SHA1 | Date | |
---|---|---|---|
ec52ca2605 | |||
5d2acf19f1 | |||
6196481b7f | |||
f002d08071 | |||
e53b83257d | |||
05e149fb17 | |||
530e175ad1 | |||
6cd3873b37 | |||
241f58657b | |||
3b42289cce | |||
b3712b57fc | |||
37769bb735 | |||
d677f8c346 | |||
98bcf647c4 | |||
682a443f4e | |||
a28a05673f | |||
3a70ee0ec6 | |||
872a320abc | |||
3cbf7ec451 | |||
748c552eea | |||
98f996fcfe | |||
97eb6bba8a | |||
fdc5a68fcd | |||
1c1005a0e8 | |||
4831410111 | |||
05bc8bee55 | |||
7112633779 | |||
79b43a90fd | |||
ec7a6fd740 | |||
f2d6698066 | |||
3c9315e34c | |||
8ed7157bfe | |||
28a1b1cc06 | |||
5738bcc7a3 | |||
4fb166631d | |||
1b862d3b0c | |||
094420b32b | |||
349cbc39f2 | |||
e294cb3458 | |||
da31f984dd | |||
9d3e8c06fc | |||
b378bbf61d | |||
04b89a9739 | |||
0d28a7bcf6 | |||
aeafd09007 | |||
8b6148ac90 | |||
15a4fdfa66 | |||
e713daba26 | |||
b78f2cd2e7 | |||
601c98000a | |||
ab1c9417b1 | |||
f6d96013e1 | |||
f74dba7ff0 | |||
794accf3dc | |||
2ca0ced808 | |||
17b430fd44 | |||
0d4197fb2c | |||
f74a77d80b | |||
5f1d61a3ba |
3
Makefile
3
Makefile
@ -100,9 +100,10 @@ uncached-docker-build-toolchain:
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN}
|
||||
|
||||
docker-build-all:
|
||||
docker-build-all:
|
||||
docker run --rm -v "$(CURDIR)/builds:/builds" \
|
||||
-v "$(CURDIR):/solo" \
|
||||
-u $(shell id -u ${USER}):$(shell id -g ${USER}) \
|
||||
$(DOCKER_TOOLCHAIN_IMAGE) "solo/in-docker-build.sh" ${SOLO_VERSION_FULL}
|
||||
|
||||
CPPCHECK_FLAGS=--quiet --error-exitcode=2
|
||||
|
@ -61,9 +61,11 @@ git checkout ${VERSION_TO_BUILD}
|
||||
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
|
||||
Alternatively, you can use Docker to create a container with the toolchain.
|
||||
|
@ -1 +1 @@
|
||||
3.0.0
|
||||
3.2.0
|
||||
|
@ -1,16 +1,23 @@
|
||||
# Using Solo for passwordless or second factor login on Linux
|
||||
|
||||
## Setup on Ubuntu 18.04
|
||||
## Setup on Ubuntu and Manjaro
|
||||
Before you can use Solo for passwordless or second factor login in your Linux system you have to install some packages.
|
||||
|
||||
This was tested under **Linux Mint 19.2**.
|
||||
|
||||
This was tested on **Linux Mint 19.3** and on **Manjaro 18.x**
|
||||
|
||||
First you have to install PAM modules for u2f.
|
||||
|
||||
**Ubuntu (Linux Mint):**
|
||||
```
|
||||
sudo apt install libpam-u2f pamu2fcfg
|
||||
```
|
||||
|
||||
**Manjaro**
|
||||
```
|
||||
pacman -Syu pam-u2f
|
||||
```
|
||||
|
||||
|
||||
## Setting up key
|
||||
To use Solo as passwordless or second factor login, you have to setup your system with your Solo.
|
||||
First create a new folder named **Yubico** in your **.config** folder in your **home** directory
|
||||
@ -28,35 +35,57 @@ If you want to register an additional key use this command instead:
|
||||
pamu2fcfg >> ~/.config/Yubico/u2f_keys
|
||||
```
|
||||
Now press the button on your Solo.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
If you can't generate your key (error message), you may add Yubico Team from PPA and install latest libpam-u2f and pamu2fcfg and try again.
|
||||
If you can't generate your key on **Ubuntu** (error message), you may add Yubico Team from PPA and install latest libpam-u2f and pamu2fcfg and try again.
|
||||
```
|
||||
sudo add-apt-repository ppa:yubico/stable
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
```
|
||||
|
||||
**Manjaro** should work without problems.
|
||||
|
||||
|
||||
## Login into Linux
|
||||
### Passwordless
|
||||
To login passwordless into your Linux system, you have to edit the file **lightdm** (or **gdm** or which display manager you prefered).
|
||||
In case of lightdm:
|
||||
In case of lightdm and VIM as editor:
|
||||
|
||||
```
|
||||
sudo vim /etc/pam.d/lightdm
|
||||
sudo vim /etc/pam.d/lightdm
|
||||
```
|
||||
Now search following entry:
|
||||
|
||||
**On Ubuntu:**<br>
|
||||
Search following entry:
|
||||
```
|
||||
@include common-auth
|
||||
@include common-auth
|
||||
```
|
||||
and add
|
||||
```
|
||||
auth sufficient pam_u2f.so
|
||||
auth sufficient pam_u2f.so
|
||||
```
|
||||
**before** @include common-auth.
|
||||
**before** *@include common-auth.*
|
||||
<br>
|
||||
<br>
|
||||
|
||||
Save the file and test it.<br>
|
||||
**On Manjaro**<br>
|
||||
Search following enrty
|
||||
```
|
||||
auth include system-login
|
||||
```
|
||||
|
||||
and add
|
||||
```
|
||||
auth sufficient pam_u2f.so
|
||||
```
|
||||
|
||||
** before** *auth include system-login*.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
Now save the file and test it.<br>
|
||||
Insert Solo in your USB port and logout.
|
||||
Now you should be able to login into Linux without password, only with pressing your button on Solo and press enter.
|
||||
|
||||
@ -65,7 +94,7 @@ Why **sufficient**? The difference between the keyword sufficient and required i
|
||||
|
||||
The login mechanism can be also used for additional features like:
|
||||
|
||||
: - Login after screen timeout - edit /etc/pam.d/mate-screensaver (or kde-screensaver, ...)
|
||||
- Login after screen timeout - edit /etc/pam.d/mate-screensaver (or kde-screensaver, ...)
|
||||
- Passwordless sudo - edit /etc/pam.d/sudo
|
||||
|
||||
Check out your folder **/etc/pam.d/** and do some experiments.
|
||||
@ -78,17 +107,36 @@ The login passwordless won't make your system more secure, but maybe more comfor
|
||||
To use Solo as second factor, for login into your Linux system, is nearly the same.
|
||||
|
||||
```
|
||||
sudo vim /etc/pam.d/lightdm
|
||||
sudo vim /etc/pam.d/lightdm
|
||||
```
|
||||
Now search following entry:
|
||||
|
||||
**On Ubuntu**<br>
|
||||
Search following entry:
|
||||
```
|
||||
@include common-auth
|
||||
@include common-auth
|
||||
```
|
||||
and add
|
||||
```
|
||||
auth required pam_u2f.so
|
||||
auth required pam_u2f.so
|
||||
```
|
||||
**after** @include common-auth.
|
||||
**after** *@include common-auth*.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
**On Manjaro**<br>
|
||||
Search following entry:
|
||||
```
|
||||
auth include system-login
|
||||
```
|
||||
|
||||
Add following entry
|
||||
```
|
||||
auth required pam_u2f.so
|
||||
```
|
||||
|
||||
**after** *auth include system-login*.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
Save the file and test it. <br>
|
||||
In case your Solo is not present, your password will be incrorrect. If Solo is plugged into your USB port, it will signal pressing the button and you will be able to login into Linux.
|
||||
|
@ -104,9 +104,24 @@ solo mergehex bootloader.hex solo.hex bundle.hex
|
||||
|
||||
`bundle.hex` is our complete firmware build. Note it is in this step that you can
|
||||
include a custom attestation certificate or lock the device from debugging/DFU.
|
||||
By default the "hacker" attestation certifcate and key is used.
|
||||
By default the "hacker" attestation certifcate and key is used. Use the `--lock` flag
|
||||
to make this permanent.
|
||||
|
||||
```
|
||||
solo mergehex \
|
||||
--attestation-key "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" \
|
||||
--attestation-cert attestation.der \
|
||||
solo.hex \
|
||||
bootloader.hex \
|
||||
bundle.hex
|
||||
```
|
||||
|
||||
**Warning**: If you use `--lock`, this will permanently lock the device to this new bootloader. You
|
||||
won't be able to program the bootloader again or be able to connect a hardware debugger.
|
||||
The new bootloader may be able to accept (signed) updates still, depending on how you configured it.
|
||||
|
||||
```
|
||||
# Permanent!
|
||||
solo mergehex \
|
||||
--attestation-key "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" \
|
||||
--attestation-cert attestation.der \
|
||||
@ -118,9 +133,5 @@ solo mergehex \
|
||||
|
||||
See [here for more information on custom attestation](/solo/customization/).
|
||||
|
||||
If you use `--lock`, this will permanently lock the device to this new bootloader. You
|
||||
won't be able to program the bootloader again or be able to connect a hardware debugger.
|
||||
The new bootloader may be able to accept (signed) updates still, depending on how you configured it.
|
||||
|
||||
To learn more about normal updates or a "full" update, you should [read more on Solo's boot stages](/solo/bootloader-mode).
|
||||
|
||||
|
@ -45,7 +45,7 @@ email=example@example.com
|
||||
openssl ecparam -genkey -name "$curve" -out root_key.pem -rand seed.bin
|
||||
|
||||
# generate a "signing request"
|
||||
openssl req -new -key root_key.pem -out root_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=example.com/emailAddress=$email"
|
||||
openssl req -new -key root_key.pem -out root_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=$CN/emailAddress=$email"
|
||||
|
||||
# self sign the request
|
||||
openssl x509 -trustout -req -days 18250 -in root_key.pem.csr -signkey root_key.pem -out root_cert.pem -sha256
|
||||
@ -74,7 +74,7 @@ Note you must use a prime256v1 curve for this step, and you must leave the unit/
|
||||
country=US
|
||||
state=Maine
|
||||
organization=OpenSourceSecurity
|
||||
unit="Authenticator Attestation"
|
||||
unit="Authenticator Attestation" # MUST KEEP THIS AS "Authenticator Attestation" for FIDO2.
|
||||
CN=example.com
|
||||
email=example@example.com
|
||||
|
||||
@ -82,7 +82,7 @@ email=example@example.com
|
||||
openssl ecparam -genkey -name "$curve" -out device_key.pem -rand seed.bin
|
||||
|
||||
# generate a "signing request"
|
||||
openssl req -new -key device_key.pem -out device_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=example.com/emailAddress=$email"
|
||||
openssl req -new -key device_key.pem -out device_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=$CN/emailAddress=$email"
|
||||
|
||||
# sign the request
|
||||
openssl x509 -req -days 18250 -in device_key.pem.csr -extfile v3.ext -CA root_cert.pem -CAkey root_key.pem -set_serial 01 -out device_cert.pem -sha256
|
||||
@ -119,7 +119,7 @@ First, [Build your solo application and bootloader](/solo/building).
|
||||
Print your attestation key in a hex string format. Using our utility script:
|
||||
|
||||
```
|
||||
python tools/print_x_y.py device_key.pem
|
||||
python3 tools/gencert/print_x_y.py device_key.pem
|
||||
```
|
||||
|
||||
Merge the `bootloader.hex`, `solo.hex`, attestion key, and certificate into one firmware file.
|
||||
@ -134,6 +134,8 @@ solo mergehex \
|
||||
bundle.hex
|
||||
```
|
||||
|
||||
**Warning**: Using the `--lock` flag prevents the DFU from being accessed on the device again. It's recommended to try first without the `--lock` flag to make sure it works.
|
||||
|
||||
Now you have a newly created `bundle.hex` file with a custom attestation key and cert. You can [program this `bundle.hex` file
|
||||
with Solo in DFU mode](/solo/programming#procedure).
|
||||
|
||||
|
@ -36,9 +36,13 @@ So it's important to not mess this up or you may brick your device.
|
||||
You can use a firmware build from the [latest release](https://github.com/solokeys/solo/releases) or use
|
||||
a build that you made yourself.
|
||||
|
||||
You need to use a firmware file that has the combined bootloader and application (or at the very least just the bootloader).
|
||||
This means using the `bundle-*.hex` file or the `bundle.hex` from your build. If you overwrite the Solo flash with a missing bootloader,
|
||||
it will be bricked.
|
||||
You need to use a firmware file that has the combined bootloader, application, and attestation key pair (bootloader + firmware + key).
|
||||
This means using the `bundle-*.hex` file or the `bundle.hex` from your build.
|
||||
|
||||
#### *Warning*
|
||||
|
||||
* **If you overwrite the Solo flash with a missing bootloader, it will be bricked**.
|
||||
* **If you program bootloader and firmware with no attestation, you will run into FIDO registration issues**
|
||||
|
||||
We provide two types of bundled builds. The `bundle-hacker-*.hex` build is the hacker build. If you update with this,
|
||||
you will update the bootloader and application, but nothing will be secured. The `bundle-secure-non-solokeys.hex`
|
||||
|
871
fido2/ctap.c
871
fido2/ctap.c
File diff suppressed because it is too large
Load Diff
67
fido2/ctap.h
67
fido2/ctap.h
@ -16,7 +16,9 @@
|
||||
#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
|
||||
|
||||
#define MC_clientDataHash 0x01
|
||||
@ -37,6 +39,19 @@
|
||||
#define GA_pinAuth 0x06
|
||||
#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_subCommand 0x02
|
||||
#define CP_cmdGetRetries 0x01
|
||||
@ -58,6 +73,11 @@
|
||||
#define EXT_HMAC_SECRET_REQUESTED 0x01
|
||||
#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_extensions 0x2
|
||||
#define RESP_aaguid 0x3
|
||||
@ -141,16 +161,29 @@ typedef struct
|
||||
|
||||
typedef struct {
|
||||
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];
|
||||
uint32_t count;
|
||||
}__attribute__((packed)) CredentialId;
|
||||
|
||||
struct Credential {
|
||||
struct __attribute__((packed)) Credential {
|
||||
CredentialId id;
|
||||
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
|
||||
{
|
||||
@ -217,6 +250,7 @@ typedef struct
|
||||
{
|
||||
uint8_t hmac_secret_present;
|
||||
CTAP_hmac_secret hmac_secret;
|
||||
uint32_t cred_protect;
|
||||
} CTAP_extensions;
|
||||
|
||||
typedef struct
|
||||
@ -285,6 +319,26 @@ typedef struct
|
||||
|
||||
} 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
|
||||
{
|
||||
int pinProtocol;
|
||||
@ -303,7 +357,12 @@ typedef struct
|
||||
|
||||
|
||||
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];
|
||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
||||
uint8_t lastcmd;
|
||||
|
@ -666,8 +666,8 @@ uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext)
|
||||
if (ret == CborErrorOutOfMemory)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, rp map key is too large. Ignoring.\n");
|
||||
cbor_value_advance(&map);
|
||||
cbor_value_advance(&map);
|
||||
check_ret( cbor_value_advance(&map) );
|
||||
check_ret( cbor_value_advance(&map) );
|
||||
continue;
|
||||
}
|
||||
check_ret(ret);
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
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);
|
||||
check_ret(ret);
|
||||
@ -871,7 +879,7 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
cbor_value_advance(&map);
|
||||
ret = cbor_value_advance(&map);
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
@ -999,6 +1007,163 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it)
|
||||
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)
|
||||
{
|
||||
@ -1132,7 +1297,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
||||
return ret;
|
||||
}
|
||||
|
||||
cbor_value_advance(&map);
|
||||
ret = cbor_value_advance(&map);
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
@ -1353,11 +1518,21 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
|
||||
break;
|
||||
case CP_getKeyAgreement:
|
||||
printf1(TAG_CP,"CP_getKeyAgreement\n");
|
||||
if (cbor_value_get_type(&map) != CborBooleanType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, expecting cbor boolean\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
ret = cbor_value_get_boolean(&map, &CP->getKeyAgreement);
|
||||
check_ret(ret);
|
||||
break;
|
||||
case CP_getRetries:
|
||||
printf1(TAG_CP,"CP_getRetries\n");
|
||||
if (cbor_value_get_type(&map) != CborBooleanType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, expecting cbor boolean\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
ret = cbor_value_get_boolean(&map, &CP->getRetries);
|
||||
check_ret(ret);
|
||||
break;
|
||||
|
@ -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_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 parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred);
|
||||
|
||||
|
@ -542,6 +542,9 @@ extern void _check_ret(CborError ret, int line, const char * filename);
|
||||
|
||||
uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb);
|
||||
|
||||
|
||||
extern void solo_lock_if_not_already();
|
||||
|
||||
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
{
|
||||
uint8_t cmd = 0;
|
||||
@ -731,6 +734,11 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
||||
ctaphid_write(wb, NULL, 0);
|
||||
return 1;
|
||||
#endif
|
||||
#if defined(SOLO)
|
||||
case CTAPHID_REBOOT:
|
||||
device_reboot();
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#if !defined(IS_BOOTLOADER)
|
||||
case CTAPHID_GETRNG:
|
||||
@ -762,34 +770,51 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
||||
return 1;
|
||||
break;
|
||||
|
||||
// Remove on next release
|
||||
#if !defined(IS_BOOTLOADER) && defined(SOLO)
|
||||
case 0x99:
|
||||
solo_lock_if_not_already();
|
||||
wb->bcnt = 0;
|
||||
ctaphid_write(wb, NULL, 0);
|
||||
return 1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_EXPERIMENTAL))
|
||||
case CTAPHID_LOADKEY:
|
||||
/**
|
||||
* Load external key. Useful for enabling backups.
|
||||
* bytes: 4 96
|
||||
* payload: | counter_increase (BE) | master_key |
|
||||
* bytes: 4 4 96
|
||||
* payload: version [maj rev patch RFU]| counter_replacement (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)
|
||||
if (len != 104)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, invalid length.\n");
|
||||
ctaphid_send_error(wb->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return 1;
|
||||
}
|
||||
param = ctap_buffer[0] << 16;
|
||||
param |= ctap_buffer[1] << 8;
|
||||
param |= ctap_buffer[2] << 0;
|
||||
if (param != 0){
|
||||
ctaphid_send_error(wb->cid, CTAP2_ERR_UNSUPPORTED_OPTION);
|
||||
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)
|
||||
if (ctap_user_presence_test(2000) > 0)
|
||||
if (ctap_user_presence_test(2000) > 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_load_external_keys(ctap_buffer + 8);
|
||||
param = ctap_buffer[7];
|
||||
param |= ctap_buffer[6] << 8;
|
||||
param |= ctap_buffer[5] << 16;
|
||||
param |= ctap_buffer[4] << 24;
|
||||
ctap_atomic_count(param);
|
||||
|
||||
wb->bcnt = 0;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define CTAPHID_BOOT (TYPE_INIT | 0x50)
|
||||
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
|
||||
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
|
||||
#define CTAPHID_REBOOT (TYPE_INIT | 0x53)
|
||||
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
|
||||
#define CTAPHID_GETVERSION (TYPE_INIT | 0x61)
|
||||
#define CTAPHID_LOADKEY (TYPE_INIT | 0x62)
|
||||
|
@ -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)
|
||||
{
|
||||
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));
|
||||
|
@ -140,6 +140,13 @@ uint32_t ctap_rk_size();
|
||||
*/
|
||||
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
|
||||
* @param index to read resident key from.
|
||||
* @param rk pointer to resident key structure to write into with RK.
|
||||
|
@ -51,6 +51,7 @@ struct logtag tagtable[] = {
|
||||
{TAG_NFC,"[1;38mNFC[0m"},
|
||||
{TAG_NFC_APDU, "NAPDU"},
|
||||
{TAG_CCID, "CCID"},
|
||||
{TAG_CM, "CRED_MGMT"},
|
||||
};
|
||||
|
||||
|
||||
|
@ -48,6 +48,7 @@ typedef enum
|
||||
TAG_NFC = (1 << 19),
|
||||
TAG_NFC_APDU = (1 << 20),
|
||||
TAG_CCID = (1 << 21),
|
||||
TAG_CM = (1 << 22),
|
||||
|
||||
TAG_NO_TAG = (1UL << 30),
|
||||
TAG_FILENO = (1UL << 31)
|
||||
|
@ -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");
|
||||
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){
|
||||
return 1;
|
||||
|
@ -1,12 +1,17 @@
|
||||
#include "version.h"
|
||||
#include "app.h"
|
||||
|
||||
const version_t firmware_version
|
||||
#ifdef SOLO
|
||||
__attribute__ ((section (".flag"))) __attribute__ ((__used__))
|
||||
#endif
|
||||
= {
|
||||
.major = SOLO_VERSION_MAJ,
|
||||
.minor = SOLO_VERSION_MIN,
|
||||
.patch = SOLO_VERSION_PATCH,
|
||||
.reserved = 0
|
||||
};
|
||||
|
||||
const version_t firmware_version __attribute__ ((section (".flag"))) __attribute__ ((__used__)) = {
|
||||
.major = SOLO_VERSION_MAJ,
|
||||
.minor = SOLO_VERSION_MIN,
|
||||
.patch = SOLO_VERSION_PATCH,
|
||||
.reserved = 0
|
||||
};
|
||||
|
||||
// from tinycbor, for a quick static_assert
|
||||
#include <compilersupport_p.h>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -50,12 +50,15 @@ typedef struct {
|
||||
uint8_t payload[255 - 10];
|
||||
} __attribute__((packed)) BootloaderReq;
|
||||
|
||||
uint8_t * last_written_app_address = 0;
|
||||
|
||||
/**
|
||||
* Erase all application pages. **APPLICATION_END_PAGE excluded**.
|
||||
*/
|
||||
static void erase_application()
|
||||
{
|
||||
int page;
|
||||
last_written_app_address = (uint8_t*) 0;
|
||||
for(page = APPLICATION_START_PAGE; page < APPLICATION_END_PAGE; page++)
|
||||
{
|
||||
flash_erase_page(page);
|
||||
@ -106,17 +109,20 @@ int is_bootloader_disabled()
|
||||
uint32_t * auth = (uint32_t *)(AUTH_WORD_ADDR+4);
|
||||
return *auth == 0;
|
||||
}
|
||||
uint8_t * last_written_app_address;
|
||||
|
||||
#include "version.h"
|
||||
bool is_firmware_version_newer_or_equal()
|
||||
{
|
||||
|
||||
if (last_written_app_address == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf1(TAG_BOOT,"Current firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
|
||||
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
|
||||
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
|
||||
);
|
||||
volatile version_t * new_version = ((volatile version_t *) last_written_app_address);
|
||||
volatile version_t * new_version = ((volatile version_t *) (last_written_app_address-8+4));
|
||||
printf1(TAG_BOOT,"Uploaded firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
|
||||
new_version->major, new_version->minor, new_version->patch, new_version->reserved,
|
||||
new_version->major, new_version->minor, new_version->patch, new_version->reserved
|
||||
@ -170,6 +176,7 @@ int bootloader_bridge(int klen, uint8_t * keyh)
|
||||
uint32_t addr = ((*((uint32_t*)req->addr)) & 0xffffff) | 0x8000000;
|
||||
|
||||
uint32_t * ptr = (uint32_t *)addr;
|
||||
uint32_t current_address;
|
||||
|
||||
switch(req->op){
|
||||
case BootWrite:
|
||||
@ -196,9 +203,16 @@ int bootloader_bridge(int klen, uint8_t * keyh)
|
||||
printf2(TAG_ERR, "Error, boot check bypassed\n");
|
||||
exit(1);
|
||||
}
|
||||
current_address = addr + len;
|
||||
if (current_address < (uint32_t) last_written_app_address) {
|
||||
printf2(TAG_ERR, "Error, only ascending writes allowed.\n");
|
||||
has_erased = 0;
|
||||
return CTAP2_ERR_NOT_ALLOWED;
|
||||
}
|
||||
last_written_app_address = (uint8_t*) current_address;
|
||||
|
||||
// Do the actual write
|
||||
flash_write((uint32_t)ptr,req->payload, len);
|
||||
last_written_app_address = (uint8_t *)ptr + len - 8 + 4;
|
||||
break;
|
||||
case BootDone:
|
||||
// Writing to flash finished. Request code validation.
|
||||
|
@ -84,4 +84,5 @@ cbor:
|
||||
cd ../../tinycbor/ && make clean
|
||||
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
|
||||
LDFLAGS="$(LDFLAGS_LIB)" \
|
||||
CFLAGS="$(CFLAGS) -Os"
|
||||
CFLAGS="$(CFLAGS) -Os -DCBOR_PARSER_MAX_RECURSIONS=3"
|
||||
|
||||
|
@ -61,7 +61,7 @@ SECTIONS
|
||||
*(.data*)
|
||||
. = ALIGN(8);
|
||||
_edata = .;
|
||||
} >ram AT> flash
|
||||
} >sram2 AT> flash
|
||||
|
||||
.flag :
|
||||
{
|
||||
|
@ -199,6 +199,20 @@ int solo_is_locked(){
|
||||
return tag == ATTESTATION_CONFIGURED_TAG && (device_settings & SOLO_FLAG_LOCKED) != 0;
|
||||
}
|
||||
|
||||
// Locks solo flash from debugging. Locks on next reboot.
|
||||
// This should be removed in next Solo release.
|
||||
void solo_lock_if_not_already() {
|
||||
uint8_t buf[2048];
|
||||
|
||||
memmove(buf, (uint8_t*)ATTESTATION_PAGE_ADDR, 2048);
|
||||
|
||||
((flash_attestation_page *)buf)->device_settings |= SOLO_FLAG_LOCKED;
|
||||
|
||||
flash_erase_page(ATTESTATION_PAGE);
|
||||
|
||||
flash_write(ATTESTATION_PAGE_ADDR, buf, 2048);
|
||||
}
|
||||
|
||||
/** device_migrate
|
||||
* Depending on version of device, migrates:
|
||||
* * Moves attestation certificate to data segment.
|
||||
@ -563,7 +577,11 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
||||
return lastc;
|
||||
}
|
||||
|
||||
lastc += amount;
|
||||
if (amount > 256){
|
||||
lastc = amount;
|
||||
} else {
|
||||
lastc += amount;
|
||||
}
|
||||
|
||||
if (lastc/256 > erases)
|
||||
{
|
||||
@ -772,33 +790,28 @@ uint32_t ctap_rk_size(void)
|
||||
|
||||
void ctap_store_rk(int index,CTAP_residentKey * rk)
|
||||
{
|
||||
int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE;
|
||||
uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + ((sizeof(CTAP_residentKey)*index) % PAGE_SIZE);
|
||||
ctap_overwrite_rk(index, rk);
|
||||
}
|
||||
|
||||
printf1(TAG_GREEN, "storing RK %d @ %04x\r\n", index,addr);
|
||||
|
||||
if (page_offset < RK_NUM_PAGES)
|
||||
{
|
||||
flash_write(addr, (uint8_t*)rk, sizeof(CTAP_residentKey));
|
||||
//dump_hex1(TAG_GREEN,rk,sizeof(CTAP_residentKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index);
|
||||
}
|
||||
void ctap_delete_rk(int index)
|
||||
{
|
||||
CTAP_residentKey rk;
|
||||
memset(&rk, 0xff, sizeof(CTAP_residentKey));
|
||||
ctap_overwrite_rk(index, &rk);
|
||||
}
|
||||
|
||||
void ctap_load_rk(int index,CTAP_residentKey * rk)
|
||||
{
|
||||
int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE;
|
||||
uint32_t addr = flash_addr(page_offset + RK_START_PAGE) + ((sizeof(CTAP_residentKey)*index) % PAGE_SIZE);
|
||||
int byte_offset_into_page = (sizeof(CTAP_residentKey) * (index % (PAGE_SIZE/sizeof(CTAP_residentKey))));
|
||||
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);
|
||||
if (page_offset < RK_NUM_PAGES)
|
||||
{
|
||||
uint32_t * ptr = (uint32_t *)addr;
|
||||
memmove((uint8_t*)rk,ptr,sizeof(CTAP_residentKey));
|
||||
//dump_hex1(TAG_GREEN,rk,sizeof(CTAP_residentKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -809,22 +822,28 @@ void ctap_load_rk(int index,CTAP_residentKey * rk)
|
||||
void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
|
||||
{
|
||||
uint8_t tmppage[PAGE_SIZE];
|
||||
int page_offset = (sizeof(CTAP_residentKey) * index) / PAGE_SIZE;
|
||||
int page = page_offset + RK_START_PAGE;
|
||||
|
||||
printf1(TAG_GREEN, "overwriting RK %d\r\n", index);
|
||||
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)
|
||||
{
|
||||
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));
|
||||
flash_erase_page(page);
|
||||
flash_write(flash_addr(page), tmppage, PAGE_SIZE);
|
||||
memmove(tmppage + byte_offset_into_page, rk, sizeof(CTAP_residentKey));
|
||||
flash_erase_page(RK_START_PAGE + page_offset);
|
||||
flash_write(flash_addr(RK_START_PAGE + page_offset), tmppage, PAGE_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR,"Out of bounds reading index %d for rk\n", index);
|
||||
}
|
||||
printf1(TAG_GREEN, "4\r\n");
|
||||
}
|
||||
|
||||
void boot_st_bootloader(void)
|
||||
|
@ -146,12 +146,14 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
||||
case DEVICE_LOW_POWER_IDLE:
|
||||
SET_CLOCK_RATE0();
|
||||
break;
|
||||
#if !defined(IS_BOOTLOADER)
|
||||
case DEVICE_LOW_POWER_FAST:
|
||||
SET_CLOCK_RATE1();
|
||||
break;
|
||||
case DEVICE_FAST:
|
||||
SET_CLOCK_RATE2();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
ecdsa
|
||||
fido2==0.7.3
|
||||
intelhex
|
||||
pyserial
|
||||
solo-python
|
||||
|
Reference in New Issue
Block a user