Compare commits

..

31 Commits

Author SHA1 Message Date
21f3a0d10f remove hacker constraint for booting into bootloader 2019-10-28 12:55:38 -04:00
b535b41d92 docs: update .all-contributorsrc 2019-10-28 11:09:54 -04:00
fd32cc0761 docs: update README.md 2019-10-28 11:09:54 -04:00
78dd2a10d3 remove binary count check 2019-10-28 10:51:35 -04:00
fa1bb0dce5 update docs 2019-10-28 10:51:35 -04:00
169dfd2f0d check attestation tag 2019-10-28 10:51:35 -04:00
dafd974d93 do not lock flash when booting to dfu 2019-10-28 10:51:35 -04:00
712fde6858 add git 2019-10-28 10:51:35 -04:00
fcc2e86a6d remove hacker/secure builds 2019-10-28 10:51:35 -04:00
8b146c4a16 fix issue with bootloader not replying data 2019-10-28 10:51:35 -04:00
a1a79b05fd fix solo locked flag for bootloader 2019-10-27 10:25:00 -04:00
c0df8b680d fix build 2019-10-27 10:25:00 -04:00
9ac2aa90c3 store all info in same page, dont use authenticator state 2019-10-27 10:25:00 -04:00
d33749fc16 add locked variable to GETVERSION hid command 2019-10-27 10:25:00 -04:00
96a2cbcb41 remove logs 2019-10-27 10:25:00 -04:00
7212982385 remove hacker macros 2019-10-27 10:25:00 -04:00
89e218e561 lock flash based on state setting 2019-10-27 10:25:00 -04:00
666cd6a0ba migrate certs 2019-10-27 10:25:00 -04:00
b4f59ec355 pull certificate from flash page 2019-10-27 10:25:00 -04:00
b7d74cc99f Add default git describe in makefile 2019-10-27 10:11:39 -04:00
375a607356 Add test for docker in travis 2019-10-27 10:11:39 -04:00
ea8409c072 Fixing Travis 2019-10-27 10:11:39 -04:00
04f06b3b0d Updating README: adding more details on how to compile the solo firmware (especially Docker) 2019-10-27 10:11:39 -04:00
a57c5170e1 Add .sha2 to .gitignore 2019-10-27 10:11:39 -04:00
aaffce4021 Make dependency on git optinal in the target/stm32l432/Makefile
"git describe" is used to get the version of the firmware from GIT tags ans it is used for build artifacts' names
We would prefer not to have this depency inside Docker
2019-10-27 10:11:39 -04:00
463a8b444d Splitting toolchain creation from firmware compilation 2019-10-27 10:11:39 -04:00
44ed3ceea5 Optimize Dockerfile 2019-10-27 10:11:39 -04:00
30f73b41e4 Move python install in the docker file 2019-10-27 10:11:39 -04:00
6f6e831fba Upgrade to the latest ARM compiler 2019-10-27 10:11:39 -04:00
9fd608d3ee Use local copy of the files 2019-10-27 10:11:39 -04:00
765dc27b15 Fix docker build 2019-10-27 10:10:27 -04:00
19 changed files with 254 additions and 166 deletions

View File

