From f09900a39106dbe7c4bb26b8f685133fd4c55f15 Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Fri, 16 Aug 2019 11:59:54 +0800 Subject: [PATCH] initial draft --- docs/solo/bootloader-mode.md | 51 +++++++++++++ docs/solo/building.md | 113 ++-------------------------- docs/solo/customization.md | 140 +++++++++++++++++++++++++++++++++++ docs/solo/programming.md | 113 ++++++++++++++++++++++++++++ in-docker-build.sh | 4 + mkdocs.yml | 3 + 6 files changed, 316 insertions(+), 108 deletions(-) create mode 100644 docs/solo/bootloader-mode.md create mode 100644 docs/solo/customization.md create mode 100644 docs/solo/programming.md diff --git a/docs/solo/bootloader-mode.md b/docs/solo/bootloader-mode.md new file mode 100644 index 0000000..5979c1b --- /dev/null +++ b/docs/solo/bootloader-mode.md @@ -0,0 +1,51 @@ +# 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. 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. + +```bash +solo program aux enter-bootloader +``` + +# The boot stages of Solo + +Solo has 3 boot stages. + +## DFU + +The first stage is the DFU (Device Firmware Update) which is in a ROM on Solo. It is baked into the chip and is not implemented by us. +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. + +You can also run this command when Solo is in bootloader mode to put it in DFU mode. + +```bash +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. + +```bash +solo program aux leave-dfu +``` + +*Warning*: If you change the firmware to something broken, and you tell the DFU to boot it, you could brick your device. + +## Solo Bootloader + +The next boot stage is the "Solo bootloader". So when we say to put your Solo into bootloader mode, it is this stage. +This bootloader is written by us and allows signed firmware updates to be written. On Solo Hackers, there is no signature checking +and will allow any firmware updates. + +It is safe to develop for Solo using our Solo bootloader. If broken firmware is uploaded to the device, then the Solo +bootloader can always be booted again by holding down the button when plugging in. + +## Solo application + +This is what contains all the important functionality of Solo. FIDO2, U2F, etc. This is what Solo will boot to by default. diff --git a/docs/solo/building.md b/docs/solo/building.md index 084e2c4..0cc4817 100644 --- a/docs/solo/building.md +++ b/docs/solo/building.md @@ -14,12 +14,6 @@ but be warned they might be out of date. Typically it will be called `gcc-arm-n Install `solo-python` usually with `pip3 install solo-python`. The `solo` python application may also be used for [programming](#programming). -To program your build, you'll need one of the following programs. - -- [openocd](http://openocd.org) -- [stlink](https://github.com/texane/stlink) -- [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html) - ## Obtain source code and solo tool Source code can be downloaded from: @@ -54,7 +48,7 @@ enabled, like being able to jump to the bootloader on command. It then merges b and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex` into `all.hex`. -If you're just planning to do development, please don't try to reprogram the bootloader, +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`. ### Building with debug messages @@ -86,6 +80,8 @@ solo monitor ### Building a Solo release +To build Solo + 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. @@ -96,105 +92,6 @@ If you're ready to program a full release, run this recipe to build. make build-release-locked ``` -Programming `all.hex` will cause the device to permanently lock itself. +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. -## Programming - -It's recommended to test a debug/hacker build first to make sure Solo is working as expected. -Then you can switch to a locked down build, which cannot be reprogrammed as easily (or not at all!). - -We recommend using our `solo` tool to manage programming. It is cross platform. First you must -install the prerequisites: - -``` -pip3 install -r tools/requirements.txt -``` - -If you're on Windows, you must also install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/). - -### Pre-programmed Solo Hacker - -If your Solo device is already programmed (it flashes green when powered), we recommend -programming it using the Solo bootloader. - -``` -solo program aux enter-bootloader -solo program bootloader solo.hex -``` - -Make sure to program `solo.hex` and not `all.hex`. Nothing bad would happen, but you'd -see errors. - -If something bad happens, you can always boot the Solo bootloader by doing the following. - -1. Unplug device. -2. Hold down button. -3. Plug in device while holding down button. -4. Wait about 2 seconds for flashing yellow light. Release button. - -If you hold the button for an additional 5 seconds, it will boot to the ST DFU (device firmware update). -Don't use the ST DFU unless you know what you're doing. - -### ST USB DFU - -If your Solo has never been programmed, it will boot the ST USB DFU. The LED is turned -off and it enumerates as "STM BOOTLOADER". - -You can program it by running the following. - -``` -solo program aux enter-bootloader -solo program aux enter-dfu -# powercycle key -solo program dfu all.hex -``` - -Make sure to program `all.hex`, as this contains both the bootloader and the Solo application. - -If all goes well, you should see a slow-flashing green light. - -### Solo Hacker vs Solo - -A Solo hacker device doesn't need to be in bootloader mode to be programmed, it will automatically switch. - -Solo (locked) needs the button to be held down when plugged in to boot to the bootloader. - -A locked Solo will only accept signed updates. - -### Signed updates - -If this is not a device with a hacker build, you can only program signed updates. - -``` -solo program bootloader /path/to/firmware.json -``` - -If you've provisioned the Solo bootloader with your own secp256r1 public key, you can sign your -firmware by running the following command. - -``` -solo sign /path/to/signing-key.pem /path/to/solo.hex /output-path/to/firmware.json -``` - -If your Solo isn't locked, you can always reprogram it using a debugger connected directly -to the token. - -## Permanently locking the device - -If you plan to be using your Solo for real, you should lock it permanently. This prevents -someone from connecting a debugger to your token and stealing credentials. - -To do this, build the locked release firmware. -``` -make build-release-locked -``` - -Now when you program `all.hex`, the device will lock itself when it first boots. You can only update it -with signed updates. - -If you'd like to also permanently disable signed updates, plug in your programmed Solo and run the following: - -``` -# WARNING: No more signed updates. -solo program disable-bootloader -``` diff --git a/docs/solo/customization.md b/docs/solo/customization.md new file mode 100644 index 0000000..08b74da --- /dev/null +++ b/docs/solo/customization.md @@ -0,0 +1,140 @@ +# Customization + +If you are interested in customizing parts of your Solo, and you have a Solo Hacker, this page is for you. + +## Custom Attestation key + +The attestation key is used in the FIDO2 *makeCredential* or U2F *register* requests. It signs +newly generated credentials. The certification associated with the attestation key is output as well. +Platforms or services can use the attestation feature to enforce specific authenticators to be used. +This is typically a use case for organizations and isn't seen in the wild for consumer use cases. + +Attestation keys are typically the same for at least 100K units of a particular authenticator model. +This is so they don't contribute a significant fingerprint that platforms could use to identify the user. + +If you don't want to use the default attestation key that Solo builds with, you can create your own +and program it. + +### Creating your attestation key pair + +Since we are generating keys, it's important to use a good entropy source. +You can use your Solo device to generate some good random numbers. + +``` +# Run for 1 second, then hit control-c +solo key rng > seed.bin +``` + +First we will create a self signed key pair that acts as the root of trust. This +won't go on the authenticator, but will sign the keypair that does. + +Please change the root certification information as needed. You may change the ECC curve. + +``` +curve=prime256v1 + +country=US +state=Maine +organization=OpenSourceSecurity +unit=Root CA +CN=example.com +email=example@example.com + +# generate EC private key +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" + +# self sign the request +openssl x509 -trustout -req -days 18250 -in root_key.pem.csr -signkey root_key.pem -out root_cert.pem -sha256 + +# convert to smaller size format DER +openssl x509 -in root_cert.pem -outform der -out root_cert.der + +# print out information and verify +openssl x509 -in root_cert.pem -text -noout +``` + +You need to create a extended certificate for the device certificate to work with FIDO2. You need to create this +file, `v3.ext`, and add these options to it. + +``` +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +``` + +Now to generate & sign the attestation key pair that will go on your device, or maybe 100,000 devices :). +Note you must use a prime256v1 curve for this step, and you must leave the unit/OU as "Authenticator Attestation". + +``` +country=US +state=Maine +organization=OpenSourceSecurity +unit=Authenticator Attestation +CN=example.com +email=example@example.com + +# generate EC private key +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 + +# 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 + +# convert to smaller size format DER +openssl x509 -in device_cert.pem -outform der -out device_cert.der + +# Verify the device certificate details +openssl x509 -in device_cert.pem -text -noout +``` + +Let's verify that the attestation key and certificate are valid, and that they can be verified with the root key pair. + +``` +echo 'challenge $RANDOM' > chal.txt + +# check that they are valid key pairs +openssl dgst -sha256 -sign device_key.pem -out sig.txt chal.txt +openssl dgst -sha256 -verify <(openssl x509 -in device_cert.der -pubkey -noout) -signature sig.txt chal.txt + +openssl dgst -sha256 -sign "root_key.pem" -out sig.txt chal.txt +openssl dgst -sha256 -verify <(openssl x509 -in root_cert.der -pubkey -noout) -signature sig.txt chal.txt + +# Check they are a chain +openssl verify -verbose -CAfile "$rcert" "$icert" +``` + +If the checks succeed, you are ready to program the device attestation key and certificate. + +### 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). + +``` +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. + +``` +python tools/print_x_y.py +``` + +Merge the bootloader.hex, solo.hex, and attestion key into one firmware file. + +``` +solo merge --attestation-key bootloader.hex solo.hex all.hex +``` + +Now you have a newly create `all.hex` file with a custom attestation key. You can [program this all.hex file +with Solo in DFU mode](/solo/programming#procedure). \ No newline at end of file diff --git a/docs/solo/programming.md b/docs/solo/programming.md new file mode 100644 index 0000000..a63d39e --- /dev/null +++ b/docs/solo/programming.md @@ -0,0 +1,113 @@ +# Programming + +This page documents how to update or program your Solo. + +## Prerequisites + +To program Solo, you'll likely only need to use our Solo tool. + +```python +pip3 install solo-python +``` + +## Updating the firmware + +If you just want to update the firmware, you can run one of the following commands. +Make sure your key [is in bootloader mode](/solo/bootloader-mode#solo-bootloader) first. + +```bash +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 +``` + +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](). + +## Updating a Hacker to a Secure Solo + +Updating a hacker to be a secure build overwrites the [Solo bootloader](/solo/bootloader-mode#solo-bootloader). +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 `all.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. + +### Procedure + +1. Boot into DFU mode. + + # Enter Solo bootloader + solo program aux enter-bootloader + + # Enter DFU + solo program aux enter-dfu + + The device should be turned off. + +2. Program the device + + solo program dfu + + 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. + +3. Boot the device + + Once Solo boots a secure build, it will lock the flash permantly from debugger access. Also the bootloader + will only accept signed firmware updates. + + solo program aux leave-dfu + +If you are having problems with solo tool and DFU mode, you could alternatively try booting into DFU +by holding down the button while Solo is in bootloader mode. Then try another programming tool that works +with ST DFU: + +* STM32CubeProg +* openocd +* stlink + +Windows users need to install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/) +for solo-python to work with Solo's DFU. + + +## Programming a Solo that hasn't been programmed + +A Solo that hasn't been programmed will boot into DFU mode. You can program +it by following a bootloader, or combined bootloader + application. + +``` +solo program dfu +``` + +Then boot the device. Make sure it has a bootloader to boot to. + +``` +solo program aux leave-dfu +``` + +## Disable signed firmware updates + +If you'd like to also permanently disable signed updates, plug in your programmed Solo and run the following: + +```bash +# WARNING: No more signed updates. +solo program disable-bootloader +``` + +You won't be able to update to any new releases. + diff --git a/in-docker-build.sh b/in-docker-build.sh index 631d359..ece565c 100755 --- a/in-docker-build.sh +++ b/in-docker-build.sh @@ -38,6 +38,7 @@ 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 pip install -U pip pip install -U solo-python @@ -49,3 +50,6 @@ 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 +sha256sum ${bundle}.hex > ${bundle}.sha2 diff --git a/mkdocs.yml b/mkdocs.yml index 2cfc0c9..642adab 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -11,6 +11,9 @@ nav: - FIDO2 Implementation: solo/fido2-impl.md - Metadata Statements: solo/metadata-statements.md - Build instructions: solo/building.md + - Programming instructions: solo/programming.md + - Bootloader mode: solo/bootloader-mode.md + - Customization: solo/customization.md - Running on Nucleo32 board: solo/nucleo32-board.md - Signed update process: solo/signed-updates.md - Code documentation: solo/code-overview.md