Compare commits

...

7 Commits

Author SHA1 Message Date
Conor Patrick
f019d7fc22 remove binary count check 2019-10-28 10:36:01 -04:00
Conor Patrick
e3409ca613 update docs 2019-10-28 10:33:54 -04:00
Conor Patrick
81ec63f17a check attestation tag 2019-10-27 16:10:01 -04:00
Conor Patrick
e4bc364c38 do not lock flash when booting to dfu 2019-10-27 16:07:36 -04:00
Conor Patrick
4c464c9cc4 add git 2019-10-27 14:33:32 -04:00
Conor Patrick
8ecaa9a3de remove hacker/secure builds 2019-10-27 13:10:35 -04:00
Conor Patrick
98803b7dd0 fix issue with bootloader not replying data 2019-10-27 11:52:44 -04:00
12 changed files with 110 additions and 87 deletions

View File

@ -8,6 +8,7 @@ RUN apt-get update \
make \
wget \
bzip2 \
git \
&& rm -rf /var/lib/apt/lists/*
# Install ARM compiler

View File

@ -138,10 +138,6 @@ test-docker:
# Check if there are 4 docker images/tas named "solokeys/solo-firmware-toolchain"
NTAGS=$$(docker images | grep -c "solokeys/solo-firmware-toolchain") && [ $$NTAGS -eq 4 ]
$(MAKE) docker-build-all
# Check that the builds were created
NFILES=$$(ls -l builds | grep -c "bootloader") && [ $$NFILES -eq 4 ]
NFILES=$$(ls -l builds | grep -c "bundle") && [ $$NFILES -eq 6 ]
NFILES=$$(ls -l builds | grep -c "firmware") && [ $$NFILES -eq 10 ]
travis:
$(MAKE) test VENV=". ../../venv/bin/activate;"

View File

@ -1,16 +1,17 @@
# Booting into bootloader mode
You can put Solo into bootloader mode by holding down the button, and plugging in Solo. After 2 seconds, bootloader mode will activate.
You'll see a yellowish flashing light and you can let go of the button.
Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
If Solo is running a hacker build, it can be put into bootloader mode on command. This makes it easier for development.
If you have a recent version of Solo, you can put it into bootloader mode by running this command.
```bash
solo program aux enter-bootloader
```
If your Solo is a bit older (<=2.5.3) You can put Solo into bootloader mode by using the button method:
Hold down button while plugging in Solo. After 2 seconds, bootloader mode will activate.
You'll see a yellowish flashing light and you can let go of the button.
Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
# The boot stages of Solo
Solo has 3 boot stages.
@ -21,7 +22,8 @@ The first stage is the DFU (Device Firmware Update) which is in a ROM on Solo.
This is what allows the entire firmware of Solo to be programmed. **It's not recommended to develop for Solo using the DFU because
if you program broken firmware, you could brick your device**.
On hacker devices, you can boot into the DFU by holding down the button for 5 seconds, when Solo is already in bootloader mode.
On hacker/nonverifying-bootloader devices, you can boot into the DFU by holding down the button for 5 seconds,
when Solo is already in bootloader mode.
You can also run this command when Solo is in bootloader mode to put it in DFU mode.
@ -29,7 +31,7 @@ You can also run this command when Solo is in bootloader mode to put it in DFU m
solo program aux enter-dfu
```
Note it will stay in DFU mode until to tell it to boot again. You can boot it again by running the following.
Note it will stay in DFU mode until you to tell it to boot again. You can boot it again by running the following.
```bash
solo program aux leave-dfu

View File

@ -36,17 +36,21 @@ Enter the `stm32l4xx` target directory.
cd targets/stm32l432
```
Now build Solo.
Now build the Solo application.
```
make build-hacker
make firmware
```
The `build-hacker` recipe does a few things. First it builds the bootloader, with
The `firmware` recipe builds the solo application, and outputs `solo.hex`. You can use this
to reprogram any unlocked/hacker Solo model. Note that it does not include the Solo bootloader,
so it is not a full reprogram.
<!-- First it builds the bootloader, with
signature checking disabled. Then it builds the Solo application with "hacker" features
enabled, like being able to jump to the bootloader on command. It then merges bootloader
and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex`
into `all.hex`.
into `all.hex`. -->
If you're just planning to do development, **please don't try to reprogram the bootloader**,
as this can be risky if done often. Just use `solo.hex`.
@ -57,13 +61,13 @@ If you're developing, you probably want to see debug messages! Solo has a USB
Serial port that it will send debug messages through (from `printf`). You can read them using
a normal serial terminal like `picocom` or `putty`.
Just add `DEBUG=1` or `DEBUG=2` to your build recipe, like this.
Just add `-debug-1` or `-debug-2` to your build recipe, like this.
```
make build-hacker DEBUG=1
make firmware-debug-1
```
If you use `DEBUG=2`, that means Solo will not boot until something starts reading
If you use `debug-2`, that means Solo will not boot until something starts reading
its debug messages. So it basically waits to tether to a serial terminal so that you don't
miss any debug messages.
@ -78,27 +82,45 @@ solo monitor <serial-port>
[See issue 62](https://github.com/solokeys/solo/issues/62).
### Building a Solo release
### Building a complete Solo build (application + bootloader + certificate)
To build Solo
To make a complete Solo build, you need to build the bootloader. We provide
two easy recipes:
If you want to build a release of Solo, we recommend trying a Hacker build first
just to make sure that it's working. Otherwise it may not be as easy or possible to
fix any mistakes.
* `bootloader-nonverifying`: bootloader with no signature checking on updates. I.e. "unlocked".
* `bootloader-verifying`: bootloader with signature checking enforced on updated. I.e. "Locked".
If you're ready to program a full release, run this recipe to build.
To be safe, let's use the `-nonverifying` build.
```
make build-release-locked
make bootloader-nonverifying
```
This outputs bootloader.hex, solo.hex, and the combined all.hex.
This outputs `bootloader.hex`. We can then merge the bootloader and application.
Programming `all.hex` will cause the device to permanently lock itself. This means debuggers cannot be used and signature checking
will be enforced on all future updates.
```
solo mergehex bootloader.hex solo.hex bundle.hex
```
Note if you program a secured `solo.hex` file onto a Solo Hacker, it will lock the flash, but the bootloader
will still accept unsigned firmware updates. So you can switch it back to being a hacker, but you will
not be able to replace the unlocked bootloader anymore, since the permanently locked flash also disables the DFU.
[Read more on Solo's boot stages](/solo/bootloader-mode).
`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.
```
solo mergehex \
--attestation-key "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" \
--attestation-cert attestation.der \
--lock \
solo.hex \
bootloader.hex \
bundle.hex
```
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).

View File

@ -114,28 +114,27 @@ If the checks succeed, you are ready to program the device attestation key and c
### Programming an attestation key and certificate
Convert the DER format of the device attestation certificate to "C" bytes using our utility script. You may first need to
first install prerequisite python modules (`pip install -r tools/requirements.txt`).
First, [Build your solo application and bootloader](/solo/building).
```
python tools/gencert/cbytes.py device_cert.der
```
Copy the byte string portion into the [`attestation.c` source file of Solo](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/attestation.c). Overwrite the development or "default" certificate that is already there.
Now [build the Solo firmware](/solo/building), either a secure or hacker build. You will need to produce a `bootloader.hex` file and a `solo.hex` file.
Print your attestation key in a hex string format.
Print your attestation key in a hex string format. Using our utility script:
```
python tools/print_x_y.py device_key.pem
```
Merge the `bootloader.hex`, `solo.hex`, and attestion key into one firmware file.
Merge the `bootloader.hex`, `solo.hex`, attestion key, and certificate into one firmware file.
```
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex
solo mergehex \
--attestation-key "(The 32-byte hex string extracted from device_key.pem)" \
--attestation-cert device_cert.der \
--lock \
solo.hex \
bootloader.hex \
bundle.hex
```
Now you have a newly create `all.hex` file with a custom attestation key. You can [program this `all.hex` file
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).
Are you interested in customizing in bulk? Contact hello@solokeys.com and we can help.

View File

@ -22,12 +22,11 @@ solo key update <--secure | --hacker>
You can manually install the [latest release](https://github.com/solokeys/solo/releases), or use a build that you made.
```bash
# If it's a hacker, it will automatically boot into bootloader mode.
solo program bootloader <firmware.hex | firmware.json>
```
Note you won't be able to use `all.hex` or the `bundle-*.hex` builds, as these include the solo bootloader. You shouldn't
risk changing the Solo bootloader unless you want to make it a secure device, or [make other customizations]().
risk changing the Solo bootloader unless you want to make it a secure device, or [make other customizations](/solo/customization/).
## Updating a Hacker to a Secure Solo
@ -38,14 +37,14 @@ You can use a firmware build from the [latest release](https://github.com/soloke
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 `all.hex` from your build. If you overwrite the Solo flash with a missing 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.
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`
is a secured build that will lock your device and it will behave just like a Secure Solo. The main difference is that
it uses a "default" attestation key in the device, rather than the SoloKeys attestation key. There is no security
concern with using our default attestation key, aside from a privacy implication that services can distinguish it from Solo Secure.
concern with using our default attestation key, aside from a small privacy implication that services can distinguish it from Solo Secure.
### Procedure
@ -61,7 +60,7 @@ concern with using our default attestation key, aside from a privacy implication
2. Program the device
solo program dfu <bundle-secure-non-solokeys.hex | all.hex>
solo program dfu <bundle-secure-non-solokeys.hex | bundle.hex>
Double check you programmed it with bootloader + application (or just bootloader).
If you messed it up, simply don't do the next step and repeat this step correctly.

View File

@ -710,6 +710,7 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
printf1(TAG_HID,"CTAPHID_BOOT\n");
u2f_set_writeback_buffer(ctap_resp);
is_busy = bootloader_bridge(len, ctap_buffer);
wb->bcnt = 1 + ctap_resp->length;
ctaphid_write(wb, &is_busy, 1);
ctaphid_write(wb, ctap_resp->data, ctap_resp->length);

View File

@ -4,6 +4,7 @@ version=$1
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
cd /solo/targets/stm32l432
ls
make cbor
@ -11,9 +12,8 @@ out_dir="/builds"
function build() {
part=${1}
variant=${2}
output=${3:-${part}}
what="${part}-${variant}"
output=${2}
what="${part}"
make full-clean
@ -27,22 +27,27 @@ function build() {
cp ${out_hex} ${out_sha2} ${out_dir}
}
build bootloader nonverifying
build bootloader verifying
build firmware hacker solo
build firmware hacker-debug-1 solo
build firmware hacker-debug-2 solo
build firmware secure solo
build firmware secure-non-solokeys solo
build bootloader-nonverifying bootloader
build bootloader-verifying bootloader
build firmware solo
build firmware-debug-1 solo
build firmware-debug-2 solo
build firmware solo
cd ${out_dir}
bundle="bundle-hacker-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-${version}.hex ${bundle}.hex
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-hacker-debug-1-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-1-${version}.hex ${bundle}.hex
bundle="bundle-hacker-debug-2-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-2-${version}.hex ${bundle}.hex
bundle="bundle-secure-non-solokeys-${version}"
/opt/conda/bin/solo mergehex bootloader-verifying-${version}.hex firmware-secure-non-solokeys-${version}.hex ${bundle}.hex
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-1-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-hacker-debug-2-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-2-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-secure-non-solokeys-${version}"
/opt/conda/bin/solo mergehex --lock bootloader-verifying-${version}.hex firmware-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2

View File

@ -13,20 +13,14 @@ merge_hex=solo mergehex
# The following are the main targets for reproducible builds.
# TODO: better explanation
firmware-hacker:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0
firmware-hacker-debug-1:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware-debug-1:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1
firmware-hacker-debug-2:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
firmware-secure-non-solokeys:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DFLASH_ROP=2'
firmware-secure:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2'
firmware-debug-2:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2
bootloader-nonverifying:
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0

View File

@ -9,7 +9,6 @@
#define _APP_H_
#include <stdint.h>
#include "version.h"
#define DEBUG_UART USART1
#ifndef DEBUG_LEVEL
@ -21,6 +20,7 @@
#define BOOT_TO_DFU 0
#define SOLO 1
#define IS_BOOTLOADER 1
#define ENABLE_U2F_EXTENSIONS

View File

@ -195,7 +195,8 @@ void device_init_button(void)
int solo_is_locked(){
uint64_t device_settings = ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->device_settings;
return (device_settings & SOLO_FLAG_LOCKED) != 0;
uint32_t tag = (uint32_t)(device_settings >> 32ull);
return tag == ATTESTATION_CONFIGURED_TAG && (device_settings & SOLO_FLAG_LOCKED) != 0;
}
/** device_migrate

View File

@ -32,14 +32,17 @@ static void flash_unlock(void)
void flash_option_bytes_init(int boot_from_dfu)
{
uint32_t val = 0xfffff8aa;
if (solo_is_locked()){
val = 0xfffff8cc;
}
if (boot_from_dfu)
{
if (boot_from_dfu){
val &= ~(1<<27); // nBOOT0 = 0 (boot from system rom)
}
else {
if (solo_is_locked())
{
val = 0xfffff8cc;
}
}
val &= ~(1<<26); // nSWBOOT0 = 0 (boot from nBoot0)
val &= ~(1<<25); // SRAM2_RST = 1 (erase sram on reset)
val &= ~(1<<24); // SRAM2_PE = 1 (parity check en)