Compare commits
32 Commits
move_certs
...
bump3.0.0
Author | SHA1 | Date | |
---|---|---|---|
873c514b2f | |||
21f3a0d10f | |||
b535b41d92 | |||
fd32cc0761 | |||
78dd2a10d3 | |||
fa1bb0dce5 | |||
169dfd2f0d | |||
dafd974d93 | |||
712fde6858 | |||
fcc2e86a6d | |||
8b146c4a16 | |||
a1a79b05fd | |||
c0df8b680d | |||
9ac2aa90c3 | |||
d33749fc16 | |||
96a2cbcb41 | |||
7212982385 | |||
89e218e561 | |||
666cd6a0ba | |||
b4f59ec355 | |||
b7d74cc99f | |||
375a607356 | |||
ea8409c072 | |||
04f06b3b0d | |||
a57c5170e1 | |||
aaffce4021 | |||
463a8b444d | |||
44ed3ceea5 | |||
30f73b41e4 | |||
6f6e831fba | |||
9fd608d3ee | |||
765dc27b15 |
@ -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
3
.gitignore
vendored
@ -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/
|
||||||
|
@ -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
|
||||||
|
61
Dockerfile
61
Dockerfile
@ -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
|
|
48
Makefile
48
Makefile
@ -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) black
|
$(MAKE) test-docker
|
||||||
|
$(MAKE) black
|
64
README.md
64
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.
|
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/>
|
||||||
|
|
||||||
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
||||||
[](#contributors)
|
[](#contributors)
|
||||||
[](https://travis-ci.com/solokeys/solo)
|
[](https://travis-ci.com/solokeys/solo)
|
||||||
[](https://discourse.solokeys.com)
|
[](https://discourse.solokeys.com)
|
||||||
[](https://keybase.io/team/solokeys.public)
|
[](https://keybase.io/team/solokeys.public)
|
||||||
|
@ -1 +1 @@
|
|||||||
2.5.3
|
3.0.0
|
||||||
|
@ -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
|
||||||
|
@ -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).
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -47,7 +47,7 @@ typedef enum
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
const uint8_t attestation_cert_der[];
|
const uint8_t * attestation_cert_der;
|
||||||
const uint16_t attestation_cert_der_size;
|
const uint16_t attestation_cert_der_size;
|
||||||
const uint8_t attestation_key[];
|
const uint8_t attestation_key[];
|
||||||
const uint16_t attestation_key_size;
|
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"
|
"\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"
|
"\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"
|
"\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"
|
"\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"
|
"\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";
|
"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7";
|
||||||
|
const uint8_t * attestation_cert_der = (const uint8_t *)_attestation_cert_der;
|
||||||
|
|
||||||
|
uint16_t attestation_cert_der_get_size(){
|
||||||
const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
|
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";
|
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);
|
void crypto_load_master_secret(uint8_t * key);
|
||||||
|
|
||||||
|
|
||||||
extern const uint8_t attestation_cert_der[];
|
extern const uint8_t * attestation_cert_der;
|
||||||
extern const uint16_t attestation_cert_der_size;
|
uint16_t attestation_cert_der_get_size();
|
||||||
|
|
||||||
extern const uint8_t attestation_key[];
|
|
||||||
extern const uint16_t attestation_key_size;
|
|
||||||
|
|
||||||
#endif
|
#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);
|
ret = cbor_encoder_create_array(&stmtmap, &x5carr, 1);
|
||||||
check_ret(ret);
|
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);
|
check_ret(ret);
|
||||||
ret = cbor_encoder_close_container(&stmtmap, &x5carr);
|
ret = cbor_encoder_close_container(&stmtmap, &x5carr);
|
||||||
check_ret(ret);
|
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);
|
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;
|
uint32_t param;
|
||||||
#endif
|
#endif
|
||||||
#if defined(IS_BOOTLOADER)
|
#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");
|
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);
|
||||||
ctaphid_write(wb, NULL, 0);
|
ctaphid_write(wb, NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
#if defined(SOLO_HACKER)
|
#if defined(SOLO)
|
||||||
case CTAPHID_ENTERBOOT:
|
case CTAPHID_ENTERBOOT:
|
||||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||||
boot_solo_bootloader();
|
boot_solo_bootloader();
|
||||||
wb->bcnt = 0;
|
wb->bcnt = 0;
|
||||||
ctaphid_write(wb, NULL, 0);
|
ctaphid_write(wb, NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
case CTAPHID_ENTERSTBOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
|
||||||
boot_st_bootloader();
|
|
||||||
return 1;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(IS_BOOTLOADER)
|
#if !defined(IS_BOOTLOADER)
|
||||||
@ -745,16 +742,21 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
|||||||
|
|
||||||
case CTAPHID_GETVERSION:
|
case CTAPHID_GETVERSION:
|
||||||
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
|
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
|
||||||
wb->bcnt = 3;
|
wb->bcnt = 4;
|
||||||
ctap_buffer[0] = SOLO_VERSION_MAJ;
|
ctap_buffer[0] = SOLO_VERSION_MAJ;
|
||||||
ctap_buffer[1] = SOLO_VERSION_MIN;
|
ctap_buffer[1] = SOLO_VERSION_MIN;
|
||||||
ctap_buffer[2] = SOLO_VERSION_PATCH;
|
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);
|
ctaphid_write(wb, NULL, 0);
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
#if !defined(IS_BOOTLOADER) && (defined(SOLO_EXPERIMENTAL))
|
||||||
case CTAPHID_LOADKEY:
|
case CTAPHID_LOADKEY:
|
||||||
/**
|
/**
|
||||||
* Load external key. Useful for enabling backups.
|
* 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;
|
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))
|
if ( ! ctap_user_presence_test(750))
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -64,4 +64,9 @@ int is_authorized_to_boot();
|
|||||||
int is_bootloader_disabled();
|
int is_bootloader_disabled();
|
||||||
void bootloader_heartbeat();
|
void bootloader_heartbeat();
|
||||||
|
|
||||||
|
// Return 1 if Solo is secure/locked.
|
||||||
|
int solo_is_locked();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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])')
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
#define SOLO
|
||||||
|
|
||||||
#define DEBUG_UART USART1
|
#define DEBUG_UART USART1
|
||||||
|
|
||||||
#ifndef DEBUG_LEVEL
|
#ifndef DEBUG_LEVEL
|
||||||
@ -46,6 +48,9 @@
|
|||||||
void printing_init();
|
void printing_init();
|
||||||
void hw_init(int lf);
|
void hw_init(int lf);
|
||||||
|
|
||||||
|
// Return 1 if Solo is secure/locked.
|
||||||
|
int solo_is_locked();
|
||||||
|
|
||||||
//#define TEST
|
//#define TEST
|
||||||
//#define TEST_POWER
|
//#define TEST_POWER
|
||||||
|
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
// copied, modified, or distributed except according to those terms.
|
// copied, modified, or distributed except according to those terms.
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "crypto.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"
|
"\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"
|
"\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"
|
"\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"
|
"\xf8\x84\xc3\x78\x35\x93\x63\x81\x2e\xbe\xa6\x12\x32\x6e\x29\x90\xc8\x91\x4b\x71"
|
||||||
"\x52"
|
"\x52"
|
||||||
;
|
;
|
||||||
#else
|
|
||||||
|
|
||||||
// For testing/development only
|
const uint8_t attestation_hacker_cert_der[] =
|
||||||
|
|
||||||
const uint8_t attestation_cert_der[] =
|
|
||||||
"\x30\x82\x02\xe9\x30\x82\x02\x8e\xa0\x03\x02\x01\x02\x02\x01\x01\x30\x0a\x06\x08"
|
"\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"
|
"\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"
|
"\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"
|
"\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)
|
void crypto_ecc256_load_attestation_key(void)
|
||||||
{
|
{
|
||||||
static uint8_t _key [32];
|
// static uint8_t _key [32];
|
||||||
memmove(_key, (uint8_t*)ATTESTATION_KEY_ADDR, 32);
|
flash_attestation_page * page =(flash_attestation_page *)ATTESTATION_PAGE_ADDR;
|
||||||
_signing_key = _key;
|
// memmove(_key, (uint8_t *)ATTESTATION_KEY_ADDR, 32);
|
||||||
|
_signing_key = page->attestation_key;
|
||||||
_key_len = 32;
|
_key_len = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#define LOW_FREQUENCY 1
|
#define LOW_FREQUENCY 1
|
||||||
#define HIGH_FREQUENCY 0
|
#define HIGH_FREQUENCY 0
|
||||||
|
|
||||||
|
#define SOLO_FLAG_LOCKED 0x2
|
||||||
|
|
||||||
void wait_for_usb_tether(void);
|
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[])
|
void device_init(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -219,6 +313,8 @@ void device_init(int argc, char *argv[])
|
|||||||
ctaphid_init();
|
ctaphid_init();
|
||||||
ctap_init();
|
ctap_init();
|
||||||
|
|
||||||
|
device_migrate();
|
||||||
|
|
||||||
#if BOOT_TO_DFU
|
#if BOOT_TO_DFU
|
||||||
flash_option_bytes_init(1);
|
flash_option_bytes_init(1);
|
||||||
#else
|
#else
|
||||||
|
@ -31,21 +31,18 @@ static void flash_unlock(void)
|
|||||||
// Locks flash and turns off DFU
|
// Locks flash and turns off DFU
|
||||||
void flash_option_bytes_init(int boot_from_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;
|
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)
|
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)
|
||||||
|
@ -17,8 +17,11 @@
|
|||||||
#define COUNTER1_PAGE (PAGES - 3)
|
#define COUNTER1_PAGE (PAGES - 3)
|
||||||
|
|
||||||
// State of FIDO2 application
|
// State of FIDO2 application
|
||||||
#define STATE2_PAGE (PAGES - 2)
|
#define STATE2_PAGE (PAGES - 2)
|
||||||
#define STATE1_PAGE (PAGES - 1)
|
#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
|
// Storage of FIDO2 resident keys
|
||||||
#define RK_NUM_PAGES 10
|
#define RK_NUM_PAGES 10
|
||||||
@ -32,8 +35,8 @@
|
|||||||
#define APPLICATION_START_ADDR (0x08000000 + ((APPLICATION_START_PAGE)*PAGE_SIZE))
|
#define APPLICATION_START_ADDR (0x08000000 + ((APPLICATION_START_PAGE)*PAGE_SIZE))
|
||||||
|
|
||||||
// where attestation key is located
|
// where attestation key is located
|
||||||
#define ATTESTATION_KEY_PAGE (PAGES - 15)
|
#define ATTESTATION_PAGE (PAGES - 15)
|
||||||
#define ATTESTATION_KEY_ADDR (0x08000000 + ATTESTATION_KEY_PAGE*PAGE_SIZE)
|
#define ATTESTATION_PAGE_ADDR (0x08000000 + ATTESTATION_PAGE*PAGE_SIZE)
|
||||||
|
|
||||||
// End of application code. Leave some extra room for future data storage.
|
// End of application code. Leave some extra room for future data storage.
|
||||||
// NOT included in application
|
// NOT included in application
|
||||||
@ -48,7 +51,6 @@
|
|||||||
#define BOOT_VERSION_ADDR (0x08000000 + BOOT_VERSION_PAGE*FLASH_PAGE_SIZE + 8)
|
#define BOOT_VERSION_ADDR (0x08000000 + BOOT_VERSION_PAGE*FLASH_PAGE_SIZE + 8)
|
||||||
#define LAST_PAGE (APPLICATION_END_PAGE-1)
|
#define LAST_PAGE (APPLICATION_END_PAGE-1)
|
||||||
|
|
||||||
|
|
||||||
struct flash_memory_st{
|
struct flash_memory_st{
|
||||||
uint8_t bootloader[APPLICATION_START_PAGE*2*1024];
|
uint8_t bootloader[APPLICATION_START_PAGE*2*1024];
|
||||||
uint8_t application[(APPLICATION_END_PAGE-APPLICATION_START_PAGE)*2*1024-8];
|
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>
|
#include <assert.h>
|
||||||
static_assert(sizeof(flash_memory_st) == 256*1024, "Data structure doesn't match flash size");
|
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
|
#endif
|
||||||
|
Reference in New Issue
Block a user