Compare commits
9 Commits
backup_imp
...
move_certs
Author | SHA1 | Date | |
---|---|---|---|
0873fa5f34 | |||
bb08f6e0d3 | |||
9fa2c97dc3 | |||
49ca42991c | |||
ef683bdc99 | |||
69478b4b6e | |||
9d5942ad10 | |||
446f1e0176 | |||
de2c1eff1b |
@ -197,16 +197,6 @@
|
||||
"code",
|
||||
"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,
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -34,8 +34,7 @@
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
targets/*/*.hex
|
||||
targets/*/*.sha2
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
|
@ -6,15 +6,14 @@ addons:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-8
|
||||
- gcc-7
|
||||
- cppcheck
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
|
||||
- sudo apt-get update -q
|
||||
- sudo apt-get install -y gcc-arm-embedded python3-venv
|
||||
- sudo apt-get install -y gcc-arm-embedded
|
||||
- sudo apt-get install -y python3-venv
|
||||
script:
|
||||
- export CC=gcc-8
|
||||
- export CC=gcc-7
|
||||
- pyenv shell 3.6.7
|
||||
- make travis
|
||||
|
61
Dockerfile
61
Dockerfile
@ -1,38 +1,33 @@
|
||||
FROM debian:9.11-slim
|
||||
FROM debian:stretch-slim
|
||||
MAINTAINER SoloKeys <hello@solokeys.com>
|
||||
|
||||
# Install necessary packages
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
make \
|
||||
wget \
|
||||
bzip2 \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -qq bzip2 git make wget >/dev/null
|
||||
|
||||
# Install ARM compiler
|
||||
RUN set -eux; \
|
||||
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"; \
|
||||
wget -O gcc.tar.bz2 "$url"; \
|
||||
echo "6341f11972dac8de185646d0fbd73bfc gcc.tar.bz2" | md5sum -c -; \
|
||||
echo "b50b02b0a16e5aad8620e9d7c31110ef285c1dde28980b1a9448b764d77d8f92 gcc.tar.bz2" | sha256sum -c -; \
|
||||
tar -C /opt -xf gcc.tar.bz2; \
|
||||
rm gcc.tar.bz2;
|
||||
# 1. ARM GCC: for compilation
|
||||
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
|
||||
# from website
|
||||
RUN echo "f55f90d483ddb3bcf4dae5882c2094cd gcc.tar.bz2" > gcc.md5
|
||||
RUN md5sum -c gcc.md5
|
||||
# self-generated
|
||||
RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.tar.bz2" > gcc.sha256
|
||||
RUN sha256sum -c gcc.sha256
|
||||
RUN tar -C /opt -xf gcc.tar.bz2
|
||||
|
||||
# Python3.7: for solo-python (merging etc.)
|
||||
RUN set -eux; \
|
||||
url="https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh"; \
|
||||
wget -O miniconda.sh "$url"; \
|
||||
echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" | md5sum -c -; \
|
||||
echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" | sha256sum -c -; \
|
||||
bash ./miniconda.sh -b -p /opt/conda; \
|
||||
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
|
||||
# 2. 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
|
||||
# from website
|
||||
RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5
|
||||
RUN md5sum -c miniconda.md5
|
||||
# self-generated
|
||||
RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" > miniconda.sha256
|
||||
RUN sha256sum -c miniconda.sha256
|
||||
|
||||
# solo-python (Python3.7 script for merging etc.)
|
||||
RUN pip install -U solo-python
|
||||
RUN bash ./miniconda.sh -b -p /opt/conda
|
||||
RUN ln -s /opt/conda/bin/python /usr/local/bin/python3
|
||||
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
|
||||
|
48
Makefile
48
Makefile
@ -23,8 +23,8 @@ else
|
||||
endif
|
||||
LDFLAGS += $(LIBCBOR)
|
||||
|
||||
VERSION:=$(shell git describe --abbrev=0 )
|
||||
VERSION_FULL:=$(shell git describe)
|
||||
VERSION:=$(shell python -c 'print("$(VERSION_FULL)".split("-")[0])')
|
||||
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
|
||||
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
|
||||
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
|
||||
@ -62,7 +62,7 @@ test: venv
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C . main
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${VERSION_FULL}
|
||||
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)"
|
||||
$(MAKE) clean
|
||||
$(MAKE) cppcheck
|
||||
|
||||
@ -88,30 +88,18 @@ wink: venv
|
||||
fido2-test: venv
|
||||
venv/bin/python tools/ctap_test.py
|
||||
|
||||
update:
|
||||
git fetch --tags
|
||||
git checkout master
|
||||
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_IMAGE := "solokeys/solo-firmware:local"
|
||||
SOLO_VERSIONISH := "master"
|
||||
docker-build:
|
||||
docker build -t $(DOCKER_IMAGE) .
|
||||
docker run --rm -v "$(CURDIR)/builds:/builds" \
|
||||
-v "$(CURDIR):/solo" \
|
||||
$(DOCKER_TOOLCHAIN_IMAGE) "solo/in-docker-build.sh" ${VERSION_FULL}
|
||||
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
|
||||
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
|
||||
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
|
||||
|
||||
@ -132,14 +120,6 @@ clean:
|
||||
full-clean: clean
|
||||
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:
|
||||
$(MAKE) test VENV=". ../../venv/bin/activate;"
|
||||
$(MAKE) test-docker
|
||||
$(MAKE) black
|
||||
$(MAKE) black
|
||||
|
64
README.md
64
README.md
@ -32,58 +32,10 @@ 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.
|
||||
|
||||
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
|
||||
git clone --recurse-submodules https://github.com/solokeys/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
|
||||
make cbor
|
||||
make build-hacker
|
||||
@ -95,6 +47,19 @@ solo program aux enter-bootloader
|
||||
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)
|
||||
|
||||
Clone Solo and build it
|
||||
@ -166,7 +131,6 @@ 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="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/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>
|
||||
</table>
|
||||
|
||||
@ -200,7 +164,7 @@ You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solok
|
||||
<br/>
|
||||
|
||||
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
||||
[](#contributors)
|
||||
[](#contributors)
|
||||
[](https://travis-ci.com/solokeys/solo)
|
||||
[](https://discourse.solokeys.com)
|
||||
[](https://keybase.io/team/solokeys.public)
|
||||
|
@ -1 +1 @@
|
||||
3.0.0
|
||||
2.5.3
|
||||
|
@ -1,17 +1,16 @@
|
||||
# Booting into bootloader mode
|
||||
|
||||
If you have a recent version of Solo, you can put it into bootloader mode by running this command.
|
||||
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.
|
||||
|
||||
```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.
|
||||
@ -22,8 +21,7 @@ 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/nonverifying-bootloader devices, you can boot into the DFU by holding down the button for 5 seconds,
|
||||
when Solo is already in bootloader mode.
|
||||
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.
|
||||
|
||||
@ -31,7 +29,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 you to tell it to boot again. You can boot it again by running the following.
|
||||
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
|
||||
|
@ -36,21 +36,17 @@ Enter the `stm32l4xx` target directory.
|
||||
cd targets/stm32l432
|
||||
```
|
||||
|
||||
Now build the Solo application.
|
||||
Now build Solo.
|
||||
|
||||
```
|
||||
make firmware
|
||||
make build-hacker
|
||||
```
|
||||
|
||||
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
|
||||
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`. -->
|
||||
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`.
|
||||
@ -61,13 +57,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 firmware-debug-1
|
||||
make build-hacker 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.
|
||||
|
||||
@ -82,45 +78,27 @@ solo monitor <serial-port>
|
||||
|
||||
[See issue 62](https://github.com/solokeys/solo/issues/62).
|
||||
|
||||
### Building a complete Solo build (application + bootloader + certificate)
|
||||
### Building a Solo release
|
||||
|
||||
To make a complete Solo build, you need to build the bootloader. We provide
|
||||
two easy recipes:
|
||||
To build Solo
|
||||
|
||||
* `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 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.
|
||||
|
||||
To be safe, let's use the `-nonverifying` build.
|
||||
If you're ready to program a full release, run this recipe to build.
|
||||
|
||||
```
|
||||
make bootloader-nonverifying
|
||||
make build-release-locked
|
||||
```
|
||||
|
||||
This outputs `bootloader.hex`. We can then merge the bootloader and application.
|
||||
This outputs bootloader.hex, solo.hex, and the combined all.hex.
|
||||
|
||||
```
|
||||
solo mergehex bootloader.hex solo.hex bundle.hex
|
||||
```
|
||||
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.
|
||||
|
||||
`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).
|
||||
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).
|
||||
|
||||
|
@ -114,27 +114,28 @@ If the checks succeed, you are ready to program the device attestation key and c
|
||||
|
||||
### Programming an attestation key and certificate
|
||||
|
||||
First, [Build your solo application and bootloader](/solo/building).
|
||||
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`).
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
Merge the `bootloader.hex`, `solo.hex`, attestion key, and certificate into one firmware file.
|
||||
Merge the `bootloader.hex`, `solo.hex`, and attestion key into one firmware file.
|
||||
|
||||
```
|
||||
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
|
||||
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex
|
||||
```
|
||||
|
||||
Now you have a newly created `bundle.hex` file with a custom attestation key and cert. You can [program this `bundle.hex` file
|
||||
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).
|
||||
|
||||
Are you interested in customizing in bulk? Contact hello@solokeys.com and we can help.
|
||||
|
@ -22,11 +22,12 @@ 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](/solo/customization/).
|
||||
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
|
||||
|
||||
@ -37,14 +38,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 `bundle.hex` from your build. If you overwrite the Solo flash with a missing 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 small privacy implication that services can distinguish it from Solo Secure.
|
||||
concern with using our default attestation key, aside from a privacy implication that services can distinguish it from Solo Secure.
|
||||
|
||||
### Procedure
|
||||
|
||||
@ -60,7 +61,7 @@ concern with using our default attestation key, aside from a small privacy impli
|
||||
|
||||
2. Program the device
|
||||
|
||||
solo program dfu <bundle-secure-non-solokeys.hex | bundle.hex>
|
||||
solo program dfu <bundle-secure-non-solokeys.hex | all.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.
|
||||
|
@ -710,7 +710,6 @@ 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);
|
||||
@ -760,37 +759,30 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
||||
case CTAPHID_LOADKEY:
|
||||
/**
|
||||
* Load external key. Useful for enabling backups.
|
||||
* bytes: 4 4 96
|
||||
* payload: version [maj rev patch RFU]| counter_replacement (BE) | master_key |
|
||||
* bytes: 4 96
|
||||
* payload: | counter_increase (BE) | master_key |
|
||||
*
|
||||
* Counter should be increased by a large amount, e.g. (0x10000000)
|
||||
* to outdo any previously lost/broken keys.
|
||||
*/
|
||||
printf1(TAG_HID,"CTAPHID_LOADKEY\n");
|
||||
if (len != 104)
|
||||
if (len != 100)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, invalid length.\n");
|
||||
ctaphid_send_error(wb->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return 1;
|
||||
}
|
||||
param = ctap_buffer[0] << 16;
|
||||
param |= ctap_buffer[1] << 8;
|
||||
param |= ctap_buffer[2] << 0;
|
||||
if (param != 0){
|
||||
ctaphid_send_error(wb->cid, CTAP2_ERR_UNSUPPORTED_OPTION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ask for THREE button presses
|
||||
if (ctap_user_presence_test(8000) > 0)
|
||||
if (ctap_user_presence_test(2000) > 0)
|
||||
if (ctap_user_presence_test(2000) > 0)
|
||||
if (ctap_user_presence_test(8000) > 0)
|
||||
if (ctap_user_presence_test(8000) > 0)
|
||||
{
|
||||
ctap_load_external_keys(ctap_buffer + 8);
|
||||
param = ctap_buffer[7];
|
||||
param |= ctap_buffer[6] << 8;
|
||||
param |= ctap_buffer[5] << 16;
|
||||
param |= ctap_buffer[4] << 24;
|
||||
ctap_load_external_keys(ctap_buffer + 4);
|
||||
param = ctap_buffer[3];
|
||||
param |= ctap_buffer[2] << 8;
|
||||
param |= ctap_buffer[1] << 16;
|
||||
param |= ctap_buffer[0] << 24;
|
||||
ctap_atomic_count(param);
|
||||
|
||||
wb->bcnt = 0;
|
||||
|
@ -1,10 +1,14 @@
|
||||
#!/bin/bash -xe
|
||||
version=$1
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
|
||||
version=${1:-master}
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
|
||||
|
||||
cd /solo/targets/stm32l432
|
||||
ls
|
||||
git fetch --tags
|
||||
git checkout ${version}
|
||||
git submodule update --init --recursive
|
||||
version=$(git describe)
|
||||
|
||||
make cbor
|
||||
|
||||
@ -12,12 +16,13 @@ out_dir="/builds"
|
||||
|
||||
function build() {
|
||||
part=${1}
|
||||
output=${2}
|
||||
what="${part}"
|
||||
variant=${2}
|
||||
output=${3:-${part}}
|
||||
what="${part}-${variant}"
|
||||
|
||||
make full-clean
|
||||
|
||||
make ${what} VERSION_FULL=${version}
|
||||
make ${what}
|
||||
|
||||
out_hex="${what}-${version}.hex"
|
||||
out_sha2="${what}-${version}.sha2"
|
||||
@ -27,27 +32,24 @@ function build() {
|
||||
cp ${out_hex} ${out_sha2} ${out_dir}
|
||||
}
|
||||
|
||||
build bootloader-nonverifying bootloader
|
||||
build bootloader-verifying bootloader
|
||||
build firmware solo
|
||||
build firmware-debug-1 solo
|
||||
build firmware-debug-2 solo
|
||||
build firmware solo
|
||||
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
|
||||
|
||||
pip install -U pip
|
||||
pip install -U solo-python
|
||||
cd ${out_dir}
|
||||
|
||||
bundle="bundle-hacker-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-${version}.hex ${bundle}.hex
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-${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-debug-1-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
||||
/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-debug-2-${version}.hex ${bundle}.hex
|
||||
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}"
|
||||
/opt/conda/bin/solo mergehex --lock bootloader-verifying-${version}.hex firmware-${version}.hex ${bundle}.hex
|
||||
/opt/conda/bin/solo mergehex bootloader-verifying-${version}.hex firmware-secure-non-solokeys-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
@ -2,9 +2,8 @@ ifndef DEBUG
|
||||
DEBUG=0
|
||||
endif
|
||||
|
||||
VERSION_FULL?=$(shell git describe)
|
||||
APPMAKE=build/application.mk VERSION_FULL=${VERSION_FULL}
|
||||
BOOTMAKE=build/bootloader.mk VERSION_FULL=${VERSION_FULL}
|
||||
APPMAKE=build/application.mk
|
||||
BOOTMAKE=build/bootloader.mk
|
||||
|
||||
merge_hex=solo mergehex
|
||||
|
||||
@ -13,14 +12,20 @@ merge_hex=solo mergehex
|
||||
|
||||
# The following are the main targets for reproducible builds.
|
||||
# TODO: better explanation
|
||||
firmware:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0
|
||||
firmware-hacker:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1
|
||||
firmware-hacker-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-debug-2:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2
|
||||
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'
|
||||
|
||||
bootloader-nonverifying:
|
||||
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
|
||||
@ -90,7 +95,7 @@ flashboot: bootloader.hex
|
||||
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
|
||||
|
||||
flash-firmware:
|
||||
$(SZ) -A solo.elf
|
||||
arm-none-eabi-size -A solo.elf
|
||||
solo program aux enter-bootloader
|
||||
solo program bootloader solo.hex
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define _APP_H_
|
||||
#include <stdint.h>
|
||||
#include "version.h"
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
@ -20,7 +21,6 @@
|
||||
#define BOOT_TO_DFU 0
|
||||
|
||||
|
||||
#define SOLO 1
|
||||
#define IS_BOOTLOADER 1
|
||||
|
||||
#define ENABLE_U2F_EXTENSIONS
|
||||
|
@ -46,7 +46,9 @@ int main()
|
||||
{
|
||||
uint8_t hidmsg[64];
|
||||
uint32_t t1 = 0;
|
||||
#ifdef SOLO_HACKER
|
||||
uint32_t stboot_time = 0;
|
||||
#endif
|
||||
uint32_t boot = 1;
|
||||
|
||||
set_logging_mask(
|
||||
@ -96,6 +98,7 @@ int main()
|
||||
}
|
||||
|
||||
|
||||
#ifdef SOLO_HACKER
|
||||
if (!is_bootloader_disabled())
|
||||
{
|
||||
stboot_time = millis();
|
||||
@ -105,6 +108,7 @@ int main()
|
||||
goto start_bootloader;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_authorized_to_boot() && (boot || is_bootloader_disabled()))
|
||||
{
|
||||
@ -115,8 +119,9 @@ int main()
|
||||
|
||||
printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR);
|
||||
}
|
||||
#ifdef SOLO_HACKER
|
||||
start_bootloader:
|
||||
|
||||
#endif
|
||||
SystemClock_Config();
|
||||
init_gpio();
|
||||
init_millisecond_timer(0);
|
||||
|
@ -66,7 +66,7 @@ all: $(TARGET).elf
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||
$(SZ) $@
|
||||
arm-none-eabi-size $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(CP) -O ihex $^ $(TARGET).hex
|
||||
|
@ -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_ccid.c
|
||||
|
||||
VERSION_FULL?=$(shell git describe)
|
||||
VERSION:=$(shell python -c 'print("$(VERSION_FULL)".split("-")[0])')
|
||||
VERSION:=$(shell git describe --abbrev=0 )
|
||||
VERSION_FULL:=$(shell git describe)
|
||||
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
|
||||
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
|
||||
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
|
||||
|
@ -195,8 +195,7 @@ void device_init_button(void)
|
||||
|
||||
int solo_is_locked(){
|
||||
uint64_t device_settings = ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->device_settings;
|
||||
uint32_t tag = (uint32_t)(device_settings >> 32ull);
|
||||
return tag == ATTESTATION_CONFIGURED_TAG && (device_settings & SOLO_FLAG_LOCKED) != 0;
|
||||
return (device_settings & SOLO_FLAG_LOCKED) != 0;
|
||||
}
|
||||
|
||||
/** device_migrate
|
||||
@ -560,11 +559,7 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
||||
return lastc;
|
||||
}
|
||||
|
||||
if (amount > 256){
|
||||
lastc = amount;
|
||||
} else {
|
||||
lastc += amount;
|
||||
}
|
||||
lastc += amount;
|
||||
|
||||
if (lastc/256 > erases)
|
||||
{
|
||||
|
@ -32,17 +32,14 @@ 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)
|
||||
|
Reference in New Issue
Block a user