Compare commits
28 Commits
move_certs
...
simplify_b
Author | SHA1 | Date | |
---|---|---|---|
f019d7fc22 | |||
e3409ca613 | |||
81ec63f17a | |||
e4bc364c38 | |||
4c464c9cc4 | |||
8ecaa9a3de | |||
98803b7dd0 | |||
a1a79b05fd | |||
c0df8b680d | |||
9ac2aa90c3 | |||
d33749fc16 | |||
96a2cbcb41 | |||
7212982385 | |||
89e218e561 | |||
666cd6a0ba | |||
b4f59ec355 | |||
b7d74cc99f | |||
375a607356 | |||
ea8409c072 | |||
04f06b3b0d | |||
a57c5170e1 | |||
aaffce4021 | |||
463a8b444d | |||
44ed3ceea5 | |||
30f73b41e4 | |||
6f6e831fba | |||
9fd608d3ee | |||
765dc27b15 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -34,7 +34,8 @@
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
targets/*/*.hex
|
||||
targets/*/*.sha2
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
|
@ -6,14 +6,15 @@ addons:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-7
|
||||
- gcc-8
|
||||
- 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
|
||||
- sudo apt-get install -y python3-venv
|
||||
- sudo apt-get install -y gcc-arm-embedded python3-venv
|
||||
script:
|
||||
- export CC=gcc-7
|
||||
- export CC=gcc-8
|
||||
- pyenv shell 3.6.7
|
||||
- make travis
|
||||
|
61
Dockerfile
61
Dockerfile
@ -1,33 +1,38 @@
|
||||
FROM debian:stretch-slim
|
||||
FROM debian:9.11-slim
|
||||
MAINTAINER SoloKeys <hello@solokeys.com>
|
||||
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -qq bzip2 git make wget >/dev/null
|
||||
# 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/*
|
||||
|
||||
# 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
|
||||
# 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;
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
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
|
||||
# solo-python (Python3.7 script for merging etc.)
|
||||
RUN pip install -U solo-python
|
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)"
|
||||
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${VERSION_FULL}
|
||||
$(MAKE) clean
|
||||
$(MAKE) cppcheck
|
||||
|
||||
@ -88,18 +88,30 @@ wink: venv
|
||||
fido2-test: venv
|
||||
venv/bin/python tools/ctap_test.py
|
||||
|
||||
DOCKER_IMAGE := "solokeys/solo-firmware:local"
|
||||
SOLO_VERSIONISH := "master"
|
||||
docker-build:
|
||||
docker build -t $(DOCKER_IMAGE) .
|
||||
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 run --rm -v "$(CURDIR)/builds:/builds" \
|
||||
-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)
|
||||
-v "$(CURDIR):/solo" \
|
||||
$(DOCKER_TOOLCHAIN_IMAGE) "solo/in-docker-build.sh" ${VERSION_FULL}
|
||||
|
||||
CPPCHECK_FLAGS=--quiet --error-exitcode=2
|
||||
|
||||
@ -120,6 +132,14 @@ 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) black
|
||||
$(MAKE) test-docker
|
||||
$(MAKE) black
|
61
README.md
61
README.md
@ -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.
|
||||
|
||||
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
|
||||
@ -47,19 +95,6 @@ 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
|
||||
|
@ -1,16 +1,17 @@
|
||||
# Booting into bootloader mode
|
||||
|
||||
You can put Solo into bootloader mode by holding down the button, and plugging in Solo. After 2 seconds, bootloader mode will activate.
|
||||
You'll see a yellowish flashing light and you can let go of the button.
|
||||
|
||||
Now Solo is ready to [accept firmware updates](/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.
|
||||
If you have a recent version of Solo, you can put it into bootloader mode by running this command.
|
||||
|
||||
```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.
|
||||
@ -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
|
||||
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.
|
||||
|
||||
@ -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
|
||||
```
|
||||
|
||||
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
|
||||
solo program aux leave-dfu
|
||||
|
@ -36,17 +36,21 @@ Enter the `stm32l4xx` target directory.
|
||||
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
|
||||
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`.
|
||||
@ -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
|
||||
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
|
||||
miss any debug messages.
|
||||
|
||||
@ -78,27 +82,45 @@ solo monitor <serial-port>
|
||||
|
||||
[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
|
||||
just to make sure that it's working. Otherwise it may not be as easy or possible to
|
||||
fix any mistakes.
|
||||
* `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'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
|
||||
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).
|
||||
`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).
|
||||
|
||||
|
@ -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
|
||||
|
||||
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`).
|
||||
First, [Build your solo application and bootloader](/solo/building).
|
||||
|
||||
```
|
||||
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.
|
||||
Print your attestation key in a hex string format. Using our utility script:
|
||||
|
||||
```
|
||||
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).
|
||||
|
||||
Are you interested in customizing in bulk? Contact hello@solokeys.com and we can help.
|
||||
|
@ -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.
|
||||
|
||||
```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]().
|
||||
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
|
||||
|
||||
@ -38,14 +37,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 `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.
|
||||
|
||||
We provide two types of bundled builds. The `bundle-hacker-*.hex` build is the hacker build. If you update with this,
|
||||
you will update the bootloader and application, but nothing will be secured. The `bundle-secure-non-solokeys.hex`
|
||||
is a secured build that will lock your device and it will behave just like a Secure Solo. The main difference is that
|
||||
it uses a "default" attestation key in the device, rather than the SoloKeys attestation key. There is no security
|
||||
concern with using our default attestation key, aside from a privacy implication that services can distinguish it from Solo Secure.
|
||||
concern with using our default attestation key, aside from a small privacy implication that services can distinguish it from Solo Secure.
|
||||
|
||||
### Procedure
|
||||
|
||||
@ -61,7 +60,7 @@ concern with using our default attestation key, aside from a privacy implication
|
||||
|
||||
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).
|
||||
If you messed it up, simply don't do the next step and repeat this step correctly.
|
||||
|
@ -47,7 +47,7 @@ typedef enum
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t attestation_cert_der[];
|
||||
const uint8_t * attestation_cert_der;
|
||||
const uint16_t attestation_cert_der_size;
|
||||
const uint8_t attestation_key[];
|
||||
const uint16_t attestation_key_size;
|
||||
@ -338,7 +338,7 @@ void crypto_aes256_encrypt(uint8_t * buf, int length)
|
||||
}
|
||||
|
||||
|
||||
const uint8_t attestation_cert_der[] =
|
||||
const uint8_t _attestation_cert_der[] =
|
||||
"\x30\x82\x01\xfb\x30\x82\x01\xa1\xa0\x03\x02\x01\x02\x02\x01\x00\x30\x0a\x06\x08"
|
||||
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
|
||||
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e"
|
||||
@ -365,9 +365,11 @@ const uint8_t attestation_cert_der[] =
|
||||
"\x7e\x74\x64\x1b\xa3\x7b\xf7\xe6\xd3\xaf\x79\x28\xdb\xdc\xa5\x88\x02\x21\x00\xcd"
|
||||
"\x06\xf1\xe3\xab\x16\x21\x8e\xd8\xc0\x14\xaf\x09\x4f\x5b\x73\xef\x5e\x9e\x4b\xe7"
|
||||
"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7";
|
||||
const uint8_t * attestation_cert_der = (const uint8_t *)_attestation_cert_der;
|
||||
|
||||
|
||||
const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
|
||||
uint16_t attestation_cert_der_get_size(){
|
||||
return sizeof(_attestation_cert_der)-1;
|
||||
}
|
||||
|
||||
|
||||
const uint8_t attestation_key[] = "\xcd\x67\xaa\x31\x0d\x09\x1e\xd1\x6e\x7e\x98\x92\xaa\x07\x0e\x19\x94\xfc\xd7\x14\xae\x7c\x40\x8f\xb9\x46\xb7\x2e\x5f\xe7\x5d\x30";
|
||||
|
@ -54,10 +54,7 @@ void crypto_reset_master_secret();
|
||||
void crypto_load_master_secret(uint8_t * key);
|
||||
|
||||
|
||||
extern const uint8_t attestation_cert_der[];
|
||||
extern const uint16_t attestation_cert_der_size;
|
||||
|
||||
extern const uint8_t attestation_key[];
|
||||
extern const uint16_t attestation_key_size;
|
||||
extern const uint8_t * attestation_cert_der;
|
||||
uint16_t attestation_cert_der_get_size();
|
||||
|
||||
#endif
|
||||
|
@ -661,7 +661,7 @@ uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
|
||||
ret = cbor_encoder_create_array(&stmtmap, &x5carr, 1);
|
||||
check_ret(ret);
|
||||
{
|
||||
ret = cbor_encode_byte_string(&x5carr, attestation_cert_der, attestation_cert_der_size);
|
||||
ret = cbor_encode_byte_string(&x5carr, attestation_cert_der, attestation_cert_der_get_size());
|
||||
check_ret(ret);
|
||||
ret = cbor_encoder_close_container(&stmtmap, &x5carr);
|
||||
check_ret(ret);
|
||||
|
@ -696,7 +696,7 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
||||
{
|
||||
ctap_response_init(ctap_resp);
|
||||
|
||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_EXPERIMENTAL))
|
||||
uint32_t param;
|
||||
#endif
|
||||
#if defined(IS_BOOTLOADER)
|
||||
@ -710,23 +710,20 @@ 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);
|
||||
ctaphid_write(wb, NULL, 0);
|
||||
return 1;
|
||||
#endif
|
||||
#if defined(SOLO_HACKER)
|
||||
#if defined(SOLO)
|
||||
case CTAPHID_ENTERBOOT:
|
||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||
boot_solo_bootloader();
|
||||
wb->bcnt = 0;
|
||||
ctaphid_write(wb, NULL, 0);
|
||||
return 1;
|
||||
case CTAPHID_ENTERSTBOOT:
|
||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||
boot_st_bootloader();
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#if !defined(IS_BOOTLOADER)
|
||||
@ -745,16 +742,21 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
||||
|
||||
case CTAPHID_GETVERSION:
|
||||
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
|
||||
wb->bcnt = 3;
|
||||
wb->bcnt = 4;
|
||||
ctap_buffer[0] = SOLO_VERSION_MAJ;
|
||||
ctap_buffer[1] = SOLO_VERSION_MIN;
|
||||
ctap_buffer[2] = SOLO_VERSION_PATCH;
|
||||
ctaphid_write(wb, ctap_buffer, 3);
|
||||
#if defined(SOLO)
|
||||
ctap_buffer[3] = solo_is_locked();
|
||||
#else
|
||||
ctap_buffer[3] = 0;
|
||||
#endif
|
||||
ctaphid_write(wb, ctap_buffer, 4);
|
||||
ctaphid_write(wb, NULL, 0);
|
||||
return 1;
|
||||
break;
|
||||
|
||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_EXPERIMENTAL))
|
||||
case CTAPHID_LOADKEY:
|
||||
/**
|
||||
* Load external key. Useful for enabling backups.
|
||||
|
@ -306,7 +306,7 @@ static int16_t u2f_register(struct u2f_register_request * req)
|
||||
uint8_t * sig = (uint8_t*)req;
|
||||
|
||||
|
||||
const uint16_t attest_size = attestation_cert_der_size;
|
||||
const uint16_t attest_size = attestation_cert_der_get_size();
|
||||
|
||||
if ( ! ctap_user_presence_test(750))
|
||||
{
|
||||
|
@ -1,14 +1,10 @@
|
||||
#!/bin/bash -xe
|
||||
version=$1
|
||||
|
||||
version=${1:-master}
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
|
||||
|
||||
cd /solo/targets/stm32l432
|
||||
git fetch --tags
|
||||
git checkout ${version}
|
||||
git submodule update --init --recursive
|
||||
version=$(git describe)
|
||||
ls
|
||||
|
||||
make cbor
|
||||
|
||||
@ -16,13 +12,12 @@ out_dir="/builds"
|
||||
|
||||
function build() {
|
||||
part=${1}
|
||||
variant=${2}
|
||||
output=${3:-${part}}
|
||||
what="${part}-${variant}"
|
||||
output=${2}
|
||||
what="${part}"
|
||||
|
||||
make full-clean
|
||||
|
||||
make ${what}
|
||||
make ${what} VERSION_FULL=${version}
|
||||
|
||||
out_hex="${what}-${version}.hex"
|
||||
out_sha2="${what}-${version}.sha2"
|
||||
@ -32,24 +27,27 @@ function build() {
|
||||
cp ${out_hex} ${out_sha2} ${out_dir}
|
||||
}
|
||||
|
||||
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
|
||||
build bootloader-nonverifying bootloader
|
||||
build bootloader-verifying bootloader
|
||||
build firmware solo
|
||||
build firmware-debug-1 solo
|
||||
build firmware-debug-2 solo
|
||||
build firmware 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-hacker-${version}.hex ${bundle}.hex
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-${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-hacker-debug-1-${version}.hex ${bundle}.hex
|
||||
bundle="bundle-hacker-debug-2-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-2-${version}.hex ${bundle}.hex
|
||||
bundle="bundle-secure-non-solokeys-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-verifying-${version}.hex firmware-secure-non-solokeys-${version}.hex ${bundle}.hex
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-1-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
@ -2,8 +2,9 @@ ifndef DEBUG
|
||||
DEBUG=0
|
||||
endif
|
||||
|
||||
APPMAKE=build/application.mk
|
||||
BOOTMAKE=build/bootloader.mk
|
||||
VERSION_FULL?=$(shell git describe)
|
||||
APPMAKE=build/application.mk VERSION_FULL=${VERSION_FULL}
|
||||
BOOTMAKE=build/bootloader.mk VERSION_FULL=${VERSION_FULL}
|
||||
|
||||
merge_hex=solo mergehex
|
||||
|
||||
@ -12,20 +13,14 @@ merge_hex=solo mergehex
|
||||
|
||||
# The following are the main targets for reproducible builds.
|
||||
# TODO: better explanation
|
||||
firmware-hacker:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
firmware:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0
|
||||
|
||||
firmware-hacker-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
firmware-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1
|
||||
|
||||
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'
|
||||
firmware-debug-2:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2
|
||||
|
||||
bootloader-nonverifying:
|
||||
$(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
|
||||
|
||||
flash-firmware:
|
||||
arm-none-eabi-size -A solo.elf
|
||||
$(SZ) -A solo.elf
|
||||
solo program aux enter-bootloader
|
||||
solo program bootloader solo.hex
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define _APP_H_
|
||||
#include <stdint.h>
|
||||
#include "version.h"
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
@ -21,6 +20,7 @@
|
||||
#define BOOT_TO_DFU 0
|
||||
|
||||
|
||||
#define SOLO 1
|
||||
#define IS_BOOTLOADER 1
|
||||
|
||||
#define ENABLE_U2F_EXTENSIONS
|
||||
@ -64,4 +64,9 @@ int is_authorized_to_boot();
|
||||
int is_bootloader_disabled();
|
||||
void bootloader_heartbeat();
|
||||
|
||||
// Return 1 if Solo is secure/locked.
|
||||
int solo_is_locked();
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -66,7 +66,7 @@ all: $(TARGET).elf
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||
arm-none-eabi-size $@
|
||||
$(SZ) $@
|
||||
|
||||
%.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:=$(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_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
|
||||
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <stdint.h>
|
||||
#include "version.h"
|
||||
|
||||
#define SOLO
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
@ -46,6 +48,9 @@
|
||||
void printing_init();
|
||||
void hw_init(int lf);
|
||||
|
||||
// Return 1 if Solo is secure/locked.
|
||||
int solo_is_locked();
|
||||
|
||||
//#define TEST
|
||||
//#define TEST_POWER
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
#include <stdint.h>
|
||||
#include "crypto.h"
|
||||
#include "memory_layout.h"
|
||||
|
||||
#ifdef USE_SOLOKEYS_CERT
|
||||
|
||||
const uint8_t attestation_cert_der[] =
|
||||
const uint8_t attestation_solo_cert_der[] =
|
||||
"\x30\x82\x02\xe1\x30\x82\x02\x88\xa0\x03\x02\x01\x02\x02\x01\x01\x30\x0a\x06\x08"
|
||||
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x81\x80\x31\x0b\x30\x09\x06\x03\x55\x04\x06"
|
||||
"\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4d\x61\x72\x79\x6c"
|
||||
@ -49,11 +49,8 @@ const uint8_t attestation_cert_der[] =
|
||||
"\xf8\x84\xc3\x78\x35\x93\x63\x81\x2e\xbe\xa6\x12\x32\x6e\x29\x90\xc8\x91\x4b\x71"
|
||||
"\x52"
|
||||
;
|
||||
#else
|
||||
|
||||
// For testing/development only
|
||||
|
||||
const uint8_t attestation_cert_der[] =
|
||||
const uint8_t attestation_hacker_cert_der[] =
|
||||
"\x30\x82\x02\xe9\x30\x82\x02\x8e\xa0\x03\x02\x01\x02\x02\x01\x01\x30\x0a\x06\x08"
|
||||
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x81\x82\x31\x0b\x30\x09\x06\x03\x55\x04\x06"
|
||||
"\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4d\x61\x72\x79\x6c"
|
||||
@ -94,8 +91,16 @@ const uint8_t attestation_cert_der[] =
|
||||
"\xf3\x87\x61\x82\xd8\xcd\x48\xfc\x57"
|
||||
;
|
||||
|
||||
#endif
|
||||
|
||||
const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
|
||||
const uint16_t attestation_solo_cert_der_size = sizeof(attestation_solo_cert_der)-1;
|
||||
const uint16_t attestation_hacker_cert_der_size = sizeof(attestation_hacker_cert_der)-1;
|
||||
|
||||
// const uint16_t attestation_key_size = 32;
|
||||
const uint8_t * attestation_cert_der = ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_cert;
|
||||
|
||||
#include "log.h"
|
||||
uint16_t attestation_cert_der_get_size(){
|
||||
uint16_t sz = (uint16_t)((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_cert_size;
|
||||
return sz;
|
||||
}
|
||||
|
||||
const uint16_t attestation_key_size = 32;
|
||||
|
@ -194,9 +194,10 @@ void crypto_ecc256_init(void)
|
||||
|
||||
void crypto_ecc256_load_attestation_key(void)
|
||||
{
|
||||
static uint8_t _key [32];
|
||||
memmove(_key, (uint8_t*)ATTESTATION_KEY_ADDR, 32);
|
||||
_signing_key = _key;
|
||||
// static uint8_t _key [32];
|
||||
flash_attestation_page * page =(flash_attestation_page *)ATTESTATION_PAGE_ADDR;
|
||||
// memmove(_key, (uint8_t *)ATTESTATION_KEY_ADDR, 32);
|
||||
_signing_key = page->attestation_key;
|
||||
_key_len = 32;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
#define LOW_FREQUENCY 1
|
||||
#define HIGH_FREQUENCY 0
|
||||
|
||||
#define SOLO_FLAG_LOCKED 0x2
|
||||
|
||||
void wait_for_usb_tether(void);
|
||||
|
||||
|
||||
@ -191,6 +193,98 @@ 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;
|
||||
}
|
||||
|
||||
/** device_migrate
|
||||
* Depending on version of device, migrates:
|
||||
* * Moves attestation certificate to data segment.
|
||||
* * Creates locked variable and stores in data segment.
|
||||
*
|
||||
* Once in place, this allows all devices to accept same firmware,
|
||||
* rather than using "hacker" and "secure" builds.
|
||||
*/
|
||||
static void device_migrate(){
|
||||
extern const uint16_t attestation_solo_cert_der_size;
|
||||
extern const uint16_t attestation_hacker_cert_der_size;
|
||||
|
||||
extern uint8_t attestation_solo_cert_der[];
|
||||
extern uint8_t attestation_hacker_cert_der[];
|
||||
|
||||
uint64_t device_settings = ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->device_settings;
|
||||
uint32_t configure_tag = (uint32_t)(device_settings >> 32);
|
||||
|
||||
if (configure_tag != ATTESTATION_CONFIGURED_TAG)
|
||||
{
|
||||
printf1(TAG_RED,"Migrating certificate and lock information to data segment.\r\n");
|
||||
|
||||
device_settings = ATTESTATION_CONFIGURED_TAG;
|
||||
device_settings <<= 32;
|
||||
|
||||
// Read current device lock level.
|
||||
uint32_t optr = FLASH->OPTR;
|
||||
if ((optr & 0xff) != 0xAA){
|
||||
device_settings |= SOLO_FLAG_LOCKED;
|
||||
}
|
||||
|
||||
uint8_t tmp_attestation_key[32];
|
||||
|
||||
memmove(tmp_attestation_key,
|
||||
((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_key,
|
||||
32);
|
||||
|
||||
flash_erase_page(ATTESTATION_PAGE);
|
||||
flash_write(
|
||||
(uint32_t)((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_key,
|
||||
tmp_attestation_key,
|
||||
32
|
||||
);
|
||||
|
||||
// Check if this is Solo Hacker attestation (not confidential)
|
||||
// then write solo or hacker attestation cert to flash page.
|
||||
uint8_t solo_hacker_attestation_key[32] = "\x1b\x26\x26\xec\xc8\xf6\x9b\x0f\x69\xe3\x4f"
|
||||
"\xb2\x36\xd7\x64\x66\xba\x12\xac\x16\xc3\xab"
|
||||
"\x57\x50\xba\x06\x4e\x8b\x90\xe0\x24\x48";
|
||||
|
||||
if (memcmp(solo_hacker_attestation_key,
|
||||
tmp_attestation_key,
|
||||
32) == 0)
|
||||
{
|
||||
printf1(TAG_GREEN,"Updating solo hacker cert\r\n");
|
||||
flash_write_dword(
|
||||
(uint32_t)&((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_cert_size,
|
||||
(uint64_t)attestation_hacker_cert_der_size
|
||||
);
|
||||
flash_write(
|
||||
(uint32_t)((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_cert,
|
||||
attestation_hacker_cert_der,
|
||||
attestation_hacker_cert_der_size
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_GREEN,"Updating solo secure cert\r\n");
|
||||
flash_write_dword(
|
||||
(uint32_t)&((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_cert_size,
|
||||
(uint64_t)attestation_solo_cert_der_size
|
||||
);
|
||||
flash_write(
|
||||
(uint32_t)((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->attestation_cert,
|
||||
attestation_solo_cert_der,
|
||||
attestation_solo_cert_der_size
|
||||
);
|
||||
}
|
||||
|
||||
// Save / done.
|
||||
flash_write_dword(
|
||||
(uint32_t) & ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->device_settings,
|
||||
(uint64_t)device_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void device_init(int argc, char *argv[])
|
||||
{
|
||||
|
||||
@ -219,6 +313,8 @@ void device_init(int argc, char *argv[])
|
||||
ctaphid_init();
|
||||
ctap_init();
|
||||
|
||||
device_migrate();
|
||||
|
||||
#if BOOT_TO_DFU
|
||||
flash_option_bytes_init(1);
|
||||
#else
|
||||
|
@ -31,21 +31,18 @@ static void flash_unlock(void)
|
||||
// Locks flash and turns off DFU
|
||||
void flash_option_bytes_init(int boot_from_dfu)
|
||||
{
|
||||
#ifndef FLASH_ROP
|
||||
#define FLASH_ROP 0
|
||||
#endif
|
||||
#if FLASH_ROP == 0
|
||||
uint32_t val = 0xfffff8aa;
|
||||
#elif FLASH_ROP == 2
|
||||
uint32_t val = 0xfffff8cc;
|
||||
#else
|
||||
uint32_t val = 0xfffff8b9;
|
||||
#endif
|
||||
|
||||
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)
|
||||
|
@ -17,8 +17,11 @@
|
||||
#define COUNTER1_PAGE (PAGES - 3)
|
||||
|
||||
// State of FIDO2 application
|
||||
#define STATE2_PAGE (PAGES - 2)
|
||||
#define STATE1_PAGE (PAGES - 1)
|
||||
#define STATE2_PAGE (PAGES - 2)
|
||||
#define STATE1_PAGE (PAGES - 1)
|
||||
|
||||
#define STATE1_PAGE_ADDR (0x08000000 + ((STATE1_PAGE)*PAGE_SIZE))
|
||||
#define STATE2_PAGE_ADDR (0x08000000 + ((STATE2_PAGE)*PAGE_SIZE))
|
||||
|
||||
// Storage of FIDO2 resident keys
|
||||
#define RK_NUM_PAGES 10
|
||||
@ -32,8 +35,8 @@
|
||||
#define APPLICATION_START_ADDR (0x08000000 + ((APPLICATION_START_PAGE)*PAGE_SIZE))
|
||||
|
||||
// where attestation key is located
|
||||
#define ATTESTATION_KEY_PAGE (PAGES - 15)
|
||||
#define ATTESTATION_KEY_ADDR (0x08000000 + ATTESTATION_KEY_PAGE*PAGE_SIZE)
|
||||
#define ATTESTATION_PAGE (PAGES - 15)
|
||||
#define ATTESTATION_PAGE_ADDR (0x08000000 + ATTESTATION_PAGE*PAGE_SIZE)
|
||||
|
||||
// End of application code. Leave some extra room for future data storage.
|
||||
// NOT included in application
|
||||
@ -48,7 +51,6 @@
|
||||
#define BOOT_VERSION_ADDR (0x08000000 + BOOT_VERSION_PAGE*FLASH_PAGE_SIZE + 8)
|
||||
#define LAST_PAGE (APPLICATION_END_PAGE-1)
|
||||
|
||||
|
||||
struct flash_memory_st{
|
||||
uint8_t bootloader[APPLICATION_START_PAGE*2*1024];
|
||||
uint8_t application[(APPLICATION_END_PAGE-APPLICATION_START_PAGE)*2*1024-8];
|
||||
@ -65,5 +67,19 @@ typedef struct flash_memory_st flash_memory_st;
|
||||
#include <assert.h>
|
||||
static_assert(sizeof(flash_memory_st) == 256*1024, "Data structure doesn't match flash size");
|
||||
|
||||
#define ATTESTATION_CONFIGURED_TAG 0xaa551e78
|
||||
|
||||
struct flash_attestation_page{
|
||||
uint8_t attestation_key[32];
|
||||
// DWORD padded.
|
||||
uint64_t device_settings;
|
||||
uint64_t attestation_cert_size;
|
||||
uint8_t attestation_cert[2048 - 32 - 8 - 8];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct flash_attestation_page flash_attestation_page;
|
||||
|
||||
static_assert(sizeof(flash_attestation_page) == 2048, "Data structure doesn't match flash size");
|
||||
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user