Compare commits
9 Commits
library_re
...
move_certs
Author | SHA1 | Date | |
---|---|---|---|
0873fa5f34 | |||
bb08f6e0d3 | |||
9fa2c97dc3 | |||
49ca42991c | |||
ef683bdc99 | |||
69478b4b6e | |||
9d5942ad10 | |||
446f1e0176 | |||
de2c1eff1b |
@ -197,27 +197,6 @@
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ccinelli",
|
||||
"name": "ccinelli",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/38021940?v=4",
|
||||
"profile": "https://github.com/ccinelli",
|
||||
"contributions": [
|
||||
"infra",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Nitrokey",
|
||||
"name": "Nitrokey",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/9438831?v=4",
|
||||
"profile": "https://www.nitrokey.com",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test",
|
||||
"ideas"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -34,8 +34,7 @@
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
targets/*/*.hex
|
||||
targets/*/*.sha2
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
|
@ -6,15 +6,14 @@ addons:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-8
|
||||
- gcc-7
|
||||
- cppcheck
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
|
||||
- sudo apt-get update -q
|
||||
- sudo apt-get install -y gcc-arm-embedded python3-venv
|
||||
- sudo apt-get install -y gcc-arm-embedded
|
||||
- sudo apt-get install -y python3-venv
|
||||
script:
|
||||
- export CC=gcc-8
|
||||
- export CC=gcc-7
|
||||
- pyenv shell 3.6.7
|
||||
- make travis
|
||||
|
61
Dockerfile
61
Dockerfile
@ -1,38 +1,33 @@
|
||||
FROM debian:9.11-slim
|
||||
FROM debian:stretch-slim
|
||||
MAINTAINER SoloKeys <hello@solokeys.com>
|
||||
|
||||
# Install necessary packages
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
make \
|
||||
wget \
|
||||
bzip2 \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -qq bzip2 git make wget >/dev/null
|
||||
|
||||
# Install ARM compiler
|
||||
RUN set -eux; \
|
||||
url="https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2019q3/RC1.1/gcc-arm-none-eabi-8-2019-q3-update-linux.tar.bz2?revision=c34d758a-be0c-476e-a2de-af8c6e16a8a2?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2019-q3-update"; \
|
||||
wget -O gcc.tar.bz2 "$url"; \
|
||||
echo "6341f11972dac8de185646d0fbd73bfc gcc.tar.bz2" | md5sum -c -; \
|
||||
echo "b50b02b0a16e5aad8620e9d7c31110ef285c1dde28980b1a9448b764d77d8f92 gcc.tar.bz2" | sha256sum -c -; \
|
||||
tar -C /opt -xf gcc.tar.bz2; \
|
||||
rm gcc.tar.bz2;
|
||||
# 1. ARM GCC: for compilation
|
||||
RUN wget -q -O gcc.tar.bz2 https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2?revision=d830f9dd-cd4f-406d-8672-cca9210dd220?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2018-q4-major
|
||||
# from website
|
||||
RUN echo "f55f90d483ddb3bcf4dae5882c2094cd gcc.tar.bz2" > gcc.md5
|
||||
RUN md5sum -c gcc.md5
|
||||
# self-generated
|
||||
RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.tar.bz2" > gcc.sha256
|
||||
RUN sha256sum -c gcc.sha256
|
||||
RUN tar -C /opt -xf gcc.tar.bz2
|
||||
|
||||
# Python3.7: for solo-python (merging etc.)
|
||||
RUN set -eux; \
|
||||
url="https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh"; \
|
||||
wget -O miniconda.sh "$url"; \
|
||||
echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" | md5sum -c -; \
|
||||
echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" | sha256sum -c -; \
|
||||
bash ./miniconda.sh -b -p /opt/conda; \
|
||||
ln -s /opt/conda/bin/python /usr/local/bin/python3; \
|
||||
ln -s /opt/conda/bin/python /usr/local/bin/python; \
|
||||
ln -s /opt/conda/bin/pip /usr/local/bin/pip3; \
|
||||
ln -s /opt/conda/bin/pip /usr/local/bin/pip; \
|
||||
rm miniconda.sh; \
|
||||
pip install -U pip
|
||||
# 2. Python3.7: for solo-python (merging etc.)
|
||||
RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh
|
||||
# from website
|
||||
RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5
|
||||
RUN md5sum -c miniconda.md5
|
||||
# self-generated
|
||||
RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a miniconda.sh" > miniconda.sha256
|
||||
RUN sha256sum -c miniconda.sha256
|
||||
|
||||
# solo-python (Python3.7 script for merging etc.)
|
||||
RUN pip install -U solo-python
|
||||
RUN bash ./miniconda.sh -b -p /opt/conda
|
||||
RUN ln -s /opt/conda/bin/python /usr/local/bin/python3
|
||||
RUN ln -s /opt/conda/bin/python /usr/local/bin/python
|
||||
RUN ln -s /opt/conda/bin/pip /usr/local/bin/pip3
|
||||
RUN ln -s /opt/conda/bin/pip /usr/local/bin/pip
|
||||
|
||||
# 3. Source code
|
||||
RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input
|
||||
|
87
Makefile
87
Makefile
@ -1,5 +1,3 @@
|
||||
include fido2/version.mk
|
||||
|
||||
#define uECC_arch_other 0
|
||||
#define uECC_x86 1
|
||||
#define uECC_x86_64 2
|
||||
@ -8,34 +6,44 @@ include fido2/version.mk
|
||||
#define uECC_arm_thumb2 5
|
||||
#define uECC_arm64 6
|
||||
#define uECC_avr 7
|
||||
|
||||
ecc_platform=2
|
||||
|
||||
src = pc/device.c pc/main.c
|
||||
src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard fido2/extensions/*.c) \
|
||||
$(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c
|
||||
|
||||
obj = $(src:.c=.o)
|
||||
obj = $(src:.c=.o) crypto/micro-ecc/uECC.o
|
||||
|
||||
LIBCBOR = tinycbor/lib/libtinycbor.a
|
||||
LIBSOLO = fido2/libsolo.a
|
||||
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
export LDFLAGS = -Wl,-dead_strip
|
||||
else
|
||||
export LDFLAGS = -Wl,--gc-sections
|
||||
endif
|
||||
LDFLAGS += $(LIBSOLO) $(LIBCBOR)
|
||||
LDFLAGS += $(LIBCBOR)
|
||||
|
||||
VERSION:=$(shell git describe --abbrev=0 )
|
||||
VERSION_FULL:=$(shell git describe)
|
||||
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
|
||||
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
|
||||
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
|
||||
|
||||
CFLAGS = -O2 -fdata-sections -ffunction-sections -g
|
||||
ECC_CFLAGS = -O2 -fdata-sections -ffunction-sections -DuECC_PLATFORM=$(ecc_platform)
|
||||
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
|
||||
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
|
||||
|
||||
INCLUDES = -I../ -I./fido2/ -I./pc -I../pc -I./tinycbor/src
|
||||
CFLAGS = -O2 -fdata-sections -ffunction-sections $(VERSION_FLAGS) -g
|
||||
|
||||
INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions
|
||||
INCLUDES += -I./crypto/cifra/src
|
||||
|
||||
CFLAGS += $(INCLUDES)
|
||||
CFLAGS += -DAES256=1 -DSOLO_EXPERIMENTAL=1 -DDEBUG_LEVEL=1
|
||||
# for crypto/tiny-AES-c
|
||||
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\" -DSOLO_EXPERIMENTAL=1
|
||||
|
||||
name = main
|
||||
|
||||
.PHONY: all $(LIBCBOR) $(LIBSOLO) black blackcheck cppcheck wink fido2-test clean full-clean travis test clean version
|
||||
.PHONY: all $(LIBCBOR) black blackcheck cppcheck wink fido2-test clean full-clean travis test clean version
|
||||
all: main
|
||||
|
||||
tinycbor/Makefile crypto/tiny-AES-c/aes.c:
|
||||
@ -45,10 +53,7 @@ tinycbor/Makefile crypto/tiny-AES-c/aes.c:
|
||||
cbor: $(LIBCBOR)
|
||||
|
||||
$(LIBCBOR):
|
||||
cd tinycbor/ && $(MAKE) LDFLAGS='' -j8
|
||||
|
||||
$(LIBSOLO):
|
||||
cd fido2/ && $(MAKE) CFLAGS="$(CFLAGS)" ECC_CFLAGS="$(ECC_CFLAGS)" APP_CONFIG=app.h -j8
|
||||
cd tinycbor/ && $(MAKE) clean && $(MAKE) LDFLAGS='' -j8
|
||||
|
||||
version:
|
||||
@git describe
|
||||
@ -57,13 +62,16 @@ test: venv
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C . main
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)" VERSION_FULL=${SOLO_VERSION_FULL}
|
||||
$(MAKE) -C ./targets/stm32l432 test PREFIX=$(PREFIX) "VENV=$(VENV)"
|
||||
$(MAKE) clean
|
||||
$(MAKE) cppcheck
|
||||
|
||||
$(name): $(obj) $(LIBCBOR) $(LIBSOLO)
|
||||
$(name): $(obj) $(LIBCBOR)
|
||||
$(CC) $(LDFLAGS) -o $@ $(obj) $(LDFLAGS)
|
||||
|
||||
crypto/micro-ecc/uECC.o: ./crypto/micro-ecc/uECC.c
|
||||
$(CC) -c -o $@ $^ -O2 -fdata-sections -ffunction-sections -DuECC_PLATFORM=$(ecc_platform) -I./crypto/micro-ecc/
|
||||
|
||||
venv:
|
||||
python3 -m venv venv
|
||||
venv/bin/pip -q install --upgrade pip
|
||||
@ -80,30 +88,18 @@ wink: venv
|
||||
fido2-test: venv
|
||||
venv/bin/python tools/ctap_test.py
|
||||
|
||||
update:
|
||||
git fetch --tags
|
||||
git checkout master
|
||||
git rebase origin/master
|
||||
git submodule update --init --recursive
|
||||
|
||||
DOCKER_TOOLCHAIN_IMAGE := "solokeys/solo-firmware-toolchain"
|
||||
|
||||
docker-build-toolchain:
|
||||
docker build -t $(DOCKER_TOOLCHAIN_IMAGE) .
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION}
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN}
|
||||
|
||||
uncached-docker-build-toolchain:
|
||||
docker build --no-cache -t $(DOCKER_TOOLCHAIN_IMAGE) .
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION}
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}
|
||||
docker tag $(DOCKER_TOOLCHAIN_IMAGE):latest $(DOCKER_TOOLCHAIN_IMAGE):${SOLO_VERSION_MAJ}.${SOLO_VERSION_MIN}
|
||||
|
||||
docker-build-all:
|
||||
DOCKER_IMAGE := "solokeys/solo-firmware:local"
|
||||
SOLO_VERSIONISH := "master"
|
||||
docker-build:
|
||||
docker build -t $(DOCKER_IMAGE) .
|
||||
docker run --rm -v "$(CURDIR)/builds:/builds" \
|
||||
-v "$(CURDIR):/solo" \
|
||||
$(DOCKER_TOOLCHAIN_IMAGE) "solo/in-docker-build.sh" ${SOLO_VERSION_FULL}
|
||||
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
|
||||
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
|
||||
uncached-docker-build:
|
||||
docker build --no-cache -t $(DOCKER_IMAGE) .
|
||||
docker run --rm -v "$(CURDIR)/builds:/builds" \
|
||||
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
|
||||
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
|
||||
|
||||
CPPCHECK_FLAGS=--quiet --error-exitcode=2
|
||||
|
||||
@ -120,19 +116,10 @@ clean:
|
||||
(cd `dirname $$f` ; git checkout -- .) ;\
|
||||
fi ;\
|
||||
done
|
||||
cd fido2 && $(MAKE) clean
|
||||
|
||||
full-clean: clean
|
||||
rm -rf venv
|
||||
|
||||
test-docker:
|
||||
rm -rf builds/*
|
||||
$(MAKE) uncached-docker-build-toolchain
|
||||
# Check if there are 4 docker images/tas named "solokeys/solo-firmware-toolchain"
|
||||
NTAGS=$$(docker images | grep -c "solokeys/solo-firmware-toolchain") && [ $$NTAGS -eq 4 ]
|
||||
$(MAKE) docker-build-all
|
||||
|
||||
travis:
|
||||
$(MAKE) test VENV=". ../../venv/bin/activate;"
|
||||
$(MAKE) test-docker
|
||||
$(MAKE) black
|
||||
$(MAKE) black
|
||||
|
69
README.md
69
README.md
@ -32,58 +32,10 @@ Check out [solokeys.com](https://solokeys.com), for options on where to buy Solo
|
||||
|
||||
If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We support Python3.
|
||||
|
||||
For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h#L48) and change `LED_INIT_VALUE`
|
||||
to be a different hex color.
|
||||
|
||||
Then recompile, load your new firmware, and enjoy a different LED color Solo.
|
||||
|
||||
In the Hacker version, hardware is the same but the firmware is unlocked, so you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently.
|
||||
|
||||
Hacker Solo isn't really secure so you should only use it for development. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
|
||||
|
||||
## Checking out the code
|
||||
```bash
|
||||
git clone --recurse-submodules https://github.com/solokeys/solo
|
||||
cd solo
|
||||
```
|
||||
|
||||
If you forgot the `--recurse-submodules` while cloning, simply run `git submodule update --init --recursive`.
|
||||
|
||||
`make update` will also checkout the latest code on `master` and submodules.
|
||||
|
||||
## Checking out the code to build a specific version
|
||||
|
||||
You can checkout the code to build a specific version of the firmware with:
|
||||
```
|
||||
VERSION_TO_BUILD=2.5.3
|
||||
git fetch --tags
|
||||
git checkout ${VERSION_TO_BUILD}
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
## Installing the toolchain
|
||||
|
||||
In order to compile ARM code, you need the ARM compiler and other things like bundling bootloader and firmware require the `solo-python` python package. Check our [documentation](https://docs.solokeys.io/solo/) for details
|
||||
|
||||
## Installing the toolkit and compiling in Docker
|
||||
Alternatively, you can use Docker to create a container with the toolchain.
|
||||
You can run:
|
||||
|
||||
```bash
|
||||
# Build the toolchain container
|
||||
make docker-build-toolchain
|
||||
|
||||
# Build all versions of the firmware in the "builds" folder
|
||||
make docker-build-all
|
||||
```
|
||||
|
||||
The `builds` folder will contain all the variation on the firmware in `.hex` files.
|
||||
|
||||
## Build locally
|
||||
|
||||
If you have the toolchain installed on your machine you can build the firmware with:
|
||||
|
||||
```bash
|
||||
cd targets/stm32l432
|
||||
make cbor
|
||||
make build-hacker
|
||||
@ -95,6 +47,19 @@ solo program aux enter-bootloader
|
||||
solo program bootloader targets/stm32l432/solo.hex
|
||||
```
|
||||
|
||||
Alternatively, run `make docker-build` and use the firmware generated in `/tmp`.
|
||||
|
||||
If you forgot the `--recurse-submodules` when cloning, simply `git submodule update --init --recursive`.
|
||||
|
||||
For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h#L48) and change `LED_INIT_VALUE`
|
||||
to be a different hex color.
|
||||
|
||||
Then recompile, load your new firmware, and enjoy a different LED color Solo.
|
||||
|
||||
In the Hacker version, hardware is the same but the firmware is unlocked, so you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently.
|
||||
|
||||
Hacker Solo isn't really secure so you should only use it for development. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
|
||||
|
||||
# Developing Solo (No Hardware Needed)
|
||||
|
||||
Clone Solo and build it
|
||||
@ -166,10 +131,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/jolo1581"><img src="https://avatars1.githubusercontent.com/u/53423977?v=4" width="100px;" alt="Jan A."/><br /><sub><b>Jan A.</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/ccinelli"><img src="https://avatars0.githubusercontent.com/u/38021940?v=4" width="100px;" alt="ccinelli"/><br /><sub><b>ccinelli</b></sub></a><br /><a href="#infra-ccinelli" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/solokeys/solo/commits?author=ccinelli" title="Tests">⚠️</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.nitrokey.com"><img src="https://avatars1.githubusercontent.com/u/9438831?v=4" width="100px;" alt="Nitrokey"/><br /><sub><b>Nitrokey</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=Nitrokey" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=Nitrokey" title="Tests">⚠️</a> <a href="#ideas-Nitrokey" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -186,7 +147,7 @@ You may use Solo software under the terms of either the Apache 2.0 license or MI
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
All hardware, unless otherwise noted, is dual licensed under CERN and CC-BY-SA.
|
||||
You may use Solo hardware under the terms of either the CERN 1.2 license or CC-BY-SA 4.0 license.
|
||||
You may use Solo hardware under the terms of either the CERN 2.1 license or CC-BY-SA 4.0 license.
|
||||
|
||||
All documentation, unless otherwise noted, is licensed under CC-BY-SA.
|
||||
You may use Solo documentation under the terms of the CC-BY-SA 4.0 license
|
||||
@ -203,7 +164,7 @@ You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solok
|
||||
<br/>
|
||||
|
||||
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
||||
[](#contributors)
|
||||
[](#contributors)
|
||||
[](https://travis-ci.com/solokeys/solo)
|
||||
[](https://discourse.solokeys.com)
|
||||
[](https://keybase.io/team/solokeys.public)
|
||||
|
@ -1 +1 @@
|
||||
3.0.0
|
||||
2.5.3
|
||||
|
@ -1,17 +1,16 @@
|
||||
# Booting into bootloader mode
|
||||
|
||||
If you have a recent version of Solo, you can put it into bootloader mode by running this command.
|
||||
You can put Solo into bootloader mode by holding down the button, and plugging in Solo. After 2 seconds, bootloader mode will activate.
|
||||
You'll see a yellowish flashing light and you can let go of the button.
|
||||
|
||||
Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
|
||||
|
||||
If Solo is running a hacker build, it can be put into bootloader mode on command. This makes it easier for development.
|
||||
|
||||
```bash
|
||||
solo program aux enter-bootloader
|
||||
```
|
||||
|
||||
If your Solo is a bit older (<=2.5.3) You can put Solo into bootloader mode by using the button method:
|
||||
Hold down button while plugging in Solo. After 2 seconds, bootloader mode will activate.
|
||||
You'll see a yellowish flashing light and you can let go of the button.
|
||||
|
||||
Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
|
||||
|
||||
# The boot stages of Solo
|
||||
|
||||
Solo has 3 boot stages.
|
||||
@ -22,8 +21,7 @@ The first stage is the DFU (Device Firmware Update) which is in a ROM on Solo.
|
||||
This is what allows the entire firmware of Solo to be programmed. **It's not recommended to develop for Solo using the DFU because
|
||||
if you program broken firmware, you could brick your device**.
|
||||
|
||||
On hacker/nonverifying-bootloader devices, you can boot into the DFU by holding down the button for 5 seconds,
|
||||
when Solo is already in bootloader mode.
|
||||
On hacker devices, you can boot into the DFU by holding down the button for 5 seconds, when Solo is already in bootloader mode.
|
||||
|
||||
You can also run this command when Solo is in bootloader mode to put it in DFU mode.
|
||||
|
||||
@ -31,7 +29,7 @@ You can also run this command when Solo is in bootloader mode to put it in DFU m
|
||||
solo program aux enter-dfu
|
||||
```
|
||||
|
||||
Note it will stay in DFU mode until you to tell it to boot again. You can boot it again by running the following.
|
||||
Note it will stay in DFU mode until to tell it to boot again. You can boot it again by running the following.
|
||||
|
||||
```bash
|
||||
solo program aux leave-dfu
|
||||
|
@ -36,21 +36,17 @@ Enter the `stm32l4xx` target directory.
|
||||
cd targets/stm32l432
|
||||
```
|
||||
|
||||
Now build the Solo application.
|
||||
Now build Solo.
|
||||
|
||||
```
|
||||
make firmware
|
||||
make build-hacker
|
||||
```
|
||||
|
||||
The `firmware` recipe builds the solo application, and outputs `solo.hex`. You can use this
|
||||
to reprogram any unlocked/hacker Solo model. Note that it does not include the Solo bootloader,
|
||||
so it is not a full reprogram.
|
||||
|
||||
<!-- First it builds the bootloader, with
|
||||
The `build-hacker` recipe does a few things. First it builds the bootloader, with
|
||||
signature checking disabled. Then it builds the Solo application with "hacker" features
|
||||
enabled, like being able to jump to the bootloader on command. It then merges bootloader
|
||||
and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex`
|
||||
into `all.hex`. -->
|
||||
into `all.hex`.
|
||||
|
||||
If you're just planning to do development, **please don't try to reprogram the bootloader**,
|
||||
as this can be risky if done often. Just use `solo.hex`.
|
||||
@ -61,13 +57,13 @@ If you're developing, you probably want to see debug messages! Solo has a USB
|
||||
Serial port that it will send debug messages through (from `printf`). You can read them using
|
||||
a normal serial terminal like `picocom` or `putty`.
|
||||
|
||||
Just add `-debug-1` or `-debug-2` to your build recipe, like this.
|
||||
Just add `DEBUG=1` or `DEBUG=2` to your build recipe, like this.
|
||||
|
||||
```
|
||||
make firmware-debug-1
|
||||
make build-hacker DEBUG=1
|
||||
```
|
||||
|
||||
If you use `debug-2`, that means Solo will not boot until something starts reading
|
||||
If you use `DEBUG=2`, that means Solo will not boot until something starts reading
|
||||
its debug messages. So it basically waits to tether to a serial terminal so that you don't
|
||||
miss any debug messages.
|
||||
|
||||
@ -82,45 +78,27 @@ solo monitor <serial-port>
|
||||
|
||||
[See issue 62](https://github.com/solokeys/solo/issues/62).
|
||||
|
||||
### Building a complete Solo build (application + bootloader + certificate)
|
||||
### Building a Solo release
|
||||
|
||||
To make a complete Solo build, you need to build the bootloader. We provide
|
||||
two easy recipes:
|
||||
To build Solo
|
||||
|
||||
* `bootloader-nonverifying`: bootloader with no signature checking on updates. I.e. "unlocked".
|
||||
* `bootloader-verifying`: bootloader with signature checking enforced on updated. I.e. "Locked".
|
||||
If you want to build a release of Solo, we recommend trying a Hacker build first
|
||||
just to make sure that it's working. Otherwise it may not be as easy or possible to
|
||||
fix any mistakes.
|
||||
|
||||
To be safe, let's use the `-nonverifying` build.
|
||||
If you're ready to program a full release, run this recipe to build.
|
||||
|
||||
```
|
||||
make bootloader-nonverifying
|
||||
make build-release-locked
|
||||
```
|
||||
|
||||
This outputs `bootloader.hex`. We can then merge the bootloader and application.
|
||||
This outputs bootloader.hex, solo.hex, and the combined all.hex.
|
||||
|
||||
```
|
||||
solo mergehex bootloader.hex solo.hex bundle.hex
|
||||
```
|
||||
Programming `all.hex` will cause the device to permanently lock itself. This means debuggers cannot be used and signature checking
|
||||
will be enforced on all future updates.
|
||||
|
||||
`bundle.hex` is our complete firmware build. Note it is in this step that you can
|
||||
include a custom attestation certificate or lock the device from debugging/DFU.
|
||||
By default the "hacker" attestation certifcate and key is used.
|
||||
|
||||
```
|
||||
solo mergehex \
|
||||
--attestation-key "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" \
|
||||
--attestation-cert attestation.der \
|
||||
--lock \
|
||||
solo.hex \
|
||||
bootloader.hex \
|
||||
bundle.hex
|
||||
```
|
||||
|
||||
See [here for more information on custom attestation](/solo/customization/).
|
||||
|
||||
If you use `--lock`, this will permanently lock the device to this new bootloader. You
|
||||
won't be able to program the bootloader again or be able to connect a hardware debugger.
|
||||
The new bootloader may be able to accept (signed) updates still, depending on how you configured it.
|
||||
|
||||
To learn more about normal updates or a "full" update, you should [read more on Solo's boot stages](/solo/bootloader-mode).
|
||||
Note if you program a secured `solo.hex` file onto a Solo Hacker, it will lock the flash, but the bootloader
|
||||
will still accept unsigned firmware updates. So you can switch it back to being a hacker, but you will
|
||||
not be able to replace the unlocked bootloader anymore, since the permanently locked flash also disables the DFU.
|
||||
[Read more on Solo's boot stages](/solo/bootloader-mode).
|
||||
|
||||
|
@ -114,27 +114,28 @@ If the checks succeed, you are ready to program the device attestation key and c
|
||||
|
||||
### Programming an attestation key and certificate
|
||||
|
||||
First, [Build your solo application and bootloader](/solo/building).
|
||||
Convert the DER format of the device attestation certificate to "C" bytes using our utility script. You may first need to
|
||||
first install prerequisite python modules (`pip install -r tools/requirements.txt`).
|
||||
|
||||
Print your attestation key in a hex string format. Using our utility script:
|
||||
```
|
||||
python tools/gencert/cbytes.py device_cert.der
|
||||
```
|
||||
|
||||
Copy the byte string portion into the [`attestation.c` source file of Solo](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/attestation.c). Overwrite the development or "default" certificate that is already there.
|
||||
|
||||
Now [build the Solo firmware](/solo/building), either a secure or hacker build. You will need to produce a `bootloader.hex` file and a `solo.hex` file.
|
||||
|
||||
Print your attestation key in a hex string format.
|
||||
|
||||
```
|
||||
python tools/print_x_y.py device_key.pem
|
||||
```
|
||||
|
||||
Merge the `bootloader.hex`, `solo.hex`, attestion key, and certificate into one firmware file.
|
||||
Merge the `bootloader.hex`, `solo.hex`, and attestion key into one firmware file.
|
||||
|
||||
```
|
||||
solo mergehex \
|
||||
--attestation-key "(The 32-byte hex string extracted from device_key.pem)" \
|
||||
--attestation-cert device_cert.der \
|
||||
--lock \
|
||||
solo.hex \
|
||||
bootloader.hex \
|
||||
bundle.hex
|
||||
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex
|
||||
```
|
||||
|
||||
Now you have a newly created `bundle.hex` file with a custom attestation key and cert. You can [program this `bundle.hex` file
|
||||
Now you have a newly create `all.hex` file with a custom attestation key. You can [program this `all.hex` file
|
||||
with Solo in DFU mode](/solo/programming#procedure).
|
||||
|
||||
Are you interested in customizing in bulk? Contact hello@solokeys.com and we can help.
|
||||
|
@ -1,60 +0,0 @@
|
||||
# Usage and Porting
|
||||
|
||||
Solo is designed to be used as a library or ported to other platforms easily. Here is an example
|
||||
`main()` function.
|
||||
|
||||
```c
|
||||
int main()
|
||||
{
|
||||
uint8_t hidmsg[64];
|
||||
uint32_t t1 = 0;
|
||||
|
||||
device_init();
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
ctaphid_handle_packet(hidmsg); // pass into libsolo!
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
}
|
||||
|
||||
|
||||
ctaphid_check_timeouts();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
`ctaphid_handle_packet(hidmsg);` is the entrance into the HID layer of libsolo, and will buffer packets and pass them
|
||||
into FIDO2 or U2F layers.
|
||||
|
||||
Everything in the library is cross-platform, but it needs some functions implemented that are usually
|
||||
platform specific. For example, how should libsolo implement an atomic counter? Where should it save state?
|
||||
For all of these platform specific functions, the library contains it's own `weak` definition, so the library will compile and run.
|
||||
LibSolo by default will not try to use an atomic
|
||||
counter or save data persistently -- that needs to be implemented externally.
|
||||
|
||||
If you are using libsolo on another platform,
|
||||
you should take a look at these possibly platform specific functions. They are listed in `fido2/device.h`.
|
||||
If you'd like to reimplement any of the functions, then simply implement the function and compile normally.
|
||||
GCC will replace libsolo's `weak` defined functions (everything in `fido2/device.h`) with your functions. By doing this, you
|
||||
are replacing the function that is used by libsolo.
|
||||
|
||||
To get the library to compile
|
||||
and run, you only need to implement one function for libsolo: `usbhid_send(uint8_t * send)`, which
|
||||
is called by the library to send a 64 byte packet over a USB HID endpoint. In essence, you are giving
|
||||
libsolo a function to write to USB.
|
||||
|
||||
The rest of the definitions in `fido2/device.h` are not required to compile and run so you can
|
||||
immediately hit the ground running and iterative add what else you need. You'll definitely want
|
||||
to continue implementing other functions in `fido2/device.h`. For example, no data will be stored
|
||||
persistently until you define how it can be done!
|
||||
|
||||
For examples, check out the build for STM32L4 and PC (check out `pc/device` and `targets/stm32l432/src/device.c`).
|
||||
|
||||
If there's something that doesn't work for you -- send a pull request! It's better if we can
|
||||
work together off of the same repo and not fork.
|
@ -22,11 +22,12 @@ solo key update <--secure | --hacker>
|
||||
You can manually install the [latest release](https://github.com/solokeys/solo/releases), or use a build that you made.
|
||||
|
||||
```bash
|
||||
# If it's a hacker, it will automatically boot into bootloader mode.
|
||||
solo program bootloader <firmware.hex | firmware.json>
|
||||
```
|
||||
|
||||
Note you won't be able to use `all.hex` or the `bundle-*.hex` builds, as these include the solo bootloader. You shouldn't
|
||||
risk changing the Solo bootloader unless you want to make it a secure device, or [make other customizations](/solo/customization/).
|
||||
risk changing the Solo bootloader unless you want to make it a secure device, or [make other customizations]().
|
||||
|
||||
## Updating a Hacker to a Secure Solo
|
||||
|
||||
@ -37,14 +38,14 @@ You can use a firmware build from the [latest release](https://github.com/soloke
|
||||
a build that you made yourself.
|
||||
|
||||
You need to use a firmware file that has the combined bootloader and application (or at the very least just the bootloader).
|
||||
This means using the `bundle-*.hex` file or the `bundle.hex` from your build. If you overwrite the Solo flash with a missing bootloader,
|
||||
This means using the `bundle-*.hex` file or the `all.hex` from your build. If you overwrite the Solo flash with a missing bootloader,
|
||||
it will be bricked.
|
||||
|
||||
We provide two types of bundled builds. The `bundle-hacker-*.hex` build is the hacker build. If you update with this,
|
||||
you will update the bootloader and application, but nothing will be secured. The `bundle-secure-non-solokeys.hex`
|
||||
is a secured build that will lock your device and it will behave just like a Secure Solo. The main difference is that
|
||||
it uses a "default" attestation key in the device, rather than the SoloKeys attestation key. There is no security
|
||||
concern with using our default attestation key, aside from a small privacy implication that services can distinguish it from Solo Secure.
|
||||
concern with using our default attestation key, aside from a privacy implication that services can distinguish it from Solo Secure.
|
||||
|
||||
### Procedure
|
||||
|
||||
@ -60,7 +61,7 @@ concern with using our default attestation key, aside from a small privacy impli
|
||||
|
||||
2. Program the device
|
||||
|
||||
solo program dfu <bundle-secure-non-solokeys.hex | bundle.hex>
|
||||
solo program dfu <bundle-secure-non-solokeys.hex | all.hex>
|
||||
|
||||
Double check you programmed it with bootloader + application (or just bootloader).
|
||||
If you messed it up, simply don't do the next step and repeat this step correctly.
|
||||
|
@ -1,44 +0,0 @@
|
||||
include version.mk
|
||||
|
||||
ifndef APP_CONFIG
|
||||
APP_CONFIG=example_app.h
|
||||
endif
|
||||
|
||||
INC = -I./ -I./extensions
|
||||
INC += -I../tinycbor/src
|
||||
INC += -I../crypto/sha256 -I../crypto/micro-ecc -I../crypto/tiny-AES-c
|
||||
INC += -I../crypto/cifra/src -I../crypto/cifra/src/ext
|
||||
|
||||
INT_CFLAGS = -DAPP_CONFIG=\"$(APP_CONFIG)\"
|
||||
INT_CFLAGS += $(INC)
|
||||
INT_CFLAGS += $(SOLO_VERSION_FLAGS)
|
||||
|
||||
SRC = apdu.c util.c u2f.c test_power.c
|
||||
SRC += stubs.c log.c ctaphid.c ctap.c
|
||||
SRC += ctap_parse.c crypto.c
|
||||
SRC += device.c
|
||||
SRC += version.c
|
||||
SRC += data_migration.c
|
||||
SRC += extensions/extensions.c extensions/solo.c
|
||||
SRC += extensions/wallet.c
|
||||
|
||||
# Crypto libs
|
||||
SRC += ../crypto/sha256/sha256.c ../crypto/micro-ecc/uECC.c ../crypto/tiny-AES-c/aes.c
|
||||
SRC += ../crypto/cifra/src/sha512.c ../crypto/cifra/src/blockwise.c
|
||||
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
all: libsolo.a
|
||||
|
||||
libsolo.a: $(OBJ)
|
||||
$(AR) cqs $@ $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $^ $(INT_CFLAGS) $(CFLAGS) -c -o $@
|
||||
|
||||
../crypto/micro-ecc/uECC.o: ../crypto/micro-ecc/uECC.c
|
||||
$(CC) $^ $(INT_CFLAGS) $(ECC_CFLAGS) -c -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) libsolo.a
|
||||
|
151
fido2/crypto.c
151
fido2/crypto.c
@ -5,33 +5,29 @@
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
/*
|
||||
* Wrapper for crypto implementation on device.
|
||||
*
|
||||
* Can be replaced with different crypto implementation by
|
||||
* defining EXTERNAL_SOLO_CRYPTO
|
||||
* Wrapper for crypto implementation on device
|
||||
*
|
||||
* */
|
||||
#ifndef EXTERNAL_SOLO_CRYPTO
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
#include "util.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef USE_SOFTWARE_IMPLEMENTATION
|
||||
|
||||
#include "sha256.h"
|
||||
#include "uECC.h"
|
||||
#include "aes.h"
|
||||
#include "ctap.h"
|
||||
#include "device.h"
|
||||
// stuff for SHA512
|
||||
#include "sha2.h"
|
||||
#include "blockwise.h"
|
||||
#include APP_CONFIG
|
||||
#include "log.h"
|
||||
#include APP_CONFIG
|
||||
|
||||
|
||||
#ifdef USING_PC
|
||||
typedef enum
|
||||
{
|
||||
MBEDTLS_ECP_DP_NONE = 0,
|
||||
@ -48,56 +44,53 @@ typedef enum
|
||||
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
|
||||
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
|
||||
} mbedtls_ecp_group_id;
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t * attestation_cert_der;
|
||||
const uint16_t attestation_cert_der_size;
|
||||
const uint8_t attestation_key[];
|
||||
const uint16_t attestation_key_size;
|
||||
|
||||
|
||||
|
||||
static SHA256_CTX sha256_ctx;
|
||||
static cf_sha512_context sha512_ctx;
|
||||
static const struct uECC_Curve_t * _es256_curve = NULL;
|
||||
static const uint8_t * _signing_key = NULL;
|
||||
static int _key_len = 0;
|
||||
|
||||
// Secrets for testing only
|
||||
static uint8_t master_secret[64];
|
||||
|
||||
static uint8_t transport_secret[32];
|
||||
|
||||
|
||||
void crypto_sha256_init(void)
|
||||
|
||||
void crypto_sha256_init()
|
||||
{
|
||||
sha256_init(&sha256_ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_init(void)
|
||||
void crypto_reset_master_secret()
|
||||
{
|
||||
cf_sha512_init(&sha512_ctx);
|
||||
}
|
||||
|
||||
void crypto_load_master_secret(uint8_t * key)
|
||||
{
|
||||
#if KEY_SPACE_BYTES < 96
|
||||
#error "need more key bytes"
|
||||
#endif
|
||||
memmove(master_secret, key, 64);
|
||||
memmove(transport_secret, key+64, 32);
|
||||
}
|
||||
|
||||
void crypto_reset_master_secret(void)
|
||||
{
|
||||
memset(master_secret, 0, 64);
|
||||
memset(transport_secret, 0, 32);
|
||||
ctap_generate_rng(master_secret, 64);
|
||||
ctap_generate_rng(transport_secret, 32);
|
||||
}
|
||||
|
||||
void crypto_load_master_secret(uint8_t * key)
|
||||
{
|
||||
#if KEY_SPACE_BYTES < 96
|
||||
#error "need more key bytes"
|
||||
#endif
|
||||
memmove(master_secret, key, 64);
|
||||
memmove(transport_secret, key+64, 32);
|
||||
}
|
||||
|
||||
void crypto_sha256_update(uint8_t * data, size_t len)
|
||||
{
|
||||
sha256_update(&sha256_ctx, data, len);
|
||||
}
|
||||
|
||||
void crypto_sha512_update(const uint8_t * data, size_t len) {
|
||||
cf_sha512_update(&sha512_ctx, data, len);
|
||||
}
|
||||
|
||||
void crypto_sha256_update_secret()
|
||||
{
|
||||
sha256_update(&sha256_ctx, master_secret, 32);
|
||||
@ -108,32 +101,26 @@ void crypto_sha256_final(uint8_t * hash)
|
||||
sha256_final(&sha256_ctx, hash);
|
||||
}
|
||||
|
||||
void crypto_sha512_final(uint8_t * hash)
|
||||
{
|
||||
// NB: there is also cf_sha512_digest
|
||||
cf_sha512_digest_final(&sha512_ctx, hash);
|
||||
}
|
||||
|
||||
void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
unsigned int i;
|
||||
int i;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (key == CRYPTO_MASTER_KEY)
|
||||
{
|
||||
key = master_secret;
|
||||
klen = sizeof(master_secret)/2;
|
||||
klen = sizeof(master_secret);
|
||||
}
|
||||
else if (key == CRYPTO_TRANSPORT_KEY)
|
||||
{
|
||||
key = transport_secret;
|
||||
klen = 32;
|
||||
}
|
||||
|
||||
|
||||
if(klen > 64)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||
printf2(TAG_ERR,"Error, key size must be <= 64\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -151,24 +138,19 @@ void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
unsigned int i;
|
||||
int i;
|
||||
crypto_sha256_final(hmac);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (key == CRYPTO_MASTER_KEY)
|
||||
{
|
||||
key = master_secret;
|
||||
klen = sizeof(master_secret)/2;
|
||||
}
|
||||
else if (key == CRYPTO_TRANSPORT_KEY2)
|
||||
{
|
||||
key = transport_secret;
|
||||
klen = 32;
|
||||
klen = sizeof(master_secret);
|
||||
}
|
||||
|
||||
|
||||
if(klen > 64)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||
printf2(TAG_ERR,"Error, key size must be <= 64\n");
|
||||
exit(1);
|
||||
}
|
||||
memmove(buf, key, klen);
|
||||
@ -185,16 +167,16 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
}
|
||||
|
||||
|
||||
void crypto_ecc256_init(void)
|
||||
void crypto_ecc256_init()
|
||||
{
|
||||
uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
|
||||
_es256_curve = uECC_secp256r1();
|
||||
}
|
||||
|
||||
|
||||
void crypto_ecc256_load_attestation_key(void)
|
||||
void crypto_ecc256_load_attestation_key()
|
||||
{
|
||||
_signing_key = device_get_attestation_key();
|
||||
_signing_key = attestation_key;
|
||||
_key_len = 32;
|
||||
}
|
||||
|
||||
@ -202,7 +184,7 @@ void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
||||
{
|
||||
if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
|
||||
{
|
||||
printf2(TAG_ERR, "error, uECC failed\n");
|
||||
printf2(TAG_ERR,"error, uECC failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -239,19 +221,19 @@ void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_I
|
||||
if (_key_len != 32) goto fail;
|
||||
break;
|
||||
default:
|
||||
printf2(TAG_ERR, "error, invalid ECDSA alg specifier\n");
|
||||
printf2(TAG_ERR,"error, invalid ECDSA alg specifier\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( uECC_sign(_signing_key, data, len, sig, curve) == 0)
|
||||
{
|
||||
printf2(TAG_ERR, "error, uECC failed\n");
|
||||
printf2(TAG_ERR,"error, uECC failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
printf2(TAG_ERR, "error, invalid key length\n");
|
||||
printf2(TAG_ERR,"error, invalid key length\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@ -261,11 +243,8 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
|
||||
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
|
||||
crypto_sha256_update(data, len);
|
||||
crypto_sha256_update(data2, len2);
|
||||
crypto_sha256_update(master_secret, 32); // TODO AES
|
||||
crypto_sha256_update(master_secret, 32);
|
||||
crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
|
||||
|
||||
crypto_aes256_init(master_secret + 32, NULL);
|
||||
crypto_aes256_encrypt(privkey, 32);
|
||||
}
|
||||
|
||||
|
||||
@ -282,12 +261,12 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
|
||||
memmove(x,pubkey,32);
|
||||
memmove(y,pubkey+32,32);
|
||||
}
|
||||
|
||||
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
|
||||
{
|
||||
uECC_compute_public_key(privkey, pubkey, _es256_curve);
|
||||
}
|
||||
|
||||
|
||||
void crypto_load_external_key(uint8_t * key, int len)
|
||||
{
|
||||
_signing_key = key;
|
||||
@ -299,7 +278,7 @@ void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
|
||||
{
|
||||
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, uECC_make_key failed\n");
|
||||
printf2(TAG_ERR,"Error, uECC_make_key failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -308,7 +287,7 @@ void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey
|
||||
{
|
||||
if (uECC_shared_secret(pubkey, privkey, shared_secret, _es256_curve) != 1)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, uECC_shared_secret failed\n");
|
||||
printf2(TAG_ERR,"Error, uECC_shared_secret failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -359,4 +338,44 @@ void crypto_aes256_encrypt(uint8_t * buf, int length)
|
||||
}
|
||||
|
||||
|
||||
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"
|
||||
"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38"
|
||||
"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32"
|
||||
"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\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\x0f\x30\x0d"
|
||||
"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55"
|
||||
"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20"
|
||||
"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72"
|
||||
"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04"
|
||||
"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07"
|
||||
"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00"
|
||||
"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf"
|
||||
"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83"
|
||||
"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca"
|
||||
"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d"
|
||||
"\xa1\x30\xa4\x2e\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\x06\x03\x55\x04"
|
||||
"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94"
|
||||
"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04"
|
||||
"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
|
||||
"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e"
|
||||
"\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;
|
||||
|
||||
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";
|
||||
const uint16_t attestation_key_size = sizeof(attestation_key)-1;
|
||||
|
||||
|
||||
#else
|
||||
#error "No crypto implementation defined"
|
||||
#endif
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define USE_SOFTWARE_IMPLEMENTATION
|
||||
|
||||
void crypto_sha256_init();
|
||||
void crypto_sha256_update(uint8_t * data, size_t len);
|
||||
void crypto_sha256_update_secret();
|
||||
@ -21,6 +23,7 @@ void crypto_sha512_init();
|
||||
void crypto_sha512_update(const uint8_t * data, size_t len);
|
||||
void crypto_sha512_final(uint8_t * hash);
|
||||
|
||||
|
||||
void crypto_ecc256_init();
|
||||
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y);
|
||||
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey);
|
||||
@ -51,4 +54,7 @@ void crypto_reset_master_secret();
|
||||
void crypto_load_master_secret(uint8_t * key);
|
||||
|
||||
|
||||
extern const uint8_t * attestation_cert_der;
|
||||
uint16_t attestation_cert_der_get_size();
|
||||
|
||||
#endif
|
||||
|
50
fido2/ctap.c
50
fido2/ctap.c
@ -282,9 +282,13 @@ void make_auth_tag(uint8_t * rpIdHash, uint8_t * nonce, uint32_t count, uint8_t
|
||||
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
|
||||
}
|
||||
|
||||
void ctap_flush_state()
|
||||
void ctap_flush_state(int backup)
|
||||
{
|
||||
authenticator_write_state(&STATE);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
if (backup)
|
||||
{
|
||||
authenticator_write_state(&STATE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t auth_data_update_count(CTAP_authDataHeader * authData)
|
||||
@ -308,7 +312,7 @@ static uint32_t auth_data_update_count(CTAP_authDataHeader * authData)
|
||||
static void ctap_increment_rk_store()
|
||||
{
|
||||
STATE.rk_stored++;
|
||||
ctap_flush_state();
|
||||
ctap_flush_state(1);
|
||||
}
|
||||
|
||||
static int is_matching_rk(CTAP_residentKey * rk, CTAP_residentKey * rk2)
|
||||
@ -657,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, device_attestation_cert_der_get_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);
|
||||
@ -1766,7 +1770,8 @@ static void ctap_state_init()
|
||||
*/
|
||||
void ctap_load_external_keys(uint8_t * keybytes){
|
||||
memmove(STATE.key_space, keybytes, KEY_SPACE_BYTES);
|
||||
authenticator_write_state(&STATE);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
authenticator_write_state(&STATE, 1);
|
||||
crypto_load_master_secret(STATE.key_space);
|
||||
}
|
||||
|
||||
@ -1780,18 +1785,30 @@ void ctap_init()
|
||||
);
|
||||
crypto_ecc256_init();
|
||||
|
||||
int is_init = authenticator_read_state(&STATE);
|
||||
authenticator_read_state(&STATE);
|
||||
|
||||
device_set_status(CTAPHID_STATUS_IDLE);
|
||||
|
||||
if (is_init)
|
||||
if (STATE.is_initialized == INITIALIZED_MARKER)
|
||||
{
|
||||
printf1(TAG_STOR,"Auth state is initialized\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ctap_state_init();
|
||||
authenticator_write_state(&STATE);
|
||||
printf1(TAG_STOR,"Auth state is NOT initialized. Initializing..\n");
|
||||
if (authenticator_is_backup_initialized())
|
||||
{
|
||||
printf1(TAG_ERR,"Warning: memory corruption detected. restoring from backup..\n");
|
||||
authenticator_read_backup_state(&STATE);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctap_state_init();
|
||||
authenticator_write_state(&STATE, 0);
|
||||
authenticator_write_state(&STATE, 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
do_migration_if_required(&STATE);
|
||||
@ -1858,7 +1875,8 @@ void ctap_update_pin(uint8_t * pin, int len)
|
||||
|
||||
STATE.is_pin_set = 1;
|
||||
|
||||
authenticator_write_state(&STATE);
|
||||
authenticator_write_state(&STATE, 1);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
|
||||
printf1(TAG_CTAP, "New pin set: %s [%d]\n", pin, len);
|
||||
dump_hex1(TAG_ERR, STATE.PIN_CODE_HASH, sizeof(STATE.PIN_CODE_HASH));
|
||||
@ -1873,7 +1891,7 @@ uint8_t ctap_decrement_pin_attempts()
|
||||
if (! ctap_device_locked())
|
||||
{
|
||||
STATE.remaining_tries--;
|
||||
ctap_flush_state();
|
||||
ctap_flush_state(0);
|
||||
printf1(TAG_CP, "ATTEMPTS left: %d\n", STATE.remaining_tries);
|
||||
|
||||
if (ctap_device_locked())
|
||||
@ -1908,7 +1926,7 @@ void ctap_reset_pin_attempts()
|
||||
{
|
||||
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||
PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||
ctap_flush_state();
|
||||
ctap_flush_state(0);
|
||||
}
|
||||
|
||||
void ctap_reset_state()
|
||||
@ -1982,7 +2000,7 @@ int8_t ctap_store_key(uint8_t index, uint8_t * key, uint16_t len)
|
||||
|
||||
memmove(STATE.key_space + offset, key, len);
|
||||
|
||||
ctap_flush_state();
|
||||
ctap_flush_state(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2024,7 +2042,8 @@ void ctap_reset()
|
||||
{
|
||||
ctap_state_init();
|
||||
|
||||
authenticator_write_state(&STATE);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
authenticator_write_state(&STATE, 1);
|
||||
|
||||
if (ctap_generate_rng(PIN_TOKEN, PIN_TOKEN_SIZE) != 1)
|
||||
{
|
||||
@ -2044,5 +2063,6 @@ void lock_device_permanently() {
|
||||
|
||||
printf1(TAG_CP, "Device locked!\n");
|
||||
|
||||
authenticator_write_state(&STATE);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
authenticator_write_state(&STATE, 1);
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ static void ctaphid_write(CTAPHID_WRITE_BUFFER * wb, void * _data, int len)
|
||||
if (wb->offset > 0)
|
||||
{
|
||||
memset(wb->buf + wb->offset, 0, HID_MESSAGE_SIZE - wb->offset);
|
||||
usbhid_send(wb->buf);
|
||||
ctaphid_write_block(wb->buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -304,7 +304,7 @@ static void ctaphid_write(CTAPHID_WRITE_BUFFER * wb, void * _data, int len)
|
||||
wb->bytes_written += 1;
|
||||
if (wb->offset == HID_MESSAGE_SIZE)
|
||||
{
|
||||
usbhid_send(wb->buf);
|
||||
ctaphid_write_block(wb->buf);
|
||||
wb->offset = 0;
|
||||
}
|
||||
}
|
||||
@ -710,7 +710,6 @@ uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE
|
||||
printf1(TAG_HID,"CTAPHID_BOOT\n");
|
||||
u2f_set_writeback_buffer(ctap_resp);
|
||||
is_busy = bootloader_bridge(len, ctap_buffer);
|
||||
wb->bcnt = 1 + ctap_resp->length;
|
||||
|
||||
ctaphid_write(wb, &is_busy, 1);
|
||||
ctaphid_write(wb, ctap_resp->data, ctap_resp->length);
|
||||
|
@ -59,8 +59,6 @@
|
||||
|
||||
#define CTAP_CAPABILITIES (CAPABILITY_WINK | CAPABILITY_CBOR)
|
||||
|
||||
#define HID_MESSAGE_SIZE 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cid;
|
||||
|
@ -56,7 +56,8 @@ bool migrate_from_FF_to_01(AuthenticatorState_0xFF* state_prev_0xff, Authenticat
|
||||
|
||||
void save_migrated_state(AuthenticatorState *state_tmp_ptr) {
|
||||
memmove(&STATE, state_tmp_ptr, sizeof(AuthenticatorState));
|
||||
authenticator_write_state(state_tmp_ptr);
|
||||
authenticator_write_state(state_tmp_ptr, 0);
|
||||
authenticator_write_state(state_tmp_ptr, 1);
|
||||
}
|
||||
|
||||
void do_migration_if_required(AuthenticatorState* state_current){
|
||||
|
201
fido2/device.c
201
fido2/device.c
@ -1,201 +0,0 @@
|
||||
// Copyright 2019 SoloKeys Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
/** device.c
|
||||
*
|
||||
* This contains (weak) implementations
|
||||
* to get FIDO2 working initially on a device. They probably
|
||||
* aren't what you want to keep, but are designed to be replaced
|
||||
* with some other platform specific implementation.
|
||||
*
|
||||
* For real examples, see the STM32L4 implementation and the PC implementation of device.c.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ctaphid.h"
|
||||
#include "log.h"
|
||||
#include APP_CONFIG
|
||||
|
||||
#define RK_NUM 50
|
||||
|
||||
struct ResidentKeyStore {
|
||||
CTAP_residentKey rks[RK_NUM];
|
||||
} RK_STORE;
|
||||
|
||||
|
||||
static bool _up_disabled = false;
|
||||
|
||||
static 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"
|
||||
"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38"
|
||||
"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32"
|
||||
"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\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\x0f\x30\x0d"
|
||||
"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55"
|
||||
"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20"
|
||||
"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72"
|
||||
"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04"
|
||||
"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07"
|
||||
"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00"
|
||||
"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf"
|
||||
"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83"
|
||||
"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca"
|
||||
"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d"
|
||||
"\xa1\x30\xa4\x2e\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\x06\x03\x55\x04"
|
||||
"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94"
|
||||
"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04"
|
||||
"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
|
||||
"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e"
|
||||
"\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";
|
||||
|
||||
__attribute__((weak)) const uint8_t * attestation_cert_der = _attestation_cert_der;
|
||||
|
||||
__attribute__((weak)) uint8_t * device_get_attestation_key(){
|
||||
static 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";
|
||||
return attestation_key;
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint16_t device_attestation_cert_der_get_size(){
|
||||
return sizeof(_attestation_cert_der)-1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void device_reboot()
|
||||
{
|
||||
printf1(TAG_RED, "REBOOT command recieved!\r\n");
|
||||
exit(100);
|
||||
}
|
||||
|
||||
__attribute__((weak)) void device_set_status(uint32_t status)
|
||||
{
|
||||
static uint32_t __device_status = 0;
|
||||
if (status != CTAPHID_STATUS_IDLE && __device_status != status)
|
||||
{
|
||||
ctaphid_update_status(status);
|
||||
}
|
||||
__device_status = status;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((weak)) void usbhid_close(){/**/}
|
||||
|
||||
|
||||
__attribute__((weak)) void device_init(int argc, char *argv[]){/**/}
|
||||
|
||||
__attribute__((weak)) void device_disable_up(bool disable)
|
||||
{
|
||||
_up_disabled = disable;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int ctap_user_presence_test(uint32_t d)
|
||||
{
|
||||
if (_up_disabled)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int ctap_user_verification(uint8_t arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint32_t ctap_atomic_count(uint32_t amount)
|
||||
{
|
||||
static uint32_t counter1 = 25;
|
||||
counter1 += (amount + 1);
|
||||
return counter1;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((weak)) int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
{
|
||||
int i;
|
||||
printf1(TAG_ERR, "Insecure RNG being used.\r\n");
|
||||
for (i = 0; i < num; i++){
|
||||
dst[i] = (uint8_t)rand();
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((weak)) int device_is_nfc()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void device_wink()
|
||||
{
|
||||
printf1(TAG_GREEN,"*WINK*\n");
|
||||
}
|
||||
|
||||
__attribute__((weak)) void device_set_clock_rate(DEVICE_CLOCK_RATE param){/**/}
|
||||
|
||||
static AuthenticatorState _tmp_state = {0};
|
||||
__attribute__((weak)) int authenticator_read_state(AuthenticatorState * s){
|
||||
if (_tmp_state.is_initialized != INITIALIZED_MARKER){
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
memmove(s, &_tmp_state, sizeof(AuthenticatorState));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((weak)) void authenticator_write_state(AuthenticatorState * s){
|
||||
memmove(&_tmp_state, s, sizeof(AuthenticatorState));
|
||||
}
|
||||
|
||||
__attribute__((weak)) void ctap_reset_rk()
|
||||
{
|
||||
memset(&RK_STORE,0xff,sizeof(RK_STORE));
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint32_t ctap_rk_size()
|
||||
{
|
||||
return RK_NUM;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((weak)) void ctap_store_rk(int index, CTAP_residentKey * rk)
|
||||
{
|
||||
if (index < RK_NUM)
|
||||
{
|
||||
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__attribute__((weak)) void ctap_load_rk(int index, CTAP_residentKey * rk)
|
||||
{
|
||||
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));
|
||||
}
|
||||
|
||||
__attribute__((weak)) void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
|
||||
{
|
||||
if (index < RK_NUM)
|
||||
{
|
||||
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
|
||||
}
|
||||
}
|
||||
|
204
fido2/device.h
204
fido2/device.h
@ -9,159 +9,82 @@
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
/** Return a millisecond timestamp. Does not need to be synchronized to anything.
|
||||
* *Optional* to compile, but will not calculate delays correctly without a correct implementation.
|
||||
*/
|
||||
void device_init(int argc, char *argv[]);
|
||||
|
||||
uint32_t millis();
|
||||
|
||||
void delay(uint32_t ms);
|
||||
|
||||
// HID message size in bytes
|
||||
#define HID_MESSAGE_SIZE 64
|
||||
|
||||
void usbhid_init();
|
||||
|
||||
int usbhid_recv(uint8_t * msg);
|
||||
|
||||
/** Called by HIDUSB layer to write bytes to the USB HID interface endpoint.
|
||||
* Will write 64 bytes at a time.
|
||||
*
|
||||
* @param msg Pointer to a 64 byte buffer containing a payload to be sent via USB HID.
|
||||
*
|
||||
* **Required** to compile and work for FIDO application.
|
||||
*/
|
||||
void usbhid_send(uint8_t * msg);
|
||||
|
||||
void usbhid_close();
|
||||
|
||||
void main_loop_delay();
|
||||
|
||||
void heartbeat();
|
||||
|
||||
/** Reboot / power reset the device.
|
||||
* **Optional** this is not used for FIDO2, and simply won't do anything if not implemented.
|
||||
*/
|
||||
void device_reboot();
|
||||
|
||||
/** Read AuthenticatorState from nonvolatile memory.
|
||||
* @param s pointer to AuthenticatorState buffer to be overwritten with contents from NV memory.
|
||||
* @return 0 - state stored is NOT initialized.
|
||||
* 1 - state stored is initialized.
|
||||
*
|
||||
* *Optional* this is required to make persistant updates to FIDO2 State (PIN and device master secret).
|
||||
* Without it, changes simply won't be persistant.
|
||||
*/
|
||||
int authenticator_read_state(AuthenticatorState * s);
|
||||
void authenticator_read_state(AuthenticatorState * );
|
||||
|
||||
/** Store changes in the authenticator state to nonvolatile memory.
|
||||
* @param s pointer to valid Authenticator state to write to NV memory.
|
||||
*
|
||||
* *Optional* this is required to make persistant updates to FIDO2 State (PIN and device master secret).
|
||||
* Without it, changes simply won't be persistant.
|
||||
*/
|
||||
void authenticator_write_state(AuthenticatorState * s);
|
||||
void authenticator_read_backup_state(AuthenticatorState * );
|
||||
|
||||
// Return 1 yes backup is init'd, else 0
|
||||
//void authenticator_initialize()
|
||||
int authenticator_is_backup_initialized();
|
||||
|
||||
void authenticator_write_state(AuthenticatorState *, int backup);
|
||||
|
||||
// Called each main loop. Doesn't need to do anything.
|
||||
void device_manage();
|
||||
|
||||
// sets status that's uses for sending status updates ~100ms.
|
||||
// A timer should be set up to call `ctaphid_update_status`
|
||||
|
||||
/** Updates status of the status of the FIDO2 layer application, which
|
||||
* can be used for polling updates in the USBHID layer.
|
||||
*
|
||||
* @param status is one of the following, which can be used appropriately by USB HID layer.
|
||||
#define CTAPHID_STATUS_IDLE 0
|
||||
#define CTAPHID_STATUS_PROCESSING 1
|
||||
#define CTAPHID_STATUS_UPNEEDED 2
|
||||
*
|
||||
* *Optional* to compile and run, but will be required to be used for proper FIDO2 operation with some platforms.
|
||||
*/
|
||||
void device_set_status(uint32_t status);
|
||||
|
||||
/** Returns true if button is currently pressed. Debouncing does not need to be handled. Should not block.
|
||||
* @return 1 if button is currently pressed.
|
||||
*
|
||||
* *Optional* to compile and run, but just returns one by default.
|
||||
*/
|
||||
// Returns if button is currently pressed
|
||||
int device_is_button_pressed();
|
||||
|
||||
//
|
||||
// Test for user presence
|
||||
// Return 2 for disabled, 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||
/** Test for user presence.
|
||||
* Perform test that user is present. Returns status on user presence. This is used by FIDO and U2F layer
|
||||
* to check if an operation should continue, or if the UP flag should be set.
|
||||
*
|
||||
* @param delay number of milliseconds to delay waiting for user before timeout.
|
||||
*
|
||||
* @return 2 - User presence is disabled. Operation should continue, but UP flag not set.
|
||||
* 1 - User presence confirmed. Operation should continue, and UP flag is set.
|
||||
* 0 - User presence is not confirmed. Operation should be denied.
|
||||
* -1 - Operation was canceled. Do not continue, reset transaction state.
|
||||
*
|
||||
* *Optional*, the default implementation will return 1, unless a FIDO2 operation calls for no UP, where this will then return 2.
|
||||
*/
|
||||
int ctap_user_presence_test(uint32_t delay);
|
||||
|
||||
/** Disable the next user presence test. This is called by FIDO2 layer when a transaction
|
||||
* requests UP to be disabled. The next call to ctap_user_presence_test should return 2,
|
||||
* and then UP should be enabled again.
|
||||
*
|
||||
* @param request_active indicate to activate (true) or disable (false) UP.
|
||||
*
|
||||
* *Optional*, the default implementation will provide expected behaviour with the default ctap_user_presence_test(...).
|
||||
*/
|
||||
void device_disable_up(bool request_active);
|
||||
|
||||
/** Generate random numbers. Random numbers should be good enough quality for
|
||||
* cryptographic use.
|
||||
*
|
||||
* @param dst the buffer to write into.
|
||||
* @param num the number of bytes to generate and write to dst.
|
||||
*
|
||||
* @return 1 if successful, or else the RNG failed.
|
||||
*
|
||||
* *Optional*, if not implemented, the random numbers will be from rand() and an error will be logged.
|
||||
*/
|
||||
// Generate @num bytes of random numbers to @dest
|
||||
// return 1 if success, error otherwise
|
||||
int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||
|
||||
/** Increment an atomic (non-volatile) counter and return the value.
|
||||
*
|
||||
* @param amount a non-zero amount to increment the counter by.
|
||||
*
|
||||
* *Optional*, if not implemented, the counter will not be persistant.
|
||||
*/
|
||||
// Increment atomic counter and return it.
|
||||
// @param amount the amount to increase the counter by.
|
||||
uint32_t ctap_atomic_count(uint32_t amount);
|
||||
|
||||
/** Delete all resident keys.
|
||||
*
|
||||
* *Optional*, if not implemented, operates on non-persistant RK's.
|
||||
*/
|
||||
// Verify the user
|
||||
// return 1 if user is verified, 0 if not
|
||||
int ctap_user_verification(uint8_t arg);
|
||||
|
||||
// Must be implemented by application
|
||||
// data is HID_MESSAGE_SIZE long in bytes
|
||||
void ctaphid_write_block(uint8_t * data);
|
||||
|
||||
|
||||
// Resident key
|
||||
void ctap_reset_rk();
|
||||
|
||||
/** Return the maximum amount of resident keys that can be stored.
|
||||
* @return max number of resident keys that can be stored, including already stored RK's.
|
||||
*
|
||||
* *Optional*, if not implemented, returns 50.
|
||||
*/
|
||||
uint32_t ctap_rk_size();
|
||||
|
||||
/** Store a resident key into an index between [ 0, ctap_rk_size() ).
|
||||
* Storage should be in non-volatile memory.
|
||||
*
|
||||
* @param index between RK index range.
|
||||
* @param rk pointer to valid rk structure that should be written to NV memory.
|
||||
*
|
||||
* *Optional*, if not implemented, operates on non-persistant RK's.
|
||||
*/
|
||||
void ctap_store_rk(int index,CTAP_residentKey * rk);
|
||||
|
||||
/** Read a resident key from an index into memory
|
||||
* @param index to read resident key from.
|
||||
* @param rk pointer to resident key structure to write into with RK.
|
||||
*
|
||||
* *Optional*, if not implemented, operates on non-persistant RK's.
|
||||
*/
|
||||
void ctap_load_rk(int index,CTAP_residentKey * rk);
|
||||
|
||||
/** Overwrite the RK located in index with a new RK.
|
||||
* @param index to write resident key to.
|
||||
* @param rk pointer to valid rk structure that should be written to NV memory, and replace existing RK there.
|
||||
*
|
||||
* *Optional*, if not implemented, operates on non-persistant RK's.
|
||||
*/
|
||||
void ctap_overwrite_rk(int index,CTAP_residentKey * rk);
|
||||
|
||||
// For Solo hacker
|
||||
void boot_solo_bootloader();
|
||||
void boot_st_bootloader();
|
||||
|
||||
/** Called by HID layer to indicate that a wink behavior should be performed.
|
||||
* Should not block, and the wink behavior should occur in parallel to FIDO operations.
|
||||
*
|
||||
* *Optional*.
|
||||
*/
|
||||
// HID wink command
|
||||
void device_wink();
|
||||
|
||||
typedef enum {
|
||||
@ -170,42 +93,21 @@ typedef enum {
|
||||
DEVICE_FAST = 2,
|
||||
} DEVICE_CLOCK_RATE;
|
||||
|
||||
/**
|
||||
* Set the clock rate for the device. This gets called only when the device is running in NFC mode.
|
||||
* Before Register and authenticate operations, the clock rate will be set to (1), and otherwise back to (0).
|
||||
* @param param
|
||||
0: Lowest clock rate for NFC.
|
||||
1: fastest clock rate supported at a low power setting for NFC FIDO.
|
||||
2: fastest clock rate. Generally for USB interface.
|
||||
* *Optional*, by default nothing happens.
|
||||
*/
|
||||
// Set the clock rate for the device.
|
||||
// Three modes are targetted for Solo.
|
||||
// 0: Lowest clock rate for NFC.
|
||||
// 1: fastest clock rate supported at a low power setting for NFC FIDO.
|
||||
// 2: fastest clock rate. Generally for USB interface.
|
||||
void device_set_clock_rate(DEVICE_CLOCK_RATE param);
|
||||
|
||||
// Returns NFC_IS_NA, NFC_IS_ACTIVE, or NFC_IS_AVAILABLE
|
||||
#define NFC_IS_NA 0
|
||||
#define NFC_IS_ACTIVE 1
|
||||
#define NFC_IS_AVAILABLE 2
|
||||
|
||||
/** Returns NFC status of the device.
|
||||
* @return 0 - NFC is not available.
|
||||
* 1 - NFC is active, and is powering the chip for a transaction.
|
||||
* 2 - NFC is available, but not currently being used.
|
||||
*/
|
||||
int device_is_nfc();
|
||||
|
||||
void device_disable_up(bool request_active);
|
||||
|
||||
/** Return pointer to attestation key.
|
||||
* @return pointer to attestation private key, raw encoded. For P256, this is 32 bytes.
|
||||
*/
|
||||
uint8_t * device_get_attestation_key();
|
||||
|
||||
/** Pointer to a ASN.1/DER encoded byte array of the attestation certificate.
|
||||
*/
|
||||
extern const uint8_t * attestation_cert_der;
|
||||
|
||||
/** Returns the size in bytes of attestation_cert_der.
|
||||
* @return number of bytes in attestation_cert_der, not including any C string null byte.
|
||||
*/
|
||||
uint16_t device_attestation_cert_der_get_size();
|
||||
void device_init_button();
|
||||
|
||||
#endif
|
||||
|
@ -1,41 +0,0 @@
|
||||
// Copyright 2019 SoloKeys Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
#ifndef SRC_APP_H_
|
||||
#define SRC_APP_H_
|
||||
#include <stdbool.h>
|
||||
|
||||
#define USING_DEV_BOARD
|
||||
|
||||
#define USING_PC
|
||||
|
||||
#define ENABLE_U2F
|
||||
#define ENABLE_U2F_EXTENSIONS
|
||||
//#define BRIDGE_TO_WALLET
|
||||
|
||||
void printing_init();
|
||||
|
||||
extern bool use_udp;
|
||||
|
||||
// 0xRRGGBB
|
||||
#define LED_INIT_VALUE 0x000800
|
||||
#define LED_WINK_VALUE 0x000008
|
||||
#define LED_MAX_SCALER 30
|
||||
#define LED_MIN_SCALER 1
|
||||
// # of ms between each change in LED
|
||||
#define HEARTBEAT_PERIOD 100
|
||||
// Each LED channel will be multiplied by a integer between LED_MAX_SCALER
|
||||
// and LED_MIN_SCALER to cause the slow pulse. E.g.
|
||||
// #define LED_INIT_VALUE 0x301000
|
||||
// #define LED_MAX_SCALER 30
|
||||
// #define LED_MIN_SCALER 1
|
||||
// #define HEARTBEAT_PERIOD 8
|
||||
// Will pulse from 0x301000 to 0x903000 to 0x301000 ...
|
||||
// Which will take ~8 * (30)*2 ms
|
||||
|
||||
|
||||
#endif /* SRC_APP_H_ */
|
@ -7,10 +7,7 @@
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
#ifdef APP_CONFIG
|
||||
#include APP_CONFIG
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
@ -53,7 +50,7 @@ typedef enum
|
||||
TAG_FILENO = (1UL << 31)
|
||||
} LOG_TAG;
|
||||
|
||||
#if defined(DEBUG_LEVEL) && DEBUG_LEVEL > 0
|
||||
#if DEBUG_LEVEL > 0
|
||||
|
||||
void set_logging_mask(uint32_t mask);
|
||||
#define printf1(tag,fmt, ...) LOG(tag & ~(TAG_FILENO), NULL, 0, fmt, ##__VA_ARGS__)
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
@ -18,12 +17,9 @@
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
#include "app.h"
|
||||
|
||||
|
||||
void device_init(int argc, char *argv[]);
|
||||
int usbhid_recv(uint8_t * msg);
|
||||
#include APP_CONFIG
|
||||
|
||||
#if !defined(TEST)
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -33,21 +29,20 @@ int main(int argc, char *argv[])
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
// TAG_GEN|
|
||||
//TAG_GEN|
|
||||
// TAG_MC |
|
||||
// TAG_GA |
|
||||
TAG_WALLET |
|
||||
TAG_STOR |
|
||||
//TAG_NFC_APDU |
|
||||
TAG_NFC |
|
||||
// TAG_CP |
|
||||
//TAG_CP |
|
||||
// TAG_CTAP|
|
||||
// TAG_HID|
|
||||
//TAG_HID|
|
||||
TAG_U2F|
|
||||
// TAG_PARSE |
|
||||
//TAG_PARSE |
|
||||
//TAG_TIME|
|
||||
// TAG_DUMP|
|
||||
// TAG_DUMP2|
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_EXT|
|
||||
@ -62,6 +57,13 @@ int main(int argc, char *argv[])
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (millis() - t1 > HEARTBEAT_PERIOD)
|
||||
{
|
||||
heartbeat();
|
||||
t1 = millis();
|
||||
}
|
||||
|
||||
device_manage();
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
@ -71,16 +73,14 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
ctaphid_check_timeouts();
|
||||
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*10;
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
usbhid_close();
|
||||
printf1(TAG_GREEN, "done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -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 = device_attestation_cert_der_get_size();
|
||||
const uint16_t attest_size = attestation_cert_der_get_size();
|
||||
|
||||
if ( ! ctap_user_presence_test(750))
|
||||
{
|
||||
|
@ -1,9 +0,0 @@
|
||||
|
||||
SOLO_VERSION_FULL?=$(shell git describe)
|
||||
SOLO_VERSION:=$(shell python -c 'print("$(SOLO_VERSION_FULL)".split("-")[0])')
|
||||
SOLO_VERSION_MAJ:=$(shell python -c 'print("$(SOLO_VERSION)".split(".")[0])')
|
||||
SOLO_VERSION_MIN:=$(shell python -c 'print("$(SOLO_VERSION)".split(".")[1])')
|
||||
SOLO_VERSION_PAT:=$(shell python -c 'print("$(SOLO_VERSION)".split(".")[2])')
|
||||
|
||||
SOLO_VERSION_FLAGS := -DSOLO_VERSION_MAJ=$(SOLO_VERSION_MAJ) -DSOLO_VERSION_MIN=$(SOLO_VERSION_MIN) \
|
||||
-DSOLO_VERSION_PATCH=$(SOLO_VERSION_PAT) -DSOLO_VERSION=\"$(SOLO_VERSION_FULL)\"
|
@ -1,10 +1,14 @@
|
||||
#!/bin/bash -xe
|
||||
version=$1
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
|
||||
version=${1:-master}
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
|
||||
|
||||
cd /solo/targets/stm32l432
|
||||
ls
|
||||
git fetch --tags
|
||||
git checkout ${version}
|
||||
git submodule update --init --recursive
|
||||
version=$(git describe)
|
||||
|
||||
make cbor
|
||||
|
||||
@ -12,12 +16,13 @@ out_dir="/builds"
|
||||
|
||||
function build() {
|
||||
part=${1}
|
||||
output=${2}
|
||||
what="${part}"
|
||||
variant=${2}
|
||||
output=${3:-${part}}
|
||||
what="${part}-${variant}"
|
||||
|
||||
make full-clean
|
||||
|
||||
make ${what} VERSION_FULL=${version}
|
||||
make ${what}
|
||||
|
||||
out_hex="${what}-${version}.hex"
|
||||
out_sha2="${what}-${version}.sha2"
|
||||
@ -27,27 +32,24 @@ function build() {
|
||||
cp ${out_hex} ${out_sha2} ${out_dir}
|
||||
}
|
||||
|
||||
build bootloader-nonverifying bootloader
|
||||
build bootloader-verifying bootloader
|
||||
build firmware solo
|
||||
build firmware-debug-1 solo
|
||||
build firmware-debug-2 solo
|
||||
build firmware solo
|
||||
build bootloader nonverifying
|
||||
build bootloader verifying
|
||||
build firmware hacker solo
|
||||
build firmware hacker-debug-1 solo
|
||||
build firmware hacker-debug-2 solo
|
||||
build firmware secure solo
|
||||
build firmware secure-non-solokeys solo
|
||||
|
||||
pip install -U pip
|
||||
pip install -U solo-python
|
||||
cd ${out_dir}
|
||||
|
||||
bundle="bundle-hacker-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-${version}.hex ${bundle}.hex
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
||||
bundle="bundle-hacker-debug-1-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-1-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-1-${version}.hex ${bundle}.hex
|
||||
bundle="bundle-hacker-debug-2-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-debug-2-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-2-${version}.hex ${bundle}.hex
|
||||
bundle="bundle-secure-non-solokeys-${version}"
|
||||
/opt/conda/bin/solo mergehex --lock bootloader-verifying-${version}.hex firmware-${version}.hex ${bundle}.hex
|
||||
/opt/conda/bin/solo mergehex bootloader-verifying-${version}.hex firmware-secure-non-solokeys-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
||||
|
@ -18,7 +18,6 @@ nav:
|
||||
- Application Ideas: solo/application-ideas.md
|
||||
- Running on Nucleo32 board: solo/nucleo32-board.md
|
||||
- Signed update process: solo/signed-updates.md
|
||||
- Usage and Porting guide: solo/porting.md
|
||||
- Code documentation: solo/code-overview.md
|
||||
- Contributing Code: solo/contributing.md
|
||||
- Contributing Docs: solo/documenting.md
|
||||
|
199
pc/device.c
199
pc/device.c
@ -11,6 +11,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
@ -24,7 +25,8 @@
|
||||
|
||||
#define RK_NUM 50
|
||||
|
||||
static bool use_udp = true;
|
||||
bool use_udp = true;
|
||||
static bool _up_disabled = false;
|
||||
|
||||
struct ResidentKeyStore {
|
||||
CTAP_residentKey rks[RK_NUM];
|
||||
@ -32,6 +34,21 @@ struct ResidentKeyStore {
|
||||
|
||||
void authenticator_initialize();
|
||||
|
||||
uint32_t __device_status = 0;
|
||||
void device_set_status(uint32_t status)
|
||||
{
|
||||
if (status != CTAPHID_STATUS_IDLE && __device_status != status)
|
||||
{
|
||||
ctaphid_update_status(status);
|
||||
}
|
||||
__device_status = status;
|
||||
}
|
||||
|
||||
void device_reboot()
|
||||
{
|
||||
printf1(TAG_RED, "REBOOT command recieved!\r\n");
|
||||
exit(100);
|
||||
}
|
||||
|
||||
int udp_server()
|
||||
{
|
||||
@ -175,6 +192,7 @@ int usbhid_recv(uint8_t * msg)
|
||||
return l;
|
||||
}
|
||||
|
||||
// Send 64 byte USB HID message
|
||||
void usbhid_send(uint8_t * msg)
|
||||
{
|
||||
if (use_udp)
|
||||
@ -191,8 +209,6 @@ void usbhid_send(uint8_t * msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void usbhid_close()
|
||||
{
|
||||
close(fd);
|
||||
@ -256,6 +272,14 @@ void device_init(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
void main_loop_delay()
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*100;
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
void delay(uint32_t ms)
|
||||
{
|
||||
struct timespec ts;
|
||||
@ -265,6 +289,40 @@ void delay(uint32_t ms)
|
||||
}
|
||||
|
||||
|
||||
void heartbeat()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ctaphid_write_block(uint8_t * data)
|
||||
{
|
||||
/*printf("<< "); dump_hex(data, 64);*/
|
||||
usbhid_send(data);
|
||||
}
|
||||
|
||||
|
||||
int ctap_user_presence_test(uint32_t d)
|
||||
{
|
||||
if (_up_disabled)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ctap_user_verification(uint8_t arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ctap_atomic_count(uint32_t amount)
|
||||
{
|
||||
static uint32_t counter1 = 25;
|
||||
counter1 += (amount + 1);
|
||||
return counter1;
|
||||
}
|
||||
|
||||
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
{
|
||||
int ret;
|
||||
@ -286,9 +344,10 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
|
||||
|
||||
const char * state_file = "authenticator_state.bin";
|
||||
const char * backup_file = "authenticator_state2.bin";
|
||||
const char * rk_file = "resident_keys.bin";
|
||||
|
||||
int authenticator_read_state(AuthenticatorState * state)
|
||||
void authenticator_read_state(AuthenticatorState * state)
|
||||
{
|
||||
FILE * f;
|
||||
int ret;
|
||||
@ -307,35 +366,104 @@ int authenticator_read_state(AuthenticatorState * state)
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
if (state->is_initialized == INITIALIZED_MARKER)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void authenticator_write_state(AuthenticatorState * state)
|
||||
void authenticator_read_backup_state(AuthenticatorState * state )
|
||||
{
|
||||
FILE * f;
|
||||
int ret;
|
||||
|
||||
f = fopen(state_file, "wb+");
|
||||
f = fopen(backup_file, "rb");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
|
||||
|
||||
ret = fread(state, 1, sizeof(AuthenticatorState), f);
|
||||
fclose(f);
|
||||
if (ret != sizeof(AuthenticatorState))
|
||||
if(ret != sizeof(AuthenticatorState))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void authenticator_write_state(AuthenticatorState * state, int backup)
|
||||
{
|
||||
FILE * f;
|
||||
int ret;
|
||||
|
||||
if (! backup)
|
||||
{
|
||||
f = fopen(state_file, "wb+");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
|
||||
fclose(f);
|
||||
if (ret != sizeof(AuthenticatorState))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
f = fopen(backup_file, "wb+");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
|
||||
fclose(f);
|
||||
if (ret != sizeof(AuthenticatorState))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return 1 yes backup is init'd, else 0
|
||||
int authenticator_is_backup_initialized()
|
||||
{
|
||||
uint8_t header[16];
|
||||
AuthenticatorState * state = (AuthenticatorState*) header;
|
||||
FILE * f;
|
||||
int ret;
|
||||
|
||||
printf("state file exists\n");
|
||||
f = fopen(backup_file, "rb");
|
||||
if (f== NULL)
|
||||
{
|
||||
printf("Warning, backup file doesn't exist\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = fread(header, 1, sizeof(header), f);
|
||||
fclose(f);
|
||||
if(ret != sizeof(header))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return state->is_initialized == INITIALIZED_MARKER;
|
||||
|
||||
}
|
||||
|
||||
// Return 1 yes backup is init'd, else 0
|
||||
/*int authenticator_is_initialized()*/
|
||||
/*{*/
|
||||
|
||||
|
||||
/*}*/
|
||||
|
||||
static void sync_rk()
|
||||
{
|
||||
@ -415,18 +543,44 @@ void authenticator_initialize()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
f = fopen(backup_file, "wb+");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
mem = malloc(sizeof(AuthenticatorState));
|
||||
memset(mem,0xff,sizeof(AuthenticatorState));
|
||||
ret = fwrite(mem, 1, sizeof(AuthenticatorState), f);
|
||||
free(mem);
|
||||
fclose(f);
|
||||
if (ret != sizeof(AuthenticatorState))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// resident_keys
|
||||
memset(&RK_STORE,0xff,sizeof(RK_STORE));
|
||||
sync_rk();
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void device_manage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ctap_reset_rk()
|
||||
{
|
||||
memset(&RK_STORE,0xff,sizeof(RK_STORE));
|
||||
sync_rk();
|
||||
|
||||
}
|
||||
|
||||
uint32_t ctap_rk_size()
|
||||
@ -468,9 +622,22 @@ void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
|
||||
}
|
||||
}
|
||||
|
||||
void device_wink()
|
||||
{
|
||||
printf("*WINK*\n");
|
||||
}
|
||||
|
||||
int device_is_nfc()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void device_disable_up(bool disable)
|
||||
{
|
||||
_up_disabled = disable;
|
||||
}
|
||||
|
||||
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,8 @@ ifndef DEBUG
|
||||
DEBUG=0
|
||||
endif
|
||||
|
||||
VERSION_FULL?=$(shell git describe)
|
||||
APPMAKE=build/application.mk VERSION_FULL=${VERSION_FULL}
|
||||
BOOTMAKE=build/bootloader.mk VERSION_FULL=${VERSION_FULL}
|
||||
APPMAKE=build/application.mk
|
||||
BOOTMAKE=build/bootloader.mk
|
||||
|
||||
merge_hex=solo mergehex
|
||||
|
||||
@ -13,14 +12,20 @@ merge_hex=solo mergehex
|
||||
|
||||
# The following are the main targets for reproducible builds.
|
||||
# TODO: better explanation
|
||||
firmware:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0
|
||||
firmware-hacker:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1
|
||||
firmware-hacker-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-debug-2:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2
|
||||
firmware-hacker-debug-2:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-secure-non-solokeys:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DFLASH_ROP=2'
|
||||
|
||||
firmware-secure:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2'
|
||||
|
||||
bootloader-nonverifying:
|
||||
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
|
||||
@ -90,7 +95,7 @@ flashboot: bootloader.hex
|
||||
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
|
||||
|
||||
flash-firmware:
|
||||
$(SZ) -A solo.elf
|
||||
arm-none-eabi-size -A solo.elf
|
||||
solo program aux enter-bootloader
|
||||
solo program bootloader solo.hex
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#define _APP_H_
|
||||
#include <stdint.h>
|
||||
#include "version.h"
|
||||
#include "solo.h"
|
||||
|
||||
#define DEBUG_UART USART1
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
@ -21,7 +21,6 @@
|
||||
#define BOOT_TO_DFU 0
|
||||
|
||||
|
||||
#define SOLO 1
|
||||
#define IS_BOOTLOADER 1
|
||||
|
||||
#define ENABLE_U2F_EXTENSIONS
|
||||
|
@ -46,7 +46,9 @@ int main()
|
||||
{
|
||||
uint8_t hidmsg[64];
|
||||
uint32_t t1 = 0;
|
||||
#ifdef SOLO_HACKER
|
||||
uint32_t stboot_time = 0;
|
||||
#endif
|
||||
uint32_t boot = 1;
|
||||
|
||||
set_logging_mask(
|
||||
@ -96,6 +98,7 @@ int main()
|
||||
}
|
||||
|
||||
|
||||
#ifdef SOLO_HACKER
|
||||
if (!is_bootloader_disabled())
|
||||
{
|
||||
stboot_time = millis();
|
||||
@ -105,6 +108,7 @@ int main()
|
||||
goto start_bootloader;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_authorized_to_boot() && (boot || is_bootloader_disabled()))
|
||||
{
|
||||
@ -115,8 +119,9 @@ int main()
|
||||
|
||||
printf1(TAG_RED,"Not authorized to boot (%08x == %08lx)\r\n", AUTH_WORD_ADDR, *(uint32_t*)AUTH_WORD_ADDR);
|
||||
}
|
||||
#ifdef SOLO_HACKER
|
||||
start_bootloader:
|
||||
|
||||
#endif
|
||||
SystemClock_Config();
|
||||
init_gpio();
|
||||
init_millisecond_timer(0);
|
||||
|
@ -2,14 +2,14 @@ include build/common.mk
|
||||
|
||||
# ST related
|
||||
SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
||||
SRC += src/fifo.c src/attestation.c src/nfc.c src/ams.c src/sense.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/nfc.c src/ams.c src/sense.c
|
||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||
SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
# FIDO2 lib
|
||||
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
||||
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
|
||||
SRC += ../../fido2/ctap_parse.c ../../fido2/crypto.c
|
||||
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
|
||||
SRC += ../../fido2/version.c
|
||||
SRC += ../../fido2/data_migration.c
|
||||
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
|
||||
@ -22,9 +22,7 @@ SRC += ../../crypto/cifra/src/sha512.c ../../crypto/cifra/src/blockwise.c
|
||||
OBJ1=$(SRC:.c=.o)
|
||||
OBJ=$(OBJ1:.s=.o)
|
||||
|
||||
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/
|
||||
|
||||
INC+= -I../../fido2/ -I../../fido2/extensions
|
||||
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
|
||||
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
|
||||
INC += -I../../crypto/tiny-AES-c
|
||||
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
|
||||
@ -68,6 +66,9 @@ all: $(TARGET).elf
|
||||
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
|
||||
$(CC) $^ $(HW) -O3 $(ECC_CFLAGS) -o $@
|
||||
|
||||
%.o: %.s
|
||||
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||
@echo "Built version: $(VERSION_FLAGS)"
|
||||
|
@ -4,14 +4,13 @@ include build/common.mk
|
||||
SRC = bootloader/main.c bootloader/bootloader.c
|
||||
SRC += bootloader/pubkey_bootloader.c bootloader/version_check.c
|
||||
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
||||
SRC += src/fifo.c src/attestation.c src/sense.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/sense.c
|
||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||
SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
# FIDO2 lib
|
||||
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/extensions/extensions.c
|
||||
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
|
||||
SRC += ../../fido2/crypto.c
|
||||
|
||||
# Crypto libs
|
||||
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c
|
||||
@ -67,7 +66,7 @@ all: $(TARGET).elf
|
||||
|
||||
%.elf: $(OBJ)
|
||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||
$(SZ) $@
|
||||
arm-none-eabi-size $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(CP) -O ihex $^ $(TARGET).hex
|
||||
|
@ -1,10 +1,7 @@
|
||||
include ../../fido2/version.mk
|
||||
|
||||
CC=$(PREFIX)arm-none-eabi-gcc
|
||||
CP=$(PREFIX)arm-none-eabi-objcopy
|
||||
SZ=$(PREFIX)arm-none-eabi-size
|
||||
AR=$(PREFIX)arm-none-eabi-ar
|
||||
AS=$(PREFIX)arm-none-eabi-as
|
||||
|
||||
DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \
|
||||
lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_rng.c lib/stm32l4xx_ll_tim.c \
|
||||
@ -16,20 +13,17 @@ USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c
|
||||
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \
|
||||
lib/usbd/usbd_ccid.c
|
||||
|
||||
VERSION_FULL?=$(SOLO_VERSION_FULL)
|
||||
VERSION:=$(SOLO_VERSION)
|
||||
VERSION_MAJ:=$(SOLO_VERSION_MAJ)
|
||||
VERSION_MIN:=$(SOLO_VERSION_MIN)
|
||||
VERSION_PAT:=$(SOLO_VERSION_PAT)
|
||||
VERSION:=$(shell git describe --abbrev=0 )
|
||||
VERSION_FULL:=$(shell git describe)
|
||||
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
|
||||
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
|
||||
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
|
||||
|
||||
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
|
||||
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
|
||||
|
||||
_all:
|
||||
echo $(SOLO_VERSION_FULL)
|
||||
echo $(SOLO_VERSION_MAJ)
|
||||
echo $(SOLO_VERSION_MIN)
|
||||
echo $(SOLO_VERSION_PAT)
|
||||
|
||||
%.o: %.s
|
||||
$(AS) -o $@ $^
|
||||
echo $(VERSION_FULL)
|
||||
echo $(VERSION_MAJ)
|
||||
echo $(VERSION_MIN)
|
||||
echo $(VERSION_PAT)
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define _APP_H_
|
||||
#include <stdint.h>
|
||||
#include "version.h"
|
||||
#include "solo.h"
|
||||
|
||||
#define SOLO
|
||||
|
||||
|
@ -95,14 +95,12 @@ const uint8_t attestation_hacker_cert_der[] =
|
||||
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;
|
||||
|
||||
uint8_t * device_get_attestation_key(){
|
||||
flash_attestation_page * page =(flash_attestation_page *)ATTESTATION_PAGE_ADDR;
|
||||
return page->attestation_key;
|
||||
}
|
||||
|
||||
uint16_t device_attestation_cert_der_get_size(){
|
||||
#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;
|
||||
}
|
||||
|
||||
|
369
targets/stm32l432/src/crypto.c
Normal file
369
targets/stm32l432/src/crypto.c
Normal file
@ -0,0 +1,369 @@
|
||||
// Copyright 2019 SoloKeys Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
/*
|
||||
* Wrapper for crypto implementation on device
|
||||
*
|
||||
* */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
#include "util.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef USE_SOFTWARE_IMPLEMENTATION
|
||||
|
||||
#include "sha256.h"
|
||||
#include "uECC.h"
|
||||
#include "aes.h"
|
||||
#include "ctap.h"
|
||||
#include "device.h"
|
||||
// stuff for SHA512
|
||||
#include "sha2.h"
|
||||
#include "blockwise.h"
|
||||
#include APP_CONFIG
|
||||
#include "log.h"
|
||||
#include "memory_layout.h"
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MBEDTLS_ECP_DP_NONE = 0,
|
||||
MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */
|
||||
MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */
|
||||
MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */
|
||||
MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */
|
||||
MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */
|
||||
MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */
|
||||
MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */
|
||||
MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */
|
||||
MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */
|
||||
MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */
|
||||
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
|
||||
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
|
||||
} mbedtls_ecp_group_id;
|
||||
|
||||
|
||||
static SHA256_CTX sha256_ctx;
|
||||
static cf_sha512_context sha512_ctx;
|
||||
static const struct uECC_Curve_t * _es256_curve = NULL;
|
||||
static const uint8_t * _signing_key = NULL;
|
||||
static int _key_len = 0;
|
||||
|
||||
// Secrets for testing only
|
||||
static uint8_t master_secret[64];
|
||||
static uint8_t transport_secret[32];
|
||||
|
||||
|
||||
void crypto_sha256_init(void)
|
||||
{
|
||||
sha256_init(&sha256_ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_init(void)
|
||||
{
|
||||
cf_sha512_init(&sha512_ctx);
|
||||
}
|
||||
|
||||
void crypto_load_master_secret(uint8_t * key)
|
||||
{
|
||||
#if KEY_SPACE_BYTES < 96
|
||||
#error "need more key bytes"
|
||||
#endif
|
||||
memmove(master_secret, key, 64);
|
||||
memmove(transport_secret, key+64, 32);
|
||||
}
|
||||
|
||||
void crypto_reset_master_secret(void)
|
||||
{
|
||||
memset(master_secret, 0, 64);
|
||||
memset(transport_secret, 0, 32);
|
||||
ctap_generate_rng(master_secret, 64);
|
||||
ctap_generate_rng(transport_secret, 32);
|
||||
}
|
||||
|
||||
|
||||
void crypto_sha256_update(uint8_t * data, size_t len)
|
||||
{
|
||||
sha256_update(&sha256_ctx, data, len);
|
||||
}
|
||||
|
||||
void crypto_sha512_update(const uint8_t * data, size_t len) {
|
||||
cf_sha512_update(&sha512_ctx, data, len);
|
||||
}
|
||||
|
||||
void crypto_sha256_update_secret()
|
||||
{
|
||||
sha256_update(&sha256_ctx, master_secret, 32);
|
||||
}
|
||||
|
||||
void crypto_sha256_final(uint8_t * hash)
|
||||
{
|
||||
sha256_final(&sha256_ctx, hash);
|
||||
}
|
||||
|
||||
void crypto_sha512_final(uint8_t * hash)
|
||||
{
|
||||
// NB: there is also cf_sha512_digest
|
||||
cf_sha512_digest_final(&sha512_ctx, hash);
|
||||
}
|
||||
|
||||
void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
unsigned int i;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (key == CRYPTO_MASTER_KEY)
|
||||
{
|
||||
key = master_secret;
|
||||
klen = sizeof(master_secret)/2;
|
||||
}
|
||||
else if (key == CRYPTO_TRANSPORT_KEY)
|
||||
{
|
||||
key = transport_secret;
|
||||
klen = 32;
|
||||
}
|
||||
|
||||
if(klen > 64)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memmove(buf, key, klen);
|
||||
|
||||
for (i = 0; i < sizeof(buf); i++)
|
||||
{
|
||||
buf[i] = buf[i] ^ 0x36;
|
||||
}
|
||||
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(buf, 64);
|
||||
}
|
||||
|
||||
void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
unsigned int i;
|
||||
crypto_sha256_final(hmac);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (key == CRYPTO_MASTER_KEY)
|
||||
{
|
||||
key = master_secret;
|
||||
klen = sizeof(master_secret)/2;
|
||||
}
|
||||
else if (key == CRYPTO_TRANSPORT_KEY2)
|
||||
{
|
||||
key = transport_secret;
|
||||
klen = 32;
|
||||
}
|
||||
|
||||
|
||||
if(klen > 64)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||
exit(1);
|
||||
}
|
||||
memmove(buf, key, klen);
|
||||
|
||||
for (i = 0; i < sizeof(buf); i++)
|
||||
{
|
||||
buf[i] = buf[i] ^ 0x5c;
|
||||
}
|
||||
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(buf, 64);
|
||||
crypto_sha256_update(hmac, 32);
|
||||
crypto_sha256_final(hmac);
|
||||
}
|
||||
|
||||
|
||||
void crypto_ecc256_init(void)
|
||||
{
|
||||
uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
|
||||
_es256_curve = uECC_secp256r1();
|
||||
}
|
||||
|
||||
|
||||
void crypto_ecc256_load_attestation_key(void)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
||||
{
|
||||
if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
|
||||
{
|
||||
printf2(TAG_ERR, "error, uECC failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2)
|
||||
{
|
||||
static uint8_t privkey[32];
|
||||
generate_private_key(data,len,data2,len2,privkey);
|
||||
_signing_key = privkey;
|
||||
_key_len = 32;
|
||||
}
|
||||
|
||||
void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID)
|
||||
{
|
||||
|
||||
const struct uECC_Curve_t * curve = NULL;
|
||||
|
||||
switch(MBEDTLS_ECP_ID)
|
||||
{
|
||||
case MBEDTLS_ECP_DP_SECP192R1:
|
||||
curve = uECC_secp192r1();
|
||||
if (_key_len != 24) goto fail;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_SECP224R1:
|
||||
curve = uECC_secp224r1();
|
||||
if (_key_len != 28) goto fail;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_SECP256R1:
|
||||
curve = uECC_secp256r1();
|
||||
if (_key_len != 32) goto fail;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_SECP256K1:
|
||||
curve = uECC_secp256k1();
|
||||
if (_key_len != 32) goto fail;
|
||||
break;
|
||||
default:
|
||||
printf2(TAG_ERR, "error, invalid ECDSA alg specifier\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( uECC_sign(_signing_key, data, len, sig, curve) == 0)
|
||||
{
|
||||
printf2(TAG_ERR, "error, uECC failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
printf2(TAG_ERR, "error, invalid key length\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey)
|
||||
{
|
||||
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
|
||||
crypto_sha256_update(data, len);
|
||||
crypto_sha256_update(data2, len2);
|
||||
crypto_sha256_update(master_secret, 32); // TODO AES
|
||||
crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
|
||||
|
||||
crypto_aes256_init(master_secret + 32, NULL);
|
||||
crypto_aes256_encrypt(privkey, 32);
|
||||
}
|
||||
|
||||
|
||||
/*int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);*/
|
||||
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y)
|
||||
{
|
||||
uint8_t privkey[32];
|
||||
uint8_t pubkey[64];
|
||||
|
||||
generate_private_key(data,len,NULL,0,privkey);
|
||||
|
||||
memset(pubkey,0,sizeof(pubkey));
|
||||
uECC_compute_public_key(privkey, pubkey, _es256_curve);
|
||||
memmove(x,pubkey,32);
|
||||
memmove(y,pubkey+32,32);
|
||||
}
|
||||
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
|
||||
{
|
||||
uECC_compute_public_key(privkey, pubkey, _es256_curve);
|
||||
}
|
||||
|
||||
|
||||
void crypto_load_external_key(uint8_t * key, int len)
|
||||
{
|
||||
_signing_key = key;
|
||||
_key_len = len;
|
||||
}
|
||||
|
||||
|
||||
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
|
||||
{
|
||||
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, uECC_make_key failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret)
|
||||
{
|
||||
if (uECC_shared_secret(pubkey, privkey, shared_secret, _es256_curve) != 1)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, uECC_shared_secret failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct AES_ctx aes_ctx;
|
||||
void crypto_aes256_init(uint8_t * key, uint8_t * nonce)
|
||||
{
|
||||
if (key == CRYPTO_TRANSPORT_KEY)
|
||||
{
|
||||
AES_init_ctx(&aes_ctx, transport_secret);
|
||||
}
|
||||
else
|
||||
{
|
||||
AES_init_ctx(&aes_ctx, key);
|
||||
}
|
||||
if (nonce == NULL)
|
||||
{
|
||||
memset(aes_ctx.Iv, 0, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(aes_ctx.Iv, nonce, 16);
|
||||
}
|
||||
}
|
||||
|
||||
// prevent round key recomputation
|
||||
void crypto_aes256_reset_iv(uint8_t * nonce)
|
||||
{
|
||||
if (nonce == NULL)
|
||||
{
|
||||
memset(aes_ctx.Iv, 0, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(aes_ctx.Iv, nonce, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_aes256_decrypt(uint8_t * buf, int length)
|
||||
{
|
||||
AES_CBC_decrypt_buffer(&aes_ctx, buf, length);
|
||||
}
|
||||
|
||||
void crypto_aes256_encrypt(uint8_t * buf, int length)
|
||||
{
|
||||
AES_CBC_encrypt_buffer(&aes_ctx, buf, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
#error "No crypto implementation defined"
|
||||
#endif
|
@ -195,8 +195,7 @@ void device_init_button(void)
|
||||
|
||||
int solo_is_locked(){
|
||||
uint64_t device_settings = ((flash_attestation_page *)ATTESTATION_PAGE_ADDR)->device_settings;
|
||||
uint32_t tag = (uint32_t)(device_settings >> 32ull);
|
||||
return tag == ATTESTATION_CONFIGURED_TAG && (device_settings & SOLO_FLAG_LOCKED) != 0;
|
||||
return (device_settings & SOLO_FLAG_LOCKED) != 0;
|
||||
}
|
||||
|
||||
/** device_migrate
|
||||
@ -285,7 +284,7 @@ static void device_migrate(){
|
||||
}
|
||||
}
|
||||
|
||||
void device_init()
|
||||
void device_init(int argc, char *argv[])
|
||||
{
|
||||
|
||||
hw_init(LOW_FREQUENCY);
|
||||
@ -468,8 +467,20 @@ void heartbeat(void)
|
||||
|
||||
}
|
||||
|
||||
void authenticator_read_state(AuthenticatorState * a)
|
||||
{
|
||||
uint32_t * ptr = (uint32_t *)flash_addr(STATE1_PAGE);
|
||||
memmove(a,ptr,sizeof(AuthenticatorState));
|
||||
}
|
||||
|
||||
static int authenticator_is_backup_initialized(void)
|
||||
void authenticator_read_backup_state(AuthenticatorState * a)
|
||||
{
|
||||
uint32_t * ptr = (uint32_t *)flash_addr(STATE2_PAGE);
|
||||
memmove(a,ptr,sizeof(AuthenticatorState));
|
||||
}
|
||||
|
||||
// Return 1 yes backup is init'd, else 0
|
||||
int authenticator_is_backup_initialized(void)
|
||||
{
|
||||
uint8_t header[16];
|
||||
uint32_t * ptr = (uint32_t *)flash_addr(STATE2_PAGE);
|
||||
@ -478,35 +489,20 @@ static int authenticator_is_backup_initialized(void)
|
||||
return state->is_initialized == INITIALIZED_MARKER;
|
||||
}
|
||||
|
||||
int authenticator_read_state(AuthenticatorState * a)
|
||||
void authenticator_write_state(AuthenticatorState * a, int backup)
|
||||
{
|
||||
uint32_t * ptr = (uint32_t *) flash_addr(STATE1_PAGE);
|
||||
memmove(a, ptr, sizeof(AuthenticatorState));
|
||||
if (! backup)
|
||||
{
|
||||
flash_erase_page(STATE1_PAGE);
|
||||
|
||||
if (a->is_initialized != INITIALIZED_MARKER){
|
||||
|
||||
if (authenticator_is_backup_initialized()){
|
||||
printf1(TAG_ERR,"Warning: memory corruption detected. restoring from backup..\n");
|
||||
ptr = (uint32_t *) flash_addr(STATE2_PAGE);
|
||||
memmove(a, ptr, sizeof(AuthenticatorState));
|
||||
authenticator_write_state(a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
flash_write(flash_addr(STATE1_PAGE), (uint8_t*)a, sizeof(AuthenticatorState));
|
||||
}
|
||||
else
|
||||
{
|
||||
flash_erase_page(STATE2_PAGE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void authenticator_write_state(AuthenticatorState * a)
|
||||
{
|
||||
flash_erase_page(STATE1_PAGE);
|
||||
flash_write(flash_addr(STATE1_PAGE), (uint8_t*)a, sizeof(AuthenticatorState));
|
||||
|
||||
flash_erase_page(STATE2_PAGE);
|
||||
flash_write(flash_addr(STATE2_PAGE), (uint8_t*)a, sizeof(AuthenticatorState));
|
||||
flash_write(flash_addr(STATE2_PAGE), (uint8_t*)a, sizeof(AuthenticatorState));
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(IS_BOOTLOADER)
|
||||
@ -755,6 +751,11 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||
}
|
||||
|
||||
|
||||
int ctap_user_verification(uint8_t arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ctap_reset_rk(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -32,17 +32,14 @@ static void flash_unlock(void)
|
||||
void flash_option_bytes_init(int boot_from_dfu)
|
||||
{
|
||||
uint32_t val = 0xfffff8aa;
|
||||
if (solo_is_locked()){
|
||||
val = 0xfffff8cc;
|
||||
}
|
||||
|
||||
if (boot_from_dfu){
|
||||
if (boot_from_dfu)
|
||||
{
|
||||
val &= ~(1<<27); // nBOOT0 = 0 (boot from system rom)
|
||||
}
|
||||
else {
|
||||
if (solo_is_locked())
|
||||
{
|
||||
val = 0xfffff8cc;
|
||||
}
|
||||
}
|
||||
|
||||
val &= ~(1<<26); // nSWBOOT0 = 0 (boot from nBoot0)
|
||||
val &= ~(1<<25); // SRAM2_RST = 1 (erase sram on reset)
|
||||
val &= ~(1<<24); // SRAM2_PE = 1 (parity check en)
|
||||
|
@ -4,83 +4,105 @@
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "stm32l4xx.h"
|
||||
#include "stm32l4xx_ll_gpio.h"
|
||||
#include "stm32l4xx_ll_rcc.h"
|
||||
#include "stm32l4xx_ll_system.h"
|
||||
#include "stm32l4xx_ll_pwr.h"
|
||||
#include "stm32l4xx_ll_utils.h"
|
||||
#include "stm32l4xx_ll_cortex.h"
|
||||
#include "stm32l4xx_ll_gpio.h"
|
||||
#include "stm32l4xx_ll_usart.h"
|
||||
#include "stm32l4xx_ll_bus.h"
|
||||
#include "stm32l4xx_ll_usb.h"
|
||||
|
||||
#include "stm32l4xx_hal_pcd.h"
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_desc.h"
|
||||
#include "usbd_hid.h"
|
||||
/*#include "usbd_hid.h"*/
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
//#include "bsp.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
#include APP_CONFIG
|
||||
#include "flash.h"
|
||||
#include "rng.h"
|
||||
#include "led.h"
|
||||
#include "device.h"
|
||||
#include "util.h"
|
||||
#include "fifo.h"
|
||||
#include "log.h"
|
||||
|
||||
#if !defined(TEST)
|
||||
#ifdef TEST_SOLO_STM32
|
||||
#define Error_Handler() _Error_Handler(__FILE__,__LINE__)
|
||||
#define PAGE_SIZE 2048
|
||||
#define PAGES 128
|
||||
// Pages 119-127 are data
|
||||
#define COUNTER2_PAGE (PAGES - 4)
|
||||
#define COUNTER1_PAGE (PAGES - 3)
|
||||
#define STATE2_PAGE (PAGES - 2)
|
||||
#define STATE1_PAGE (PAGES - 1)
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
uint32_t __90_ms = 0;
|
||||
#define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||
|
||||
// Timer6 overflow handler. happens every ~90ms.
|
||||
void TIM6_DAC_IRQHandler()
|
||||
{
|
||||
uint8_t hidmsg[64];
|
||||
uint32_t t1 = 0;
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
//TAG_GEN|
|
||||
// TAG_MC |
|
||||
// TAG_GA |
|
||||
TAG_WALLET |
|
||||
TAG_STOR |
|
||||
//TAG_NFC_APDU |
|
||||
TAG_NFC |
|
||||
//TAG_CP |
|
||||
// TAG_CTAP|
|
||||
//TAG_HID|
|
||||
TAG_U2F|
|
||||
//TAG_PARSE |
|
||||
//TAG_TIME|
|
||||
// TAG_DUMP|
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_EXT|
|
||||
TAG_CCID|
|
||||
TAG_ERR
|
||||
);
|
||||
|
||||
device_init(argc, argv);
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
// timer is only 16 bits, so roll it over here
|
||||
TIM6->SR = 0;
|
||||
__90_ms += 1;
|
||||
}
|
||||
|
||||
uint32_t millis(void)
|
||||
{
|
||||
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
||||
}
|
||||
|
||||
void _Error_Handler(char *file, int line)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if (millis() - t1 > HEARTBEAT_PERIOD)
|
||||
{
|
||||
heartbeat();
|
||||
t1 = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_manage();
|
||||
int main(void)
|
||||
{
|
||||
uint32_t i = 5;
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
hw_init();
|
||||
|
||||
LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT);
|
||||
LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP);
|
||||
flash_option_bytes_init(1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t t0 = millis() % 750;
|
||||
if (! IS_BUTTON_PRESSED())
|
||||
{
|
||||
ctaphid_handle_packet(hidmsg);
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
if (t0 < 750*1/3)
|
||||
{
|
||||
led_rgb(0 | (0 << 8) | (i << 17));
|
||||
}
|
||||
else if (t0 < 750*2/3)
|
||||
{
|
||||
led_rgb(0 | (i << 8) | (0 << 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
led_rgb(i | (0 << 8) | (0 << 16));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
led_rgb(0x151515);
|
||||
}
|
||||
ctaphid_check_timeouts();
|
||||
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
usbhid_close();
|
||||
printf1(TAG_GREEN, "done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,25 +0,0 @@
|
||||
#ifndef _SOLO_H_
|
||||
#define _SOLO_H_
|
||||
|
||||
void device_init();
|
||||
|
||||
void main_loop_delay();
|
||||
void usbhid_init();
|
||||
void usbhid_close();
|
||||
int usbhid_recv(uint8_t * msg);
|
||||
|
||||
void heartbeat();
|
||||
|
||||
// Called each main loop. Doesn't need to do anything.
|
||||
void device_manage();
|
||||
|
||||
void device_init_button();
|
||||
|
||||
// For Solo hacker
|
||||
void boot_solo_bootloader();
|
||||
void boot_st_bootloader();
|
||||
|
||||
|
||||
void delay(uint32_t ms);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user