From 64c3ea5271ef3b6e8881b5c483f68fe6211bf820 Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Sun, 14 Oct 2018 22:49:48 -0400 Subject: [PATCH] add some security relevant documentation --- .gitignore | 1 + docs/contributing.md | 4 +-- docs/fido2-impl.md | 82 ++++++++++++++++++++++++++++++++++++++++++ docs/signed-updates.md | 26 ++++++++++++++ docs/udev.md | 21 +++++++++++ mkdocs.yml | 2 ++ 6 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 docs/fido2-impl.md create mode 100644 docs/signed-updates.md diff --git a/.gitignore b/.gitignore index c5a0c27..e47ce92 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ tools/python-fido2/* *.bin *.key site/ +_site/ diff --git a/docs/contributing.md b/docs/contributing.md index 9155152..d171608 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -2,11 +2,11 @@ We are very open to contributions! [Currently](https://github.com/solokeyssec/solo/issues), most work will go towards -* implementing SAM L11 +* implementing STM32L442 * 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 TrustZone of the SAM L11 to good use! +In the future, we would love to see creative plugins/extensions, putting the TRNG and other features of the STM32L442 to good use! Feel free to send a [pull request](https://github.com/SoloKeysSec/solo/pulls) at any time, we don't currently have a formal contribution process. diff --git a/docs/fido2-impl.md b/docs/fido2-impl.md new file mode 100644 index 0000000..4747516 --- /dev/null +++ b/docs/fido2-impl.md @@ -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. + + + + +## 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`. + + + +* 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. diff --git a/docs/signed-updates.md b/docs/signed-updates.md new file mode 100644 index 0000000..f2a00e4 --- /dev/null +++ b/docs/signed-updates.md @@ -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. + +On the STM32L442, 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. diff --git a/docs/udev.md b/docs/udev.md index 92ee07d..e6ff08c 100644 --- a/docs/udev.md +++ b/docs/udev.md @@ -1,3 +1,18 @@ +# tl;dr + +Create `/etc/udev/fido.rules` and add the following. + +``` +# U2F Zero +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess" +``` + +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. @@ -34,6 +49,12 @@ KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", MODE="0644", GR ``` 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? Current prototypes reuse the IDs of the U2F Zero (10c4/8acf). The final Solo will probably be assigned new IDs; read about it here first :) diff --git a/mkdocs.yml b/mkdocs.yml index 2a5dccd..698b2cc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,8 @@ copyright: 'Copyright © 2018 SoloKeys' nav: - Home: index.md - README.md: repo-readme.md + - FIDO2 Implementation: fido2-impl.md + - Signed update process: signed-updates.md - Contributing Code: contributing.md - Contributing Docs: documenting.md - What the udev?!: udev.md