@ -197,6 +197,16 @@
"code", "code",
"doc" "doc"
] ]
},
{
"login": "ccinelli",
"name": "ccinelli",
"avatar_url": "https://avatars0.githubusercontent.com/u/38021940?v=4",
"profile": "https://github.com/ccinelli",
"contributions": [
"infra",
"test"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

3
.gitignore vendored
View File

@ -34,7 +34,8 @@
*.app *.app
*.i*86 *.i*86
*.x86_64 *.x86_64
*.hex targets/*/*.hex
targets/*/*.sha2
# Debug files # Debug files
*.dSYM/ *.dSYM/

View File

@ -6,14 +6,15 @@ addons:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
- gcc-7 - gcc-8
- cppcheck - cppcheck
services:
- docker
before_install: before_install:
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
- sudo apt-get update -q - sudo apt-get update -q
- sudo apt-get install -y gcc-arm-embedded - sudo apt-get install -y gcc-arm-embedded python3-venv
- sudo apt-get install -y python3-venv
script: script:
- export CC=gcc-7 - export CC=gcc-8
- pyenv shell 3.6.7 - pyenv shell 3.6.7
- make travis - make travis

View File

@ -1,33 +1,38 @@
FROM debian:stretch-slim FROM debian:9.11-slim
MAINTAINER SoloKeys <hello@solokeys.com> MAINTAINER SoloKeys <hello@solokeys.com>
RUN apt-get update -qq # Install necessary packages
RUN apt-get install -qq bzip2 git make wget >/dev/null RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
make \
wget \
bzip2 \
git \
&& rm -rf /var/lib/apt/lists/*
# 1. ARM GCC: for compilation # Install ARM compiler
RUN wget -q -O gcc.tar.bz2 https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2?revision=d830f9dd-cd4f-406d-8672-cca9210dd220?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2018-q4-major RUN set -eux; \
# from website url="https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2019q3/RC1.1/gcc-arm-none-eabi-8-2019-q3-update-linux.tar.bz2?revision=c34d758a-be0c-476e-a2de-af8c6e16a8a2?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2019-q3-update"; \
RUN echo "f55f90d483ddb3bcf4dae5882c2094cd gcc.tar.bz2" > gcc.md5 wget -O gcc.tar.bz2 "$url"; \
RUN md5sum -c gcc.md5 echo "6341f11972dac8de185646d0fbd73bfc gcc.tar.bz2" | md5sum -c -; \
# self-generated echo "b50b02b0a16e5aad8620e9d7c31110ef285c1dde28980b1a9448b764d77d8f92 gcc.tar.bz2" | sha256sum -c -; \
RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.tar.bz2" > gcc.sha256 tar -C /opt -xf gcc.tar.bz2; \
RUN sha256sum -c gcc.sha256 rm gcc.tar.bz2;
RUN tar -C /opt -xf gcc.tar.bz2
# 2. Python3.7: for solo-python (merging etc.) # Python3.7: for solo-python (merging etc.)
RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh RUN set -eux; \
# from website url="https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh"; \
RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5 wget -O miniconda.sh "$url"; \
RUN md5sum -c miniconda.md5 echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" | md5sum -c -; \
# self-generated echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" | sha256sum -c -; \
RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" > miniconda.sha256 bash ./miniconda.sh -b -p /opt/conda; \
RUN sha256sum -c miniconda.sha256 ln -s /opt/conda/bin/python /usr/local/bin/python3; \
ln -s /opt/conda/bin/python /usr/local/bin/python; \
ln -s /opt/conda/bin/pip /usr/local/bin/pip3; \
ln -s /opt/conda/bin/pip /usr/local/bin/pip; \
rm miniconda.sh; \
pip install -U pip
RUN bash ./miniconda.sh -b -p /opt/conda # solo-python (Python3.7 script for merging etc.)
RUN ln -s /opt/conda/bin/python /usr/local/bin/python3 RUN pip install -U solo-python
RUN ln -s /opt/conda/bin/python /usr/local/bin/python
RUN ln -s /opt/conda/bin/pip /usr/local/bin/pip3
RUN ln -s /opt/conda/bin/pip /usr/local/bin/pip
# 3. Source code
RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input

View File

@ -23,8 +23,8 @@ else
endif endif
LDFLAGS += $(LIBCBOR) LDFLAGS += $(LIBCBOR)
VERSION:=$(shell git describe --abbrev=0 )
VERSION_FULL:=$(shell git describe) VERSION_FULL:=$(shell git describe)
VERSION:=$(shell python -c 'print("$(VERSION_FULL)".split("-")[0])')
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])') VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])') VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])') VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
@ -62,7 +62,7 @@ test: venv
$(MAKE) clean $(MAKE) clean
$(MAKE) -C . main $(MAKE) -C . main
$(MAKE) clean $(MAKE) clean
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" $(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${VERSION_FULL}
$(MAKE) clean $(MAKE) clean
$(MAKE) cppcheck $(MAKE) cppcheck
@ -88,18 +88,30 @@ wink: venv
fido2-test: venv fido2-test: venv
venv/bin/python tools/ctap_test.py venv/bin/python tools/ctap_test.py
DOCKER_IMAGE := "solokeys/solo-firmware:local" update:
SOLO_VERSIONISH := "master" git fetch --tags
docker-build: git checkout master
docker build -t $(DOCKER_IMAGE) . git rebase origin/master
git submodule update --init --recursive
DOCKER_TOOLCHAIN_IMAGE := "solokeys/solo-firmware-toolchain"
docker-build-toolchain:
docker build -t $(DOCKER_TOOLCHAIN_IMAGE) .
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${VERSION}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${VERSION_MAJ}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${VERSION_MAJ}.${VERSION_MIN}
uncached-docker-build-toolchain:
docker build --no-cache -t $(DOCKER_TOOLCHAIN_IMAGE) .
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${VERSION}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${VERSION_MAJ}
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${VERSION_MAJ}.${VERSION_MIN}
docker-build-all:
docker run --rm -v "$(CURDIR)/builds:/builds" \ docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \ -v "$(CURDIR):/solo" \
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH) $(DOCKER_TOOLCHAIN_IMAGE) "solo/in-docker-build.sh" ${VERSION_FULL}
uncached-docker-build:
docker build --no-cache -t $(DOCKER_IMAGE) .
docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
CPPCHECK_FLAGS=--quiet --error-exitcode=2 CPPCHECK_FLAGS=--quiet --error-exitcode=2
@ -120,6 +132,14 @@ clean:
full-clean: clean full-clean: clean
rm -rf venv rm -rf venv
test-docker:
rm -rf builds/*
$(MAKE) uncached-docker-build-toolchain
# 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
travis: travis:
$(MAKE) test VENV=". ../../venv/bin/activate;" $(MAKE) test VENV=". ../../venv/bin/activate;"
$(MAKE) test-docker
$(MAKE) black $(MAKE) black

View File

@ -32,10 +32,58 @@ Check out [solokeys.com](https://solokeys.com), for options on where to buy Solo
If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We support Python3. If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We support Python3.
For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h#L48) and change `LED_INIT_VALUE`
to be a different hex color.
Then recompile, load your new firmware, and enjoy a different LED color Solo.
In the Hacker version, hardware is the same but the firmware is unlocked, so you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently.
Hacker Solo isn't really secure so you should only use it for development. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
## Checking out the code
```bash ```bash
git clone --recurse-submodules https://github.com/solokeys/solo git clone --recurse-submodules https://github.com/solokeys/solo
cd solo cd solo
```
If you forgot the `--recurse-submodules` while cloning, simply run `git submodule update --init --recursive`.
`make update` will also checkout the latest code on `master` and submodules.
## Checking out the code to build a specific version
You can checkout the code to build a specific version of the firmware with:
```
VERSION_TO_BUILD=2.5.3
git fetch --tags
git checkout ${VERSION_TO_BUILD}
git submodule update --init --recursive
```
## Installing the toolchain
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
## Installing the toolkit and compiling in Docker
Alternatively, you can use Docker to create a container with the toolchain.
You can run:
```bash
# Build the toolchain container
make docker-build-toolchain
# Build all versions of the firmware in the "builds" folder
make docker-build-all
```
The `builds` folder will contain all the variation on the firmware in `.hex` files.
## Build locally
If you have the toolchain installed on your machine you can build the firmware with:
```bash
cd targets/stm32l432 cd targets/stm32l432
make cbor make cbor
make build-hacker make build-hacker
@ -47,19 +95,6 @@ solo program aux enter-bootloader
solo program bootloader targets/stm32l432/solo.hex solo program bootloader targets/stm32l432/solo.hex
``` ```
Alternatively, run `make docker-build` and use the firmware generated in `/tmp`.
If you forgot the `--recurse-submodules` when cloning, simply `git submodule update --init --recursive`.
For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h#L48) and change `LED_INIT_VALUE`
to be a different hex color.
Then recompile, load your new firmware, and enjoy a different LED color Solo.
In the Hacker version, hardware is the same but the firmware is unlocked, so you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently.
Hacker Solo isn't really secure so you should only use it for development. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
# Developing Solo (No Hardware Needed) # Developing Solo (No Hardware Needed)
Clone Solo and build it Clone Solo and build it
@ -131,6 +166,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td> <td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td> <td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/jolo1581"><img src="https://avatars1.githubusercontent.com/u/53423977?v=4" width="100px;" alt="Jan A."/><br /><sub><b>Jan A.</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/jolo1581"><img src="https://avatars1.githubusercontent.com/u/53423977?v=4" width="100px;" alt="Jan A."/><br /><sub><b>Jan A.</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ccinelli"><img src="https://avatars0.githubusercontent.com/u/38021940?v=4" width="100px;" alt="ccinelli"/><br /><sub><b>ccinelli</b></sub></a><br /><a href="#infra-ccinelli" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/solokeys/solo/commits?author=ccinelli" title="Tests">⚠️</a></td>
</tr> </tr>
</table> </table>
@ -164,7 +200,7 @@ You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solok
<br/> <br/>
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE) [![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![All Contributors](https://img.shields.io/badge/all_contributors-20-orange.svg?style=flat-square)](#contributors) [![All Contributors](https://img.shields.io/badge/all_contributors-21-orange.svg?style=flat-square)](#contributors)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo) [![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com) [![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public) [![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)

View File

@ -1,16 +1,17 @@
# Booting into bootloader mode # 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. If you have a recent version of Solo, you can put it into bootloader mode by running this command.
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.
```bash ```bash
solo program aux enter-bootloader 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 # The boot stages of Solo
Solo has 3 boot stages. 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 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**. 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. 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 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 ```bash
solo program aux leave-dfu solo program aux leave-dfu

View File

@ -36,17 +36,21 @@ Enter the `stm32l4xx` target directory.
cd targets/stm32l432 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 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 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` 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**, 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`. 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 Serial port that it will send debug messages through (from `printf`). You can read them using
a normal serial terminal like `picocom` or `putty`. 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 its debug messages. So it basically waits to tether to a serial terminal so that you don't
miss any debug messages. miss any debug messages.
@ -78,27 +82,45 @@ solo monitor <serial-port>
[See issue 62](https://github.com/solokeys/solo/issues/62). [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 * `bootloader-nonverifying`: bootloader with no signature checking on updates. I.e. "unlocked".
just to make sure that it's working. Otherwise it may not be as easy or possible to * `bootloader-verifying`: bootloader with signature checking enforced on updated. I.e. "Locked".
fix any mistakes.
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 `bundle.hex` is our complete firmware build. Note it is in this step that you can
will still accept unsigned firmware updates. So you can switch it back to being a hacker, but you will include a custom attestation certificate or lock the device from debugging/DFU.
not be able to replace the unlocked bootloader anymore, since the permanently locked flash also disables the DFU. By default the "hacker" attestation certifcate and key is used.
[Read more on Solo's boot stages](/solo/bootloader-mode).
```
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 ### 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, [Build your solo application and bootloader](/solo/building).
first install prerequisite python modules (`pip install -r tools/requirements.txt`).
``` Print your attestation key in a hex string format. Using our utility script:
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 device_key.pem 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). 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. You can manually install the [latest release](https://github.com/solokeys/solo/releases), or use a build that you made.
```bash ```bash
# If it's a hacker, it will automatically boot into bootloader mode.
solo program bootloader <firmware.hex | firmware.json> 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 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 ## 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. 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). 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. 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, 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` 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 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 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 ### Procedure
@ -61,7 +60,7 @@ concern with using our default attestation key, aside from a privacy implication
2. Program the device 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). 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. 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"); printf1(TAG_HID,"CTAPHID_BOOT\n");
u2f_set_writeback_buffer(ctap_resp); u2f_set_writeback_buffer(ctap_resp);
is_busy = bootloader_bridge(len, ctap_buffer); is_busy = bootloader_bridge(len, ctap_buffer);
wb->bcnt = 1 + ctap_resp->length;
ctaphid_write(wb, &is_busy, 1); ctaphid_write(wb, &is_busy, 1);
ctaphid_write(wb, ctap_resp->data, ctap_resp->length); ctaphid_write(wb, ctap_resp->data, ctap_resp->length);

View File

@ -1,14 +1,10 @@
#!/bin/bash -xe #!/bin/bash -xe
version=$1
version=${1:-master} export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
cd /solo/targets/stm32l432 cd /solo/targets/stm32l432
git fetch --tags ls
git checkout ${version}
git submodule update --init --recursive
version=$(git describe)
make cbor make cbor
@ -16,13 +12,12 @@ out_dir="/builds"
function build() { function build() {
part=${1} part=${1}
variant=${2} output=${2}
output=${3:-${part}} what="${part}"
what="${part}-${variant}"
make full-clean make full-clean
make ${what} make ${what} VERSION_FULL=${version}
out_hex="${what}-${version}.hex" out_hex="${what}-${version}.hex"
out_sha2="${what}-${version}.sha2" out_sha2="${what}-${version}.sha2"
@ -32,24 +27,27 @@ function build() {
cp ${out_hex} ${out_sha2} ${out_dir} cp ${out_hex} ${out_sha2} ${out_dir}
} }
build bootloader nonverifying build bootloader-nonverifying bootloader
build bootloader verifying build bootloader-verifying bootloader
build firmware hacker solo build firmware solo
build firmware hacker-debug-1 solo build firmware-debug-1 solo
build firmware hacker-debug-2 solo build firmware-debug-2 solo
build firmware secure solo build firmware solo
build firmware secure-non-solokeys solo
pip install -U pip
pip install -U solo-python
cd ${out_dir} cd ${out_dir}
bundle="bundle-hacker-${version}" 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 sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-hacker-debug-1-${version}" bundle="bundle-hacker-debug-1-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-1-${version}.hex ${bundle}.hex /opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-1-${version}.hex ${bundle}.hex
bundle="bundle-hacker-debug-2-${version}" sha256sum ${bundle}.hex > ${bundle}.sha2
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-2-${version}.hex ${bundle}.hex
bundle="bundle-secure-non-solokeys-${version}" bundle="bundle-hacker-debug-2-${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-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 sha256sum ${bundle}.hex > ${bundle}.sha2

View File

@ -2,8 +2,9 @@ ifndef DEBUG
DEBUG=0 DEBUG=0
endif endif
APPMAKE=build/application.mk VERSION_FULL?=$(shell git describe)
BOOTMAKE=build/bootloader.mk APPMAKE=build/application.mk VERSION_FULL=${VERSION_FULL}
BOOTMAKE=build/bootloader.mk VERSION_FULL=${VERSION_FULL}
merge_hex=solo mergehex merge_hex=solo mergehex
@ -12,20 +13,14 @@ merge_hex=solo mergehex
# The following are the main targets for reproducible builds. # The following are the main targets for reproducible builds.
# TODO: better explanation # TODO: better explanation
firmware-hacker: firmware:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0
firmware-hacker-debug-1: firmware-debug-1:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1
firmware-hacker-debug-2: firmware-debug-2:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2
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'
bootloader-nonverifying: bootloader-nonverifying:
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0 $(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
@ -95,7 +90,7 @@ flashboot: bootloader.hex
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
flash-firmware: flash-firmware:
arm-none-eabi-size -A solo.elf $(SZ) -A solo.elf
solo program aux enter-bootloader solo program aux enter-bootloader
solo program bootloader solo.hex solo program bootloader solo.hex

View File

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

View File

@ -46,9 +46,7 @@ int main()
{ {
uint8_t hidmsg[64]; uint8_t hidmsg[64];
uint32_t t1 = 0; uint32_t t1 = 0;
#ifdef SOLO_HACKER
uint32_t stboot_time = 0; uint32_t stboot_time = 0;
#endif
uint32_t boot = 1; uint32_t boot = 1;
set_logging_mask( set_logging_mask(
@ -98,7 +96,6 @@ int main()
} }
#ifdef SOLO_HACKER
if (!is_bootloader_disabled()) if (!is_bootloader_disabled())
{ {
stboot_time = millis(); stboot_time = millis();
@ -108,7 +105,6 @@ int main()
goto start_bootloader; goto start_bootloader;
} }
} }
#endif
if (is_authorized_to_boot() && (boot || is_bootloader_disabled())) if (is_authorized_to_boot() && (boot || is_bootloader_disabled()))
{ {
@ -119,9 +115,8 @@ int main()
printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR); printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR);
} }
#ifdef SOLO_HACKER
start_bootloader: start_bootloader:
#endif
SystemClock_Config(); SystemClock_Config();
init_gpio(); init_gpio();
init_millisecond_timer(0); init_millisecond_timer(0);

View File

@ -66,7 +66,7 @@ all: $(TARGET).elf
%.elf: $(OBJ) %.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@ $(CC) $^ $(HW) $(LDFLAGS) -o $@
arm-none-eabi-size $@ $(SZ) $@
%.hex: %.elf %.hex: %.elf
$(CP) -O ihex $^ $(TARGET).hex $(CP) -O ihex $^ $(TARGET).hex

View File

@ -13,8 +13,8 @@ USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \ lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \
lib/usbd/usbd_ccid.c lib/usbd/usbd_ccid.c
VERSION:=$(shell git describe --abbrev=0 ) VERSION_FULL?=$(shell git describe)
VERSION_FULL:=$(shell git describe) VERSION:=$(shell python -c 'print("$(VERSION_FULL)".split("-")[0])')
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])') VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])') VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])') VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')

View File

@ -195,7 +195,8 @@ void device_init_button(void)
int solo_is_locked(){ int solo_is_locked(){
uint64_t device_settings = ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->device_settings; 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 /** device_migrate

View File

@ -32,14 +32,17 @@ static void flash_unlock(void)
void flash_option_bytes_init(int boot_from_dfu) void flash_option_bytes_init(int boot_from_dfu)
{ {
uint32_t val = 0xfffff8aa; 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) 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<<26); // nSWBOOT0 = 0 (boot from nBoot0)
val &= ~(1<<25); // SRAM2_RST = 1 (erase sram on reset) val &= ~(1<<25); // SRAM2_RST = 1 (erase sram on reset)
val &= ~(1<<24); // SRAM2_PE = 1 (parity check en) val &= ~(1<<24); // SRAM2_PE = 1 (parity check en)