Merge branch 'master' of github.com:solokeyssec/solo

This commit is contained in:
Conor Patrick
2019-01-07 18:09:03 -05:00
17 changed files with 36 additions and 35 deletions

185
docs/solo/building.md Normal file
View File

@@ -0,0 +1,185 @@
To build, develop and debug the firmware for the STM32L432. This will work
for Solo Hacker, the Nucleo development board, or you own homemade Solo.
There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; The board does contain a debugger, so all you need is a USB cable (and some [udev](/udev) [rules](https://rust-embedded.github.io/book/intro/install/linux.html#udev-rules)).
# Prerequisites
Install the [latest ARM compiler toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) for your system. We recommend getting the latest compilers from ARM.
You can also install the ARM toolchain using a package manage like `apt-get` or `pacman`,
but be warned they might be out of date. Typically it will be called `gcc-arm-none-eabi binutils-arm-none-eabi`.
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)
# Compilation
Enter the `stm32l4xx` target directory.
```
cd targets/stm32l432
```
Build the cbor library.
```bash
make cbor
```
Now build Solo.
```
make build-hacker
```
The `build-hacker` recipe does a few things. 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`.
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
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.
```
make build-hacker DEBUG=1
```
If you use `DEBUG=2`, that means Solo will not boot until something starts reading
it's debug messages. So it basically it waits to tether to a serial terminal so that you don't
miss any debug messages.
We recommend using our `solotool.py` as a serial emulator since it will automatically
reconnect each time you program Solo.
```
python tools/solotool.py monitor <serial-port>
```
#### Linux Users:
[See issue 62](https://github.com/solokeys/solo/issues/62).
### Building a Solo release
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.
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
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 `solotool.py` 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.
```
python tools/solotool.py program 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.
```
python tools/solotool.py program all.hex --use-dfu --detach
```
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.
```
python tools/solotool.py program /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.
```
python tools/solotool.py 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.
python tools/programmer.py --disable
```

View File

@@ -0,0 +1,40 @@
# Overview of firmware
This is a high level overview of the code. We aim to make the code self documenting
and easy to understand, especially when paired with a high level overview.
## FIDO2 codebase
* main.c - calls high level functions and implements event loop.
* ctaphid.c - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO.
* u2f.c - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html).
* ctap.c - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html).
* ctap_parse.c - implements parsing for CTAP protocol.
* this could use some work minimizing.
* log.c - embedded friendly debug logging.
* crypto.c - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in crypto.h should be the same.
* device.h - definitions of functions that are platform specific and should be implemented separately. See device.c in any of the implementations to see examples.
## Data flow
The main loop will poll the USB peripheral to see if any messages arrived,
and then pass each one to the USBHID layer.
Once a USBHID message is fully buffered, it will be acted on, unless there was a previous error.
This will get passed up to U2F or CTAP2 layer. The response is buffered and then written out to USB.
Depending on platform, there should be a minimum number of interrupts configured. USB will need interrupts,
and possibly timer interrupts for keeping track of time. ST implementation users a 16-bit timer to track time,
and interrupts to count overflows.
If the application is waiting on user input in CTAP2, then USBHID messages need to be continued to be polled,
to catch any [cancel command](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-hid-cancel).
Also, every 100ms or so, an update needs to be sent via USBHID if the CTAP2 application is still processing a getAssertion request,
a makeCredential request, or is waiting on user input. ST leverages same 16-bit timer interrupt for this.

15
docs/solo/contributing.md Normal file
View File

@@ -0,0 +1,15 @@
We are very open to contributions!
[Currently](https://github.com/solokeys/solo/issues), most work will go towards
* implementing STM32L432
* implementing NFC
* adding documentation and improving accessability of the code
In the future, we would love to see creative plugins/extensions, putting the TRNG and other features of the STM32L432 to good use!
Feel free to send a [pull request](https://github.com/solokeys/solo/pulls) at any time, we don't currently have a formal contribution process.
If you want to discuss your plans in quasi-realtime beforehand, you can also join our [solokeys.public](https://keybase.io/team/solokeys.public) Keybase team.
But first: [join our mailing list!](https://solokeys.us19.list-manage.com/subscribe/post?u=cc0c298fb99cd136bdec8294b&id=b9cb3de62d)

11
docs/solo/documenting.md Normal file
View File

@@ -0,0 +1,11 @@
Documentation of the `master` branch is deployed to Netlify automatically.
To host or develop locally:
```
pip install mkdocs mkdocs-material
```
`mkdocs serve` and visit [localhost:8000](http://localhost:8000).
The file `runtime.txt` is necessary to tell Netlify to use Python3.

82
docs/solo/fido2-impl.md Normal file
View File

@@ -0,0 +1,82 @@
This page aims to document the security related aspects of the FIDO2
implementation on Solo. This is to make it easier for public review and
comments.
# Key generation
Solo aims to achieve 256 bit (32 byte) security with its FIDO2 implementation,
even in light of physical side channels.
When Solo is first programmed, it will be "uninitialized," meaning it won't
have any secret material, until the first time it boots, then it will leverage
the TRNG to generate all necessary material. This only happens once.
A master secret, `M`, is generated at initialization. This is only used for
all key generation and derivation in FIDO2. Solo uses a key wrapping method
for FIDO2 operation.
## Key wrapping
When you register a service with a FIDO2 or U2F authenticator, the
authenticator must generate a new keypair unique to that service. This keypair
could be stored on the authenticator to be used in subsequent authentications,
but now a certain amount of memory needs to be allocated for this. On embedded
devices, there isn't much memory to spare and users will allows frustratingly
hit the limit of this memory.
The answer to this problem is to do key wrapping. The authenticator just
stores `M` and uses `M` and the TRNG to generate new keys and derive previous
keys on the fly. A random number, `R`, is generated, and is placed in the
FIDO2/U2F `KEYID` parameter. The service stores `KEYID` after registering a
key and will issue it back to the authenticator for subsequent authentications.
In essence, the following happens at registration.
1. Generate `R`, calculate private key, `K`, using `HMAC(M,R)`
2. Derive public key, `P`, from `K`
3. Return `P` and `R` to service. (`R` is in `KEYID` parameter)
4. Service stores `P` and `R`.
Now on authenication.
1. Service issues authentication request with `R` in `KEYID` parameter.
2. \* Authenticator generates `K` by calculating `HMAC(M,R)`.
3. Proceed normally as if `K` was loaded from storage memory.
<!-- As part of FIDO2/U2F, there is a `KEYID` parameter that is bascially a
binary blob that the authenticator returns to the service after registering,
and the service must store it and provide it to the authenticator on subsquent
authentications.
64 bytes of secrets will be generated to make master secret parts `M1` and
`M2`, 32 bytes each. The master secrets are only used for generating signing
keys which are then used for FIDO2/U2F. -->
## Key derivation
Master secret `M` consists of 64 bytes, split into equal parts `M1` and `M2`.
In theory, we should only need 32 bytes to achieve 256 security, but we also
plan to have side channel security hence the added bytes.
Our HMAC currently is a two step process. First, just generate a normal
`SHA256-HMAC`.
1. `tmp = SHA256_HMAC(M1, R)`
We could proceed using `tmp` as our secret key, `K`. But our `SHA256-HMAC`
implementation isn't side channel resistant and we won't bother trying to add
side channel resistance. So we add an additional stage that is side channel
resistant.
2. `K = aes256_masked(M2, tmp)`
We add a masked AES encryption to provide side channel resistance. Masked AES
is well studied and relatively easy to implement. An adversary may be able to
recover `M1` via SCA but not `M2`.
<sup>* There are other details I leave out. There's also an authentication tag
in the `KEYID` parameter to ensure this is a key generated by the Solo
key.</sup>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

14
docs/solo/images/logo.svg Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 300 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<g transform="matrix(1,0,0,1,-20.3892,11.4354)">
<path d="M53.089,63.558C64.091,63.558 72.618,58.03 72.618,48.032C72.618,37.829 64.624,35.095 55.758,33.028C48.62,31.427 44.952,30.627 44.952,27.293C44.952,24.626 47.687,22.825 51.822,22.825C56.224,22.825 59.026,24.892 59.493,28.56L71.019,28.56C70.553,18.562 62.559,13.9 52.222,13.9C41.554,13.9 33.293,18.363 33.293,28.56C33.293,38.563 42.02,41.097 50.288,43.03C56.825,44.631 60.693,45.431 60.693,49.232C60.693,52.833 56.891,54.233 53.023,54.233C47.353,54.233 44.219,52.233 43.686,47.432L31.827,47.432C32.093,57.963 40.422,63.558 53.089,63.558Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<path d="M93.756,55.767C89.02,55.767 86.552,51.632 86.552,45.429C86.552,39.227 89.02,35.025 93.756,35.025C98.492,35.025 101.027,39.227 101.027,45.429C101.027,51.632 98.492,55.767 93.756,55.767ZM93.823,63.492C104.824,63.492 112.018,55.7 112.018,45.429C112.018,35.159 104.824,27.367 93.823,27.367C82.888,27.367 75.56,35.159 75.56,45.429C75.56,55.7 82.888,63.492 93.823,63.492Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<rect x="115.76" y="14.767" width="10.992" height="47.658" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<path d="M148.689,55.767C143.953,55.767 141.485,51.632 141.485,45.429C141.485,39.227 143.953,35.025 148.689,35.025C153.425,35.025 155.96,39.227 155.96,45.429C155.96,51.632 153.425,55.767 148.689,55.767ZM148.756,63.492C159.757,63.492 166.952,55.7 166.952,45.429C166.952,35.159 159.757,27.367 148.756,27.367C137.821,27.367 130.493,35.159 130.493,45.429C130.493,55.7 137.821,63.492 148.756,63.492Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<path d="M174.493,62.425L180.485,62.425L180.485,45.538L188.152,37.862L206.085,62.425L213.085,62.425L192.218,33.79L211.485,14.7L203.952,14.7L180.485,38.396L180.485,14.7L174.493,14.7L174.493,62.425Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<path d="M228.689,63.358C236.493,63.358 241.888,59.166 243.486,51.762L238.227,51.762C237.026,56.432 233.691,58.833 228.689,58.833C221.753,58.833 217.952,53.496 217.552,46.492L244.218,46.492C244.218,35.095 238.693,27.1 228.356,27.1C218.552,27.1 212.027,35.228 212.027,45.228C212.027,55.231 218.152,63.358 228.689,63.358ZM228.356,31.358C234.558,31.358 238.093,35.562 238.427,42.433L217.685,42.433C218.485,36.162 221.953,31.358 228.356,31.358Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<path d="M253.891,73.825C258.09,73.825 260.756,72.361 263.556,65.233L278.285,27.967L272.553,27.967L264.689,49.433C263.622,52.3 262.422,56.167 262.422,56.167L262.289,56.167C262.289,56.167 261.023,52.3 259.956,49.433L251.825,27.967L245.96,27.967L259.423,61.433L258.09,64.833C256.757,68.167 255.224,69.033 252.958,69.033C251.159,69.033 250.026,68.7 249.293,68.3L249.026,68.3L249.026,73.093C250.492,73.692 251.825,73.825 253.891,73.825Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
<path d="M294.823,63.425C302.76,63.425 308.418,59.898 308.418,52.965C308.418,45.029 302.627,43.495 295.69,42.095C289.753,40.895 286.418,40.161 286.418,36.426C286.418,33.692 288.419,31.492 293.355,31.492C298.491,31.492 300.959,33.492 301.493,38.027L307.021,38.027C306.222,31.292 302.026,27.233 293.489,27.233C285.487,27.233 281.093,30.959 281.093,36.693C281.093,44.229 287.152,45.629 293.956,47.03C300.292,48.363 302.96,49.364 302.96,53.232C302.96,56.433 300.626,58.9 294.956,58.9C289.82,58.9 285.819,57.233 285.087,51.231L279.56,51.231C280.093,58.967 285.353,63.425 294.823,63.425Z" style="fill:rgb(35,31,32);fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

4
docs/solo/index.md Normal file
View File

@@ -0,0 +1,4 @@
Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo).
For now, you can read the repository `README.md`, more documentation to come!

1
docs/solo/repo-readme.md Symbolic link
View File

@@ -0,0 +1 @@
../../README.md

View File

@@ -0,0 +1,26 @@
Solo has a bootloader that's fixed in memory to allow for signed firmware updates. It is not a built-in bootloader provided by the chip
manufacturer, it is our own. We plan to use Ed25519 signatures, which have [efficient constant-time implementations on Cortex-M4 chips](http://www.cs.haifa.ac.il/~orrd/LC17/paper39.pdf).
On the STM32L432, there is 256 KB of memory. The first 14 KB of memory is reserved for the bootloader.
The bootloader is the first thing that boots, and if the button of the device is not held for 2 seconds, the
application is immediately booted.
Consider the following memory layout of the device.
| 14 KB | 226 KB | 16KB |
|---|---|---|
| --boot-- | -------application------- | --data-- |
Our bootloader resides at address 0, followed by the application, and then the final 16 KB allocated for secret data.
The bootloader is allowed to replace any data in the application segment. When the application is first written to,
a mass erase of the application segment is triggered and a flag in the data segment is set indicating the application
is not safe to boot.
In order to boot the application, a valid signature must be provided to the bootloader. The bootloader will verify the
signature using a public key stored in the bootloader section, and the data in the application section. If the signature
is valid, the boot flag in the data section will be changed to allow boot.
Signature checks and checks to the data section boot flag are made redundantly to make glitching attacks more difficult. Random delays
between redundant checks are also made.

72
docs/solo/udev.md Normal file
View File

@@ -0,0 +1,72 @@
# tl;dr
Create [`/etc/udev/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules) and add the following (which assumes your user is in group `plugdev`):
```
# Solo
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="solokey"
# U2F Zero
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"
```
Then run
```
udevadm trigger
```
# How do udev rules work and why are they needed
In Linux, `udev` (part of `systemd`, read `man 7 udev`) handles "hot-pluggable" devices, of which Solo and U2F Zero are examples. In particular, it creates nodes in the `/dev` filesystem (in Linux, everything is a file), which allow accessing the device.
By default, for security reasons often only the `root` user can access these nodes, unless they are whitelisted using a so-called "udev rule". So depending on your system setup, such a udev rule may be necessary to allow non-root users access to the device, for instance yourself when using a browser to perform two-factor authentication.
## What does a udev rule do?
It matches events it receives (typically, comparing with the `==` operator), and performs actions (typically, setting attributes of the node with the `=` or `+=` operators).
## What is `hidraw`?
HID are human-interface devices (keyboards, mice, Solo keys), attached via USB. The `hidraw` system gives software direct ("raw") access to the device.
## Which node is my Solo or U2F Zero security key?
You can either compare `ls /dev` before and after inserting, or use the `udevadm` tool, e.g., by running
```
udevadm monitor --environment --udev | grep DEVNAME
```
Typically, you will detect `/dev/hidraw0`. Using the symlinks above, you can follow symlinks from `/dev/solokey` and `/dev/u2fzero`.
## How do you know if your system is configured correctly?
Try reading and writing to the device node you identified in the previous step. Assuming the node is called `/dev/hidraw0`:
* read: try `cat /dev/solokey`, if you don't get "permission denied", you can access.
* write: try `echo "hello, Solo" > /dev/solokey`. Again, if you don't get denied permission, you're OK.
## Which rule should I use, and how do I do it?
Simplest is probably to copy [Yubico's rule file](https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules) to `/etc/udev/rules.d/fido.rules` on your system, for instance:
```
$ (cd /etc/udev/rules.d/ && sudo curl https://raw.githubusercontent.com/Yubico/libu2f-host/master/70-u2f.rules -O)
```
This contains rules for Yubico's keys, the U2F Zero, and many others. The relevant line for U2F Zero is:
```
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
```
It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as
```
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", MODE="0644", GROUP="plugdev"
```
which sets MODE of the device node to readable by anyone.
Now reload the device events.
```
udevadm trigger
```
## What about vendor and product ID for Solo?
| Key | Vendor ID | Product ID |
| --- | --- | --- |
| Solo | 10c4 | 8acf |
| U2F Zero | 0483 | a2ca |
## You got this all wrong, I can't believe it!
Are you suffering from [us being wrong](https://xkcd.com/386/)? Please, send us a [pull request](https://github.com/solokeys/solo/pulls) and prove us wrong :D