Compare commits
179 Commits
Author | SHA1 | Date | |
---|---|---|---|
195dc2a8ae | |||
4982b13f64 | |||
63a93f6ec2 | |||
7b8ec18e76 | |||
67faef0117 | |||
0b9f0af3c7 | |||
880d54a4f0 | |||
1507758ad1 | |||
e883c5aa6e | |||
afc85e0d2e | |||
a40dcf3f17 | |||
4b82e80d7a | |||
246dea8a44 | |||
7a98764a5b | |||
dc946f5b35 | |||
0232893611 | |||
5995f84822 | |||
1ff00895b1 | |||
83641b3789 | |||
9b356076c5 | |||
6c96521c7d | |||
35707c3797 | |||
e31e703afd | |||
3a8be9eef7 | |||
e2b30ec087 | |||
495e10f3a1 | |||
11ca6bd517 | |||
a265da09fb | |||
1b4d1be9ee | |||
32f2436380 | |||
7255c4f8db | |||
4e215db42a | |||
a1ad641076 | |||
daf56b0cc7 | |||
5859073cb8 | |||
ff5207ba77 | |||
324b4a89cc | |||
9f60caf9c1 | |||
0865f2a660 | |||
b1c72c9d94 | |||
5e70c11b54 | |||
46ada5a8b9 | |||
0eac67259d | |||
9399a5f195 | |||
47aa287480 | |||
865b698bed | |||
14974e0ebe | |||
1ed7833c9f | |||
e8d0ad5e7c | |||
e2ca7f52db | |||
c97b9f9b8f | |||
ecf994b647 | |||
347d0942b1 | |||
ff0d42c8d5 | |||
a6673b0917 | |||
0c296bba30 | |||
57930aaa13 | |||
1a6895ca25 | |||
54241ecd42 | |||
e537d00173 | |||
a195408a11 | |||
54b7f42056 | |||
6128e86da2 | |||
fed9f473aa | |||
f6ff3c1b87 | |||
afd3218358 | |||
ed6da0ba1e | |||
46d7be865d | |||
596c6c1077 | |||
6c3014575f | |||
190ecc8fd8 | |||
0d2e03a5a9 | |||
991530f88b | |||
de31924be3 | |||
6b97807f51 | |||
35022775cd | |||
6fecb3c035 | |||
3fed8cebdf | |||
c81bc9fb98 | |||
99f09790f1 | |||
6745c9a0cb | |||
0651316da5 | |||
f48becc6dc | |||
85c58e9d5b | |||
c9862977bf | |||
1a40299dcb | |||
8f9ff17bef | |||
9e9d26e604 | |||
b3d76d56e0 | |||
13424fdbcd | |||
3b320e0aeb | |||
529b879c08 | |||
2893cd7ce3 | |||
120fb95541 | |||
665e84d183 | |||
13d9885da4 | |||
e230a9464e | |||
342af18b1f | |||
be9bd941c8 | |||
0f6be6740b | |||
9054736e0e | |||
c6d946136e | |||
32400c8d09 | |||
587c9aad14 | |||
c624a32ef6 | |||
3005a63938 | |||
f470e9a9cd | |||
e3971a5e0f | |||
2ed8667f18 | |||
765d532f82 | |||
ca05385513 | |||
5328610ff1 | |||
bc1bb3509f | |||
375db69e3a | |||
771fffe329 | |||
4611f05051 | |||
e657e26886 | |||
3ffcc47374 | |||
1b5e230d45 | |||
81a89ed6aa | |||
ca2074de36 | |||
ee98340a03 | |||
3d0d91fa5c | |||
38171dba06 | |||
4ba57ccc85 | |||
c3bddee814 | |||
b7bc50bc4f | |||
19627a959a | |||
429e4b2a77 | |||
6e5de7bd6b | |||
c6daa4acc9 | |||
ab01d0c73d | |||
0ef42b2df7 | |||
f6e2bfa683 | |||
5c8acdd666 | |||
e996d470f9 | |||
e2e29492e6 | |||
5f637992b1 | |||
91d092a27a | |||
23cbfde312 | |||
cce25b2a1c | |||
f24058d2e8 | |||
4c941997b4 | |||
2049020b92 | |||
1857482617 | |||
2feef8b043 | |||
3eddfbf8a9 | |||
a662a9a619 | |||
1a656d60e4 | |||
e235402fb8 | |||
6ca9f1946b | |||
df671775ba | |||
3ba83f6407 | |||
ffa4225827 | |||
cde6bc107a | |||
15de8dc4a6 | |||
94fe58d020 | |||
e8634a2d61 | |||
67b0abde4b | |||
d713167ec4 | |||
45888c9a25 | |||
d02206ba09 | |||
ad9186c13b | |||
4e0dc15dfd | |||
dcf7940b3d | |||
1874e11fba | |||
302ce75ce6 | |||
62cd7cc728 | |||
20f8aac768 | |||
121070822f | |||
96f65be9c2 | |||
78c40976c3 | |||
aa978abfc7 | |||
b7c0e4ea92 | |||
6ffba7d472 | |||
c330346c31 | |||
eda26e3c93 | |||
44077a4f2f | |||
4c6f0969c1 |
12
.gitignore
vendored
12
.gitignore
vendored
@ -81,13 +81,5 @@ env3/
|
||||
.tags*
|
||||
targets/*/docs/
|
||||
main
|
||||
targets/efm32/.project
|
||||
targets/efm32/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs
|
||||
targets/efm32/.settings/org.eclipse.cdt.codan.core.prefs
|
||||
targets/efm32/CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.s
|
||||
targets/efm32/CMSIS/EFM32PG1B/system_efm32pg1b.c
|
||||
targets/efm32/EFM32.hwconf
|
||||
targets/efm32/EFM32_EFM32JG1B200F128GM32.hwconf
|
||||
targets/efm32/emlib/em_adc.c
|
||||
targets/efm32/emlib/em_assert.c
|
||||
targets/efm32/emlib/em_cmu.c
|
||||
|
||||
builds/*
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,9 +1,6 @@
|
||||
[submodule "tinycbor"]
|
||||
path = tinycbor
|
||||
url = https://github.com/intel/tinycbor
|
||||
[submodule "python-fido2"]
|
||||
path = python-fido2
|
||||
url = https://github.com/solokeys/python-fido2
|
||||
[submodule "crypto/micro-ecc"]
|
||||
path = crypto/micro-ecc
|
||||
url = https://github.com/kmackay/micro-ecc.git
|
||||
@ -13,3 +10,6 @@
|
||||
[submodule "targets/stm32l442/dfuse-tool"]
|
||||
path = targets/stm32l442/dfuse-tool
|
||||
url = https://github.com/solokeys/dfuse-tool
|
||||
[submodule "crypto/cifra"]
|
||||
path = crypto/cifra
|
||||
url = https://github.com/solokeys/cifra.git
|
||||
|
@ -1,25 +0,0 @@
|
||||
# Notify ModemManager this device should be ignored
|
||||
ACTION!="add|change|move", GOTO="mm_usb_device_blacklist_end"
|
||||
SUBSYSTEM!="usb", GOTO="mm_usb_device_blacklist_end"
|
||||
ENV{DEVTYPE}!="usb_device", GOTO="mm_usb_device_blacklist_end"
|
||||
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
LABEL="mm_usb_device_blacklist_end"
|
||||
|
||||
|
||||
# Solo
|
||||
|
||||
## access
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev"
|
||||
|
||||
## Solo Secure symlink
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo [1-9]*", SYMLINK+="solokey"
|
||||
## Solo Hacker symlink
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo Hacker [1-9]*", SYMLINK+="solohacker"
|
||||
## Solo Serial access + symlink
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="soloserial"
|
||||
|
||||
|
||||
# U2F Zero
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"
|
1
99-solo.rules
Symbolic link
1
99-solo.rules
Symbolic link
@ -0,0 +1 @@
|
||||
udev/70-solokeys-access.rules
|
17
CHANGELOG.md
Normal file
17
CHANGELOG.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.0] - 2019-02-17
|
||||
### Added
|
||||
- Code cleanup
|
||||
- Buffer over-read bug fix
|
||||
- U2F counter endianness bug fix
|
||||
- More testing
|
||||
- Extension interface to U2F and FIDO2
|
||||
- Read firmware version
|
||||
- Read RNG bytes
|
33
Dockerfile
Normal file
33
Dockerfile
Normal file
@ -0,0 +1,33 @@
|
||||
FROM debian:stretch-slim
|
||||
MAINTAINER SoloKeys <hello@solokeys.com>
|
||||
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -qq bzip2 git make wget >/dev/null
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
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
|
17
Makefile
17
Makefile
@ -23,6 +23,7 @@ LDFLAGS += $(LIBCBOR)
|
||||
CFLAGS = -O2 -fdata-sections -ffunction-sections
|
||||
|
||||
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)
|
||||
# for crypto/tiny-AES-c
|
||||
@ -30,7 +31,7 @@ CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\"
|
||||
|
||||
name = main
|
||||
|
||||
.PHONY: all $(LIBCBOR) black blackcheck cppcheck wink fido2-test clean full-clean travis test clean
|
||||
.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:
|
||||
@ -42,6 +43,9 @@ cbor: $(LIBCBOR)
|
||||
$(LIBCBOR):
|
||||
cd tinycbor/ && $(MAKE) clean && $(MAKE) -j8
|
||||
|
||||
version:
|
||||
@git describe
|
||||
|
||||
test: venv
|
||||
$(MAKE) clean
|
||||
$(MAKE) -C . main
|
||||
@ -58,6 +62,7 @@ crypto/micro-ecc/uECC.o: ./crypto/micro-ecc/uECC.c
|
||||
|
||||
venv:
|
||||
python3 -m venv venv
|
||||
venv/bin/pip -q install --upgrade pip
|
||||
venv/bin/pip -q install --upgrade -r tools/requirements.txt
|
||||
venv/bin/pip -q install --upgrade black
|
||||
|
||||
@ -66,11 +71,19 @@ black: venv
|
||||
venv/bin/black --skip-string-normalization --check tools/
|
||||
|
||||
wink: venv
|
||||
venv/bin/python tools/solotool.py solo --wink
|
||||
venv/bin/solo key wink
|
||||
|
||||
fido2-test: venv
|
||||
venv/bin/python tools/ctap_test.py
|
||||
|
||||
DOCKER_IMAGE := "solokeys/solo-firmware:local"
|
||||
SOLO_VERSIONISH := "master"
|
||||
docker-build:
|
||||
docker build -t $(DOCKER_IMAGE) .
|
||||
docker run --rm -v "$(CURDIR)/builds:/builds" \
|
||||
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
|
||||
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
|
||||
|
||||
CPPCHECK_FLAGS=--quiet --error-exitcode=2
|
||||
|
||||
cppcheck:
|
||||
|
@ -35,7 +35,7 @@ Solo for Hacker is a special version of Solo that let you customize its firmware
|
||||
|
||||
You can only buy Solo for Hacker at [solokeys.com](https://solokeys.com), as we don't sell it on Amazon and other places to avoid confusing customers. If you buy a Hacker, you can permanently lock it into a regular Solo, but viceversa you can NOT take a regular Solo and turn it a Hacker.
|
||||
|
||||
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/).
|
||||
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 only support Python3.
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules https://github.com/solokeys/solo
|
||||
@ -43,14 +43,17 @@ cd solo
|
||||
|
||||
cd targets/stm32l432
|
||||
make cbor
|
||||
make all-hacker
|
||||
make build-hacker
|
||||
cd ../..
|
||||
|
||||
make venv
|
||||
source venv/bin/activate
|
||||
python tools/solotool.py program targets/stm32l432/solo.hex
|
||||
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/led.c#L15) and force:
|
||||
|
1
STABLE_VERSION
Normal file
1
STABLE_VERSION
Normal file
@ -0,0 +1 @@
|
||||
1.1.1
|
0
builds/.gitkeep
Normal file
0
builds/.gitkeep
Normal file
1
crypto/cifra
Submodule
1
crypto/cifra
Submodule
Submodule crypto/cifra added at d04dd31860
@ -55,11 +55,11 @@ If you use `DEBUG=2`, that means Solo will not boot until something starts readi
|
||||
it's debug messages. So it basically it waits to tether to a serial terminal so that you don't
|
||||
miss any debug messages.
|
||||
|
||||
We recommend using our `solotool.py` as a serial emulator since it will automatically
|
||||
We recommend using our `solo` tool as a serial emulator since it will automatically
|
||||
reconnect each time you program Solo.
|
||||
|
||||
```
|
||||
python tools/solotool.py monitor <serial-port>
|
||||
solo monitor <serial-port>
|
||||
```
|
||||
|
||||
#### Linux Users:
|
||||
@ -86,7 +86,7 @@ Programming `all.hex` will cause the device to permanently lock itself.
|
||||
It's recommended to test a debug/hacker build first to make sure Solo is working as expected.
|
||||
Then you can switch to a locked down build, which cannot be reprogrammed as easily (or not at all!).
|
||||
|
||||
We recommend using our `solotool.py` to manage programming. It is cross platform. First you must
|
||||
We recommend using our `solo` tool to manage programming. It is cross platform. First you must
|
||||
install the prerequisites:
|
||||
|
||||
```
|
||||
@ -101,7 +101,8 @@ If your Solo device is already programmed (it flashes green when powered), we re
|
||||
programming it using the Solo bootloader.
|
||||
|
||||
```
|
||||
python tools/solotool.py program solo.hex
|
||||
solo program aux enter-bootloader
|
||||
solo program bootloader solo.hex
|
||||
```
|
||||
|
||||
Make sure to program `solo.hex` and not `all.hex`. Nothing bad would happen, but you'd
|
||||
@ -125,7 +126,10 @@ off and it enumerates as "STM BOOTLOADER".
|
||||
You can program it by running the following.
|
||||
|
||||
```
|
||||
python tools/solotool.py program all.hex --use-dfu --detach
|
||||
solo program aux enter-bootloader
|
||||
solo program aux enter-dfu
|
||||
# powercycle key
|
||||
solo program dfu all.hex
|
||||
```
|
||||
|
||||
Make sure to program `all.hex`, as this contains both the bootloader and the Solo application.
|
||||
@ -145,14 +149,14 @@ A locked Solo will only accept signed updates.
|
||||
If this is not a device with a hacker build, you can only program signed updates.
|
||||
|
||||
```
|
||||
python tools/solotool.py program /path/to/firmware.json
|
||||
solo program bootloader /path/to/firmware.json
|
||||
```
|
||||
|
||||
If you've provisioned the Solo bootloader with your own secp256r1 public key, you can sign your
|
||||
firmware by running the following command.
|
||||
|
||||
```
|
||||
python tools/solotool.py sign /path/to/signing-key.pem /path/to/solo.hex /output-path/to/firmware.json
|
||||
solo sign /path/to/signing-key.pem /path/to/solo.hex /output-path/to/firmware.json
|
||||
```
|
||||
|
||||
If your Solo isn't locked, you can always reprogram it using a debugger connected directly
|
||||
@ -175,5 +179,5 @@ If you'd like to also permanently disable signed updates, plug in your programme
|
||||
|
||||
```
|
||||
# WARNING: No more signed updates.
|
||||
python tools/programmer.py --disable
|
||||
solo program disable-bootloader
|
||||
```
|
||||
|
@ -1,13 +1,16 @@
|
||||
# tl;dr
|
||||
|
||||
Create [`/etc/udev/rules.d/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules) and add the following (which assumes your user is in group `plugdev`):
|
||||
Create a file like [`/etc/udev/rules.d/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules), for instance the following rules should cover access in all cases:
|
||||
|
||||
```
|
||||
# Solo
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="solokey"
|
||||
# Solo bootloader + firmware
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev"
|
||||
|
||||
# ST DFU bootloader
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess", GROUP="plugdev"
|
||||
|
||||
# U2F Zero
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"
|
||||
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev"
|
||||
```
|
||||
|
||||
Then run
|
||||
@ -50,7 +53,7 @@ This contains rules for Yubico's keys, the U2F Zero, and many others. The releva
|
||||
```
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
|
||||
```
|
||||
It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as
|
||||
It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as
|
||||
```
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", MODE="0644", GROUP="plugdev"
|
||||
```
|
||||
|
30
fido2/apdu.h
Normal file
30
fido2/apdu.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef _APDU_H_
|
||||
#define _APDU_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cla;
|
||||
uint8_t ins;
|
||||
uint8_t p1;
|
||||
uint8_t p2;
|
||||
uint8_t lc;
|
||||
} __attribute__((packed)) APDU_HEADER;
|
||||
|
||||
#define APDU_FIDO_U2F_REGISTER 0x01
|
||||
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
|
||||
#define APDU_FIDO_U2F_VERSION 0x03
|
||||
#define APDU_FIDO_NFCCTAP_MSG 0x10
|
||||
#define APDU_INS_SELECT 0xA4
|
||||
#define APDU_INS_READ_BINARY 0xB0
|
||||
|
||||
#define SW_SUCCESS 0x9000
|
||||
#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE.
|
||||
#define SW_WRONG_LENGTH 0x6700
|
||||
#define SW_COND_USE_NOT_SATISFIED 0x6985
|
||||
#define SW_FILE_NOT_FOUND 0x6a82
|
||||
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
|
||||
#define SW_INTERNAL_EXCEPTION 0x6f00
|
||||
|
||||
#endif //_APDU_H_
|
@ -60,7 +60,7 @@ static const uint8_t * _signing_key = NULL;
|
||||
static int _key_len = 0;
|
||||
|
||||
// Secrets for testing only
|
||||
static uint8_t master_secret[32];
|
||||
static uint8_t master_secret[64];
|
||||
|
||||
static uint8_t transport_secret[32];
|
||||
|
||||
@ -73,13 +73,17 @@ void crypto_sha256_init()
|
||||
|
||||
void crypto_reset_master_secret()
|
||||
{
|
||||
ctap_generate_rng(master_secret, 32);
|
||||
ctap_generate_rng(master_secret, 64);
|
||||
ctap_generate_rng(transport_secret, 32);
|
||||
}
|
||||
|
||||
void crypto_load_master_secret(uint8_t * key)
|
||||
{
|
||||
memmove(master_secret, key, 32);
|
||||
memmove(transport_secret, key+32, 32);
|
||||
#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)
|
||||
@ -108,7 +112,12 @@ void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||
key = master_secret;
|
||||
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");
|
||||
|
@ -19,6 +19,10 @@ void crypto_sha256_final(uint8_t * hash);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
78
fido2/ctap.c
78
fido2/ctap.c
@ -21,10 +21,10 @@
|
||||
#include "device.h"
|
||||
#include APP_CONFIG
|
||||
#include "wallet.h"
|
||||
#include "extensions.h"
|
||||
|
||||
#include "device.h"
|
||||
|
||||
#define PIN_TOKEN_SIZE 16
|
||||
uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
||||
uint8_t KEY_AGREEMENT_PUB[64];
|
||||
static uint8_t KEY_AGREEMENT_PRIV[32];
|
||||
@ -33,6 +33,9 @@ static int8_t PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||
|
||||
AuthenticatorState STATE;
|
||||
|
||||
|
||||
static void ctap_reset_key_agreement();
|
||||
|
||||
static struct {
|
||||
CTAP_authDataHeader authData;
|
||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||
@ -335,7 +338,12 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||
count = auth_data_update_count(&authData->head);
|
||||
|
||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||
int but = ctap_user_presence_test();
|
||||
// if NFC - not need to click a button
|
||||
int but = 1;
|
||||
if(!device_is_nfc())
|
||||
{
|
||||
but = ctap_user_presence_test();
|
||||
}
|
||||
|
||||
if (!but)
|
||||
{
|
||||
@ -557,6 +565,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
uint8_t * sigder = auth_data_buf + 32 + 64;
|
||||
|
||||
ret = ctap_parse_make_credential(&MC,encoder,request,length);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printf2(TAG_ERR,"error, parse_make_credential failed\n");
|
||||
@ -611,6 +620,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
check_ret(ret);
|
||||
}
|
||||
|
||||
|
||||
CborEncoder map;
|
||||
ret = cbor_encoder_create_map(encoder, &map, 3);
|
||||
check_ret(ret);
|
||||
@ -623,7 +633,6 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
|
||||
crypto_ecc256_load_attestation_key();
|
||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_sz, MC.clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
|
||||
printf1(TAG_MC,"der sig [%d]: ", sigder_sz); dump_hex1(TAG_MC, sigder, sigder_sz);
|
||||
|
||||
ret = ctap_add_attest_statement(&map, sigder, sigder_sz);
|
||||
@ -776,7 +785,18 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA)
|
||||
if (! ctap_authenticate_credential(&GA->rp, &GA->creds[i]))
|
||||
{
|
||||
printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.id.count);
|
||||
GA->creds[i].credential.id.count = 0; // invalidate
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
if (is_extension_request((uint8_t*)&GA->creds[i].credential.id, sizeof(CredentialId)))
|
||||
{
|
||||
printf1(TAG_EXT, "CRED #%d is extension\n", GA->creds[i].credential.id.count);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
GA->creds[i].credential.id.count = 0; // invalidate
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -803,7 +823,7 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA)
|
||||
printf1(TAG_GA, "RK %d is a rpId match!\r\n", i);
|
||||
if (count == ALLOW_LIST_MAX_SIZE-1)
|
||||
{
|
||||
printf2(TAG_ERR, "not enough ram allocated for matching RK's (%d)\r\n", count);
|
||||
printf2(TAG_ERR, "not enough ram allocated for matching RK's (%d). Skipping.\r\n", count);
|
||||
break;
|
||||
}
|
||||
GA->creds[count].type = PUB_KEY_CRED_PUB_KEY;
|
||||
@ -856,6 +876,7 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
||||
int ret;
|
||||
uint8_t sigbuf[64];
|
||||
uint8_t sigder[72];
|
||||
int sigder_sz;
|
||||
|
||||
if (add_user)
|
||||
{
|
||||
@ -869,7 +890,16 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
||||
|
||||
crypto_ecc256_load_key((uint8_t*)&cred->credential.id, sizeof(CredentialId), NULL, 0);
|
||||
|
||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
if ( extend_fido2(&cred->credential.id, sigder) )
|
||||
{
|
||||
sigder_sz = 72;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||
}
|
||||
|
||||
{
|
||||
ret = cbor_encode_int(map, RESP_signature);
|
||||
@ -988,8 +1018,21 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
ret = cbor_encoder_create_map(encoder, &map, map_size);
|
||||
check_ret(ret);
|
||||
|
||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL, 0);
|
||||
check_retr(ret);
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
if ( is_extension_request((uint8_t*)&GA.creds[validCredCount - 1].credential.id, sizeof(CredentialId)) )
|
||||
{
|
||||
ret = cbor_encode_int(&map,RESP_authData);
|
||||
check_ret(ret);
|
||||
memset(auth_data_buf,0,sizeof(auth_data_buf));
|
||||
ret = cbor_encode_byte_string(&map, auth_data_buf, sizeof(auth_data_buf));
|
||||
check_ret(ret);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL, 0);
|
||||
check_retr(ret);
|
||||
}
|
||||
|
||||
/*for (int j = 0; j < GA.credLen; j++)*/
|
||||
/*{*/
|
||||
@ -1147,7 +1190,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
||||
crypto_aes256_decrypt(pinHashEnc, 16);
|
||||
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
||||
{
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
ctap_reset_key_agreement();
|
||||
ctap_decrement_pin_attempts();
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
@ -1190,7 +1233,7 @@ uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubke
|
||||
printf2(TAG_ERR,"platform-pubkey: "); dump_hex1(TAG_ERR, platform_pubkey, 64);
|
||||
printf2(TAG_ERR,"device-pubkey: "); dump_hex1(TAG_ERR, KEY_AGREEMENT_PUB, 64);
|
||||
// Generate new keyAgreement pair
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
ctap_reset_key_agreement();
|
||||
ctap_decrement_pin_attempts();
|
||||
if (ctap_device_boot_locked())
|
||||
{
|
||||
@ -1215,6 +1258,7 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
|
||||
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
|
||||
int ret = ctap_parse_client_pin(&CP,request,length);
|
||||
|
||||
|
||||
switch(CP.subCommand)
|
||||
{
|
||||
case CP_cmdSetPin:
|
||||
@ -1362,6 +1406,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
pkt_raw++;
|
||||
length--;
|
||||
|
||||
|
||||
uint8_t * buf = resp->data;
|
||||
|
||||
cbor_encoder_init(&encoder, buf, resp->data_size, 0);
|
||||
@ -1551,12 +1596,16 @@ void ctap_init()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
if (! device_is_nfc())
|
||||
{
|
||||
ctap_reset_key_agreement();
|
||||
}
|
||||
|
||||
#ifdef BRIDGE_TO_WALLET
|
||||
wallet_init();
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
uint8_t ctap_is_pin_set()
|
||||
@ -1747,7 +1796,10 @@ int8_t ctap_load_key(uint8_t index, uint8_t * key)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ctap_reset_key_agreement()
|
||||
{
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
}
|
||||
|
||||
void ctap_reset()
|
||||
{
|
||||
@ -1764,7 +1816,7 @@ void ctap_reset()
|
||||
|
||||
ctap_reset_state();
|
||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||
ctap_reset_key_agreement();
|
||||
|
||||
crypto_reset_master_secret();
|
||||
}
|
||||
|
@ -521,7 +521,7 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
|
||||
|
||||
if (cbor_value_get_type(&map) != CborBooleanType)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, expecting text string type for rp map value\n");
|
||||
printf2(TAG_ERR,"Error, expecting bool type for option map value\n");
|
||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||
}
|
||||
|
||||
|
159
fido2/ctaphid.c
159
fido2/ctaphid.c
@ -16,6 +16,12 @@
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "extensions.h"
|
||||
|
||||
// move custom SHA512 command out,
|
||||
// and the following headers too
|
||||
#include "sha2.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#include APP_CONFIG
|
||||
|
||||
typedef enum
|
||||
@ -528,6 +534,10 @@ static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * ci
|
||||
return buffer_status();
|
||||
}
|
||||
|
||||
extern void _check_ret(CborError ret, int line, const char * filename);
|
||||
#define check_hardcore(r) _check_ret(r,__LINE__, __FILE__);\
|
||||
if ((r) != CborNoError) exit(1);
|
||||
|
||||
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
{
|
||||
uint8_t cmd;
|
||||
@ -718,6 +728,155 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
is_busy = 0;
|
||||
break;
|
||||
#endif
|
||||
#if defined(SOLO_HACKER) && (DEBUG_LEVEL > 0) && (!IS_BOOTLOADER == 1)
|
||||
case CTAPHID_PROBE:
|
||||
|
||||
/*
|
||||
* Expects CBOR-serialized data of the form
|
||||
* {"subcommand": "hash_type", "data": b"the_data"}
|
||||
* with hash_type in SHA256, SHA512
|
||||
*/
|
||||
|
||||
// some random logging
|
||||
printf1(TAG_HID,"CTAPHID_PROBE\n");
|
||||
// initialise CTAP response object
|
||||
ctap_response_init(&ctap_resp);
|
||||
// initialise write buffer
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_PROBE;
|
||||
|
||||
// prepare parsing (or halt)
|
||||
int ret;
|
||||
CborParser parser;
|
||||
CborValue it, map;
|
||||
ret = cbor_parser_init(
|
||||
ctap_buffer, (size_t) buffer_len(),
|
||||
// strictly speaking, CTAP is not RFC canonical...
|
||||
CborValidateCanonicalFormat,
|
||||
&parser, &it);
|
||||
check_hardcore(ret);
|
||||
|
||||
CborType type = cbor_value_get_type(&it);
|
||||
if (type != CborMapType) exit(1);
|
||||
|
||||
ret = cbor_value_enter_container(&it,&map);
|
||||
check_hardcore(ret);
|
||||
|
||||
size_t map_length = 0;
|
||||
ret = cbor_value_get_map_length(&it, &map_length);
|
||||
if (map_length != 2) exit(1);
|
||||
|
||||
// parse subcommand (or halt)
|
||||
CborValue val;
|
||||
ret = cbor_value_map_find_value(&it, "subcommand", &val);
|
||||
check_hardcore(ret);
|
||||
if (!cbor_value_is_text_string(&val))
|
||||
exit(1);
|
||||
|
||||
int sha_version = 0;
|
||||
bool found = false;
|
||||
if (!found) {
|
||||
ret = cbor_value_text_string_equals(
|
||||
&val, "SHA256", &found);
|
||||
check_hardcore(ret);
|
||||
if (found)
|
||||
sha_version = 256;
|
||||
}
|
||||
if (!found) {
|
||||
ret = cbor_value_text_string_equals(
|
||||
&val, "SHA512", &found);
|
||||
check_hardcore(ret);
|
||||
if (found)
|
||||
sha_version = 512;
|
||||
}
|
||||
if (sha_version == 0)
|
||||
exit(1);
|
||||
|
||||
// parse data (or halt)
|
||||
ret = cbor_value_map_find_value(&it, "data", &val);
|
||||
check_hardcore(ret);
|
||||
if (!cbor_value_is_byte_string(&val))
|
||||
exit(1);
|
||||
|
||||
size_t data_length = 0;
|
||||
ret = cbor_value_calculate_string_length(&val, &data_length);
|
||||
check_hardcore(ret);
|
||||
if (data_length > 6*1024)
|
||||
exit(1);
|
||||
|
||||
unsigned char data[6*1024];
|
||||
ret = cbor_value_copy_byte_string (
|
||||
&val, &data[0], &data_length, &val);
|
||||
check_hardcore(ret);
|
||||
|
||||
// execute subcommand
|
||||
if (sha_version == 256) {
|
||||
// calculate hash
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(data, data_length);
|
||||
crypto_sha256_final(ctap_buffer);
|
||||
// write output
|
||||
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
|
||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
|
||||
}
|
||||
|
||||
if (sha_version == 512) {
|
||||
// calculate hash
|
||||
crypto_sha512_init();
|
||||
crypto_sha512_update(data, data_length);
|
||||
crypto_sha512_final(ctap_buffer);
|
||||
// write output
|
||||
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
|
||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
|
||||
}
|
||||
|
||||
// finalize
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
is_busy = 0;
|
||||
break;
|
||||
|
||||
/*
|
||||
case CTAPHID_SHA256:
|
||||
// some random logging
|
||||
printf1(TAG_HID,"CTAPHID_SHA256\n");
|
||||
// initialise CTAP response object
|
||||
ctap_response_init(&ctap_resp);
|
||||
// initialise write buffer
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_SHA256;
|
||||
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
|
||||
// calculate hash
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(ctap_buffer, buffer_len());
|
||||
crypto_sha256_final(ctap_buffer);
|
||||
// copy to output
|
||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
is_busy = 0;
|
||||
break;
|
||||
case CTAPHID_SHA512:
|
||||
// some random logging
|
||||
printf1(TAG_HID,"CTAPHID_SHA512\n");
|
||||
// initialise CTAP response object
|
||||
ctap_response_init(&ctap_resp);
|
||||
// initialise write buffer
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_SHA512;
|
||||
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
|
||||
// calculate hash
|
||||
crypto_sha512_init();
|
||||
crypto_sha512_update(ctap_buffer, buffer_len());
|
||||
crypto_sha512_final(ctap_buffer);
|
||||
// copy to output
|
||||
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
is_busy = 0;
|
||||
break;
|
||||
*/
|
||||
#endif
|
||||
default:
|
||||
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||
|
@ -28,6 +28,8 @@
|
||||
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
|
||||
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
|
||||
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
|
||||
// reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0
|
||||
#define CTAPHID_PROBE (TYPE_INIT | 0x70)
|
||||
|
||||
#define ERR_INVALID_CMD 0x01
|
||||
#define ERR_INVALID_PAR 0x02
|
||||
|
@ -86,5 +86,22 @@ void boot_st_bootloader();
|
||||
// HID wink command
|
||||
void device_wink();
|
||||
|
||||
typedef enum {
|
||||
DEVICE_LOW_POWER_IDLE = 0,
|
||||
DEVICE_LOW_POWER_FAST = 1,
|
||||
DEVICE_FAST = 2,
|
||||
} DEVICE_CLOCK_RATE;
|
||||
|
||||
// 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 1 if operating in NFC mode.
|
||||
// 0 otherwise.
|
||||
bool device_is_nfc();
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
#include "extensions.h"
|
||||
#include "u2f.h"
|
||||
#include "ctap.h"
|
||||
#include "wallet.h"
|
||||
#include "solo.h"
|
||||
#include "device.h"
|
||||
@ -57,7 +58,8 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
|
||||
#elif defined(WALLET_EXTENSION)
|
||||
ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh);
|
||||
#else
|
||||
ret = bridge_u2f_to_solo(_chal, _appid, klen, keyh);
|
||||
ret = bridge_u2f_to_solo(sig, keyh, klen);
|
||||
u2f_response_writeback(sig,72);
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
@ -74,10 +76,25 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
|
||||
return U2F_SW_NO_ERROR;
|
||||
}
|
||||
|
||||
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
|
||||
// Returns 1 if this is a extension request.
|
||||
// Else 0 if nothing is done.
|
||||
int16_t extend_fido2(CredentialId * credid, uint8_t * output)
|
||||
{
|
||||
if (is_extension_request((uint8_t*)credid, sizeof(CredentialId)))
|
||||
{
|
||||
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len)
|
||||
{
|
||||
|
||||
struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) req->payload;
|
||||
struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) payload;
|
||||
uint16_t rcode;
|
||||
|
||||
if (req->ins == U2F_AUTHENTICATE)
|
||||
@ -93,7 +110,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
|
||||
{
|
||||
rcode = U2F_SW_WRONG_DATA;
|
||||
}
|
||||
printf1(TAG_EXT,"Ignoring U2F request\n");
|
||||
printf1(TAG_EXT,"Ignoring U2F check request\n");
|
||||
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
|
||||
goto end;
|
||||
}
|
||||
@ -101,8 +118,8 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
|
||||
{
|
||||
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
|
||||
{
|
||||
rcode = U2F_SW_WRONG_PAYLOAD;
|
||||
printf1(TAG_EXT, "Ignoring U2F request\n");
|
||||
rcode = U2F_SW_WRONG_DATA;
|
||||
printf1(TAG_EXT, "Ignoring U2F auth request\n");
|
||||
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
|
||||
goto end;
|
||||
}
|
||||
|
@ -7,9 +7,14 @@
|
||||
#ifndef EXTENSIONS_H_
|
||||
#define EXTENSIONS_H_
|
||||
#include "u2f.h"
|
||||
#include "apdu.h"
|
||||
|
||||
int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len);
|
||||
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len);
|
||||
|
||||
int16_t extend_fido2(CredentialId * credid, uint8_t * output);
|
||||
|
||||
int bootloader_bridge(int klen, uint8_t * keyh);
|
||||
|
||||
int is_extension_request(uint8_t * kh, int len);
|
||||
|
||||
#endif /* EXTENSIONS_H_ */
|
||||
|
@ -31,27 +31,26 @@
|
||||
#include "log.h"
|
||||
#include APP_CONFIG
|
||||
|
||||
int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
|
||||
// output must be at least 71 bytes
|
||||
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
|
||||
{
|
||||
static uint8_t msg_buf[72];
|
||||
int8_t ret = 0;
|
||||
|
||||
wallet_request * req = (wallet_request *) keyh;
|
||||
|
||||
printf1(TAG_WALLET, "u2f-solo [%d]: ", klen); dump_hex1(TAG_WALLET, keyh, klen);
|
||||
printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen);
|
||||
|
||||
switch(req->operation)
|
||||
{
|
||||
case WalletVersion:
|
||||
msg_buf[0] = SOLO_VERSION_MAJ;
|
||||
msg_buf[1] = SOLO_VERSION_MIN;
|
||||
msg_buf[2] = SOLO_VERSION_PATCH;
|
||||
u2f_response_writeback(msg_buf, 3);
|
||||
output[0] = SOLO_VERSION_MAJ;
|
||||
output[1] = SOLO_VERSION_MIN;
|
||||
output[2] = SOLO_VERSION_PATCH;
|
||||
break;
|
||||
case WalletRng:
|
||||
printf1(TAG_WALLET,"SoloRng\n");
|
||||
|
||||
ret = ctap_generate_rng(msg_buf, 72);
|
||||
ret = ctap_generate_rng(output, 71);
|
||||
if (ret != 1)
|
||||
{
|
||||
printf1(TAG_WALLET,"Rng failed\n");
|
||||
@ -60,7 +59,6 @@ int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
u2f_response_writeback((uint8_t *)msg_buf,72);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -22,6 +22,6 @@
|
||||
#ifndef SOLO_H_
|
||||
#define SOLO_H_
|
||||
|
||||
int16_t bridge_u2f_to_solo(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh);
|
||||
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen);
|
||||
|
||||
#endif
|
||||
|
@ -47,7 +47,9 @@ struct logtag tagtable[] = {
|
||||
{TAG_WALLET,"[1;34mWALLET[0m"},
|
||||
{TAG_STOR,"[1;35mSTOR[0m"},
|
||||
{TAG_BOOT,"[1;36mBOOT[0m"},
|
||||
{TAG_BOOT,"[1;37mEXT[0m"},
|
||||
{TAG_EXT,"[1;37mEXT[0m"},
|
||||
{TAG_NFC,"[1;38mNFC[0m"},
|
||||
{TAG_NFC_APDU, "NAPDU"},
|
||||
};
|
||||
|
||||
|
||||
@ -68,7 +70,7 @@ void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...)
|
||||
{
|
||||
if (tag & tagtable[i].tagn)
|
||||
{
|
||||
if (tagtable[i].tag[0]) printf("[%s] ", tagtable[i].tag);
|
||||
if (tagtable[i].tag[0] && !(tag & TAG_NO_TAG)) printf("[%s] ", tagtable[i].tag);
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
|
43
fido2/log.h
43
fido2/log.h
@ -23,27 +23,30 @@ void set_logging_tag(uint32_t tag);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TAG_GEN = (1 << 0),
|
||||
TAG_MC = (1 << 1),
|
||||
TAG_GA = (1 << 2),
|
||||
TAG_CP = (1 << 3),
|
||||
TAG_ERR = (1 << 4),
|
||||
TAG_PARSE= (1 << 5),
|
||||
TAG_CTAP = (1 << 6),
|
||||
TAG_U2F = (1 << 7),
|
||||
TAG_DUMP = (1 << 8),
|
||||
TAG_GREEN = (1 << 9),
|
||||
TAG_RED= (1 << 10),
|
||||
TAG_TIME= (1 << 11),
|
||||
TAG_HID = (1 << 12),
|
||||
TAG_USB = (1 << 13),
|
||||
TAG_WALLET = (1 << 14),
|
||||
TAG_STOR = (1 << 15),
|
||||
TAG_DUMP2 = (1 << 16),
|
||||
TAG_BOOT = (1 << 17),
|
||||
TAG_EXT = (1 << 17),
|
||||
TAG_GEN = (1 << 0),
|
||||
TAG_MC = (1 << 1),
|
||||
TAG_GA = (1 << 2),
|
||||
TAG_CP = (1 << 3),
|
||||
TAG_ERR = (1 << 4),
|
||||
TAG_PARSE = (1 << 5),
|
||||
TAG_CTAP = (1 << 6),
|
||||
TAG_U2F = (1 << 7),
|
||||
TAG_DUMP = (1 << 8),
|
||||
TAG_GREEN = (1 << 9),
|
||||
TAG_RED = (1 << 10),
|
||||
TAG_TIME = (1 << 11),
|
||||
TAG_HID = (1 << 12),
|
||||
TAG_USB = (1 << 13),
|
||||
TAG_WALLET = (1 << 14),
|
||||
TAG_STOR = (1 << 15),
|
||||
TAG_DUMP2 = (1 << 16),
|
||||
TAG_BOOT = (1 << 17),
|
||||
TAG_EXT = (1 << 18),
|
||||
TAG_NFC = (1 << 19),
|
||||
TAG_NFC_APDU = (1 << 20),
|
||||
|
||||
TAG_FILENO = (1u << 31)
|
||||
TAG_NO_TAG = (1UL << 30),
|
||||
TAG_FILENO = (1UL << 31)
|
||||
} LOG_TAG;
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
|
48
fido2/main.c
48
fido2/main.c
@ -25,40 +25,33 @@ int main()
|
||||
uint32_t t1 = 0;
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
// TAG_GEN|
|
||||
// TAG_MC |
|
||||
// TAG_GA |
|
||||
TAG_WALLET |
|
||||
TAG_STOR |
|
||||
// TAG_CP |
|
||||
// TAG_CTAP|
|
||||
// TAG_HID|
|
||||
/*TAG_U2F|*/
|
||||
// TAG_PARSE |
|
||||
// TAG_TIME|
|
||||
// TAG_DUMP|
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_ERR
|
||||
);
|
||||
/*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_ERR
|
||||
);
|
||||
|
||||
device_init();
|
||||
printf1(TAG_GEN,"init device\n");
|
||||
|
||||
usbhid_init();
|
||||
printf1(TAG_GEN,"init usb\n");
|
||||
|
||||
|
||||
ctaphid_init();
|
||||
printf1(TAG_GEN,"init ctaphid\n");
|
||||
|
||||
ctap_init();
|
||||
printf1(TAG_GEN,"init ctap\n");
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||
// printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||
|
||||
|
||||
while(1)
|
||||
@ -80,6 +73,7 @@ int main()
|
||||
{
|
||||
}
|
||||
ctaphid_check_timeouts();
|
||||
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
|
78
fido2/u2f.c
78
fido2/u2f.c
@ -10,6 +10,7 @@
|
||||
#include "crypto.h"
|
||||
#include "log.h"
|
||||
#include "device.h"
|
||||
#include "apdu.h"
|
||||
#include "wallet.h"
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
#include "extensions.h"
|
||||
@ -27,12 +28,12 @@ void u2f_reset_response();
|
||||
|
||||
static CTAP_RESPONSE * _u2f_resp = NULL;
|
||||
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPONSE * resp)
|
||||
{
|
||||
uint16_t rcode = 0;
|
||||
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
|
||||
uint8_t byte;
|
||||
|
||||
ctap_response_init(resp);
|
||||
u2f_set_writeback_buffer(resp);
|
||||
|
||||
if (req->cla != 0)
|
||||
@ -42,9 +43,9 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
goto end;
|
||||
}
|
||||
#ifdef ENABLE_U2F_EXTENSIONS
|
||||
rcode = extend_u2f(req, len);
|
||||
rcode = extend_u2f(req, payload, len);
|
||||
#endif
|
||||
if (rcode != U2F_SW_NO_ERROR) // If the extension didn't do anything...
|
||||
if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
|
||||
{
|
||||
#ifdef ENABLE_U2F
|
||||
switch(req->ins)
|
||||
@ -59,7 +60,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
{
|
||||
|
||||
timestamp();
|
||||
rcode = u2f_register((struct u2f_register_request*)req->payload);
|
||||
rcode = u2f_register((struct u2f_register_request*)payload);
|
||||
printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp());
|
||||
|
||||
}
|
||||
@ -67,7 +68,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
case U2F_AUTHENTICATE:
|
||||
printf1(TAG_U2F, "U2F_AUTHENTICATE\n");
|
||||
timestamp();
|
||||
rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1);
|
||||
rcode = u2f_authenticate((struct u2f_authenticate_request*)payload, req->p1);
|
||||
printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp());
|
||||
break;
|
||||
case U2F_VERSION:
|
||||
@ -109,6 +110,22 @@ end:
|
||||
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
|
||||
}
|
||||
|
||||
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp)
|
||||
{
|
||||
if (len < 5 || !req)
|
||||
return;
|
||||
|
||||
uint32_t alen = req[4];
|
||||
|
||||
u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp);
|
||||
}
|
||||
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
{
|
||||
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
|
||||
|
||||
u2f_request_ex((APDU_HEADER *)req, req->payload, len, resp);
|
||||
}
|
||||
|
||||
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len)
|
||||
{
|
||||
@ -156,7 +173,7 @@ static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8
|
||||
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
|
||||
}
|
||||
|
||||
static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey)
|
||||
int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey)
|
||||
{
|
||||
ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE);
|
||||
u2f_make_auth_tag(kh, appid, kh->tag);
|
||||
@ -196,6 +213,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
||||
|
||||
if (control == U2F_AUTHENTICATE_CHECK)
|
||||
{
|
||||
printf1(TAG_U2F, "CHECK-ONLY\r\n");
|
||||
if (u2f_appid_eq(&req->kh, req->app) == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
@ -206,42 +224,47 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
||||
}
|
||||
}
|
||||
if (
|
||||
control != U2F_AUTHENTICATE_SIGN ||
|
||||
req->khl != U2F_KEY_HANDLE_SIZE ||
|
||||
(control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) ||
|
||||
req->khl != U2F_KEY_HANDLE_SIZE ||
|
||||
u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important
|
||||
u2f_load_key(&req->kh, req->app) != 0
|
||||
|
||||
)
|
||||
{
|
||||
return U2F_SW_WRONG_PAYLOAD;
|
||||
return U2F_SW_WRONG_DATA;
|
||||
}
|
||||
|
||||
// dont-enforce-user-presence-and-sign
|
||||
if (control == U2F_AUTHENTICATE_SIGN_NO_USER)
|
||||
up = 0;
|
||||
|
||||
|
||||
if (ctap_user_presence_test() == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
if(!device_is_nfc() && up)
|
||||
{
|
||||
if (ctap_user_presence_test() == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
count = ctap_atomic_count(0);
|
||||
hash[0] = (count >> 24) & 0xff;
|
||||
hash[0] = 0x7f;
|
||||
hash[1] = (count >> 16) & 0xff;
|
||||
hash[2] = (count >> 8) & 0xff;
|
||||
hash[3] = (count >> 0) & 0xff;
|
||||
crypto_sha256_init();
|
||||
|
||||
crypto_sha256_update(req->app,32);
|
||||
crypto_sha256_update(&up,1);
|
||||
crypto_sha256_update(hash,4);
|
||||
crypto_sha256_update(req->chal,32);
|
||||
crypto_sha256_update(req->app, 32);
|
||||
crypto_sha256_update(&up, 1);
|
||||
crypto_sha256_update(hash, 4);
|
||||
crypto_sha256_update(req->chal, 32);
|
||||
|
||||
crypto_sha256_final(hash);
|
||||
|
||||
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F,hash,32);
|
||||
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F, hash, 32);
|
||||
crypto_ecc256_sign(hash, 32, sig);
|
||||
|
||||
u2f_response_writeback(&up,1);
|
||||
hash[0] = (count >> 24) & 0xff;
|
||||
hash[0] = 0x7f;
|
||||
hash[1] = (count >> 16) & 0xff;
|
||||
hash[2] = (count >> 8) & 0xff;
|
||||
hash[3] = (count >> 0) & 0xff;
|
||||
@ -263,10 +286,13 @@ static int16_t u2f_register(struct u2f_register_request * req)
|
||||
|
||||
const uint16_t attest_size = attestation_cert_der_size;
|
||||
|
||||
if ( ! ctap_user_presence_test())
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
if(!device_is_nfc())
|
||||
{
|
||||
if ( ! ctap_user_presence_test())
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1)
|
||||
{
|
||||
|
11
fido2/u2f.h
11
fido2/u2f.h
@ -38,16 +38,16 @@
|
||||
// U2F Authenticate
|
||||
#define U2F_AUTHENTICATE_CHECK 0x7
|
||||
#define U2F_AUTHENTICATE_SIGN 0x3
|
||||
#define U2F_AUTHENTICATE_SIGN_NO_USER 0x8
|
||||
|
||||
|
||||
// Command status responses
|
||||
#define U2F_SW_NO_ERROR 0x9000
|
||||
#define U2F_SW_WRONG_DATA 0x6984
|
||||
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985
|
||||
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00
|
||||
#define U2F_SW_WRONG_LENGTH 0x6700
|
||||
#define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00
|
||||
#define U2F_SW_WRONG_PAYLOAD 0x6a80
|
||||
#define U2F_SW_WRONG_DATA 0x6a80
|
||||
#define U2F_SW_INSUFFICIENT_MEMORY 0x9210
|
||||
|
||||
// Delay in milliseconds to wait for user input
|
||||
@ -95,9 +95,14 @@ struct u2f_authenticate_request
|
||||
};
|
||||
|
||||
// u2f_request send a U2F message to U2F protocol
|
||||
// @req U2F message
|
||||
// @req U2F message
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
|
||||
|
||||
// u2f_request send a U2F message to NFC protocol
|
||||
// @req data with iso7816 apdu message
|
||||
// @len data length
|
||||
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp);
|
||||
|
||||
|
||||
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
||||
void u2f_reset_response();
|
||||
|
44
in-docker-build.sh
Executable file
44
in-docker-build.sh
Executable file
@ -0,0 +1,44 @@
|
||||
#!/bin/bash -xe
|
||||
|
||||
version=${1:-master}
|
||||
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
|
||||
|
||||
cd /solo/targets/stm32l432
|
||||
git fetch --tags
|
||||
git checkout ${version}
|
||||
version=$(git describe)
|
||||
|
||||
make cbor
|
||||
|
||||
out_dir="/builds"
|
||||
|
||||
function build() {
|
||||
part=${1}
|
||||
variant=${2}
|
||||
output=${3:-${part}}
|
||||
what="${part}-${variant}"
|
||||
|
||||
make full-clean
|
||||
|
||||
make ${what}
|
||||
|
||||
out_hex="${what}-${version}.hex"
|
||||
out_sha2="${what}-${version}.sha2"
|
||||
|
||||
mv ${output}.hex ${out_hex}
|
||||
sha256sum ${out_hex} > ${out_sha2}
|
||||
cp ${out_hex} ${out_sha2} ${out_dir}
|
||||
}
|
||||
|
||||
build bootloader nonverifying
|
||||
build bootloader verifying
|
||||
build firmware hacker solo
|
||||
build firmware secure solo
|
||||
|
||||
pip install -U pip
|
||||
pip install -U solo-python
|
||||
cd ${out_dir}
|
||||
bundle="bundle-hacker-${version}"
|
||||
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-${version}.hex ${bundle}.hex
|
||||
sha256sum ${bundle}.hex > ${bundle}.sha2
|
118
pc/device.c
118
pc/device.c
@ -22,6 +22,11 @@
|
||||
#include "log.h"
|
||||
#include "ctaphid.h"
|
||||
|
||||
#define RK_NUM 50
|
||||
|
||||
struct ResidentKeyStore {
|
||||
CTAP_residentKey rks[RK_NUM];
|
||||
} RK_STORE;
|
||||
|
||||
void authenticator_initialize();
|
||||
|
||||
@ -141,11 +146,20 @@ void usbhid_init()
|
||||
int usbhid_recv(uint8_t * msg)
|
||||
{
|
||||
int l = udp_recv(serverfd, msg, HID_MESSAGE_SIZE);
|
||||
/*if (l && l != HID_MESSAGE_SIZE)*/
|
||||
/*{*/
|
||||
/*printf("Error, recv'd message of wrong size %d", l);*/
|
||||
/*exit(1);*/
|
||||
/*}*/
|
||||
uint8_t magic_cmd[] = "\xac\x10\x52\xca\x95\xe5\x69\xde\x69\xe0\x2e\xbf"
|
||||
"\xf3\x33\x48\x5f\x13\xf9\xb2\xda\x34\xc5\xa8\xa3"
|
||||
"\x40\x52\x66\x97\xa9\xab\x2e\x0b\x39\x4d\x8d\x04"
|
||||
"\x97\x3c\x13\x40\x05\xbe\x1a\x01\x40\xbf\xf6\x04"
|
||||
"\x5b\xb2\x6e\xb7\x7a\x73\xea\xa4\x78\x13\xf6\xb4"
|
||||
"\x9a\x72\x50\xdc";
|
||||
if ( memcmp(magic_cmd, msg, 64) == 0 )
|
||||
{
|
||||
printf1(TAG_RED, "MAGIC REBOOT command recieved!\r\n");
|
||||
memset(msg,0,64);
|
||||
exit(100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -174,6 +188,10 @@ void device_init()
|
||||
usbhid_init();
|
||||
|
||||
authenticator_initialize();
|
||||
|
||||
ctaphid_init();
|
||||
|
||||
ctap_init( 1 );
|
||||
}
|
||||
|
||||
|
||||
@ -181,7 +199,7 @@ void main_loop_delay()
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1000*1000*25;
|
||||
ts.tv_nsec = 1000*1000*100;
|
||||
nanosleep(&ts,NULL);
|
||||
}
|
||||
|
||||
@ -247,6 +265,7 @@ 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";
|
||||
|
||||
void authenticator_read_state(AuthenticatorState * state)
|
||||
{
|
||||
@ -366,6 +385,24 @@ int authenticator_is_backup_initialized()
|
||||
|
||||
/*}*/
|
||||
|
||||
static void sync_rk()
|
||||
{
|
||||
FILE * f = fopen(rk_file, "wb+");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ret = fwrite(&RK_STORE, 1, sizeof(RK_STORE), f);
|
||||
fclose(f);
|
||||
if (ret != sizeof(RK_STORE))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void authenticator_initialize()
|
||||
{
|
||||
uint8_t header[16];
|
||||
@ -389,6 +426,22 @@ void authenticator_initialize()
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// resident_keys
|
||||
f = fopen(rk_file, "rb");
|
||||
if (f== NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
ret = fread(&RK_STORE, 1, sizeof(RK_STORE), f);
|
||||
fclose(f);
|
||||
if(ret != sizeof(RK_STORE))
|
||||
{
|
||||
perror("fwrite");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -427,6 +480,12 @@ void authenticator_initialize()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// resident_keys
|
||||
memset(&RK_STORE,0xff,sizeof(RK_STORE));
|
||||
sync_rk();
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,29 +494,60 @@ void device_manage()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ctap_reset_rk()
|
||||
{
|
||||
memset(&RK_STORE,0xff,sizeof(RK_STORE));
|
||||
sync_rk();
|
||||
|
||||
}
|
||||
|
||||
uint32_t ctap_rk_size()
|
||||
{
|
||||
printf("Warning: rk not implemented\n");
|
||||
return 0;
|
||||
return RK_NUM;
|
||||
}
|
||||
void ctap_store_rk(int index,CTAP_residentKey * rk)
|
||||
|
||||
|
||||
void ctap_store_rk(int index, CTAP_residentKey * rk)
|
||||
{
|
||||
printf("Warning: rk not implemented\n");
|
||||
if (index < RK_NUM)
|
||||
{
|
||||
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
|
||||
sync_rk();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
|
||||
}
|
||||
|
||||
}
|
||||
void ctap_load_rk(int index,CTAP_residentKey * rk)
|
||||
|
||||
|
||||
void ctap_load_rk(int index, CTAP_residentKey * rk)
|
||||
{
|
||||
printf("Warning: rk not implemented\n");
|
||||
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey));
|
||||
}
|
||||
void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
|
||||
|
||||
void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
|
||||
{
|
||||
printf("Warning: rk not implemented\n");
|
||||
if (index < RK_NUM)
|
||||
{
|
||||
memmove(RK_STORE.rks + index, rk, sizeof(CTAP_residentKey));
|
||||
sync_rk();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_ERR,"Out of bounds for store_rk\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void device_wink()
|
||||
{
|
||||
printf("*WINK*\n");
|
||||
}
|
||||
|
||||
bool device_is_nfc()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
Submodule python-fido2 deleted from 329434fdd4
@ -5,10 +5,35 @@ endif
|
||||
APPMAKE=build/application.mk
|
||||
BOOTMAKE=build/bootloader.mk
|
||||
|
||||
merge_hex=../../tools/solotool.py mergehex
|
||||
merge_hex=solo mergehex
|
||||
|
||||
.PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor test
|
||||
|
||||
|
||||
# The following are the main targets for reproducible builds.
|
||||
# TODO: better explanation
|
||||
firmware-hacker:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-hacker-debug-1:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=1 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
firmware-hacker-debug-2:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=2 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0'
|
||||
|
||||
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
|
||||
|
||||
bootloader-verifying:
|
||||
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) DEBUG=0
|
||||
|
||||
full-clean: clean2
|
||||
|
||||
|
||||
# The older targets, may be re-organised
|
||||
all:
|
||||
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DFLASH_ROP=1'
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
||||
#define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION
|
||||
|
||||
void printing_init();
|
||||
void hw_init(void);
|
||||
void hw_init(int lf);
|
||||
|
||||
// Trigger software reset
|
||||
void device_reboot();
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "stm32l4xx_ll_rcc.h"
|
||||
#include "stm32l4xx_ll_gpio.h"
|
||||
#include "stm32l4xx.h"
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
@ -17,14 +21,13 @@
|
||||
#include "ctap.h"
|
||||
#include "app.h"
|
||||
#include "memory_layout.h"
|
||||
#include "stm32l4xx_ll_rcc.h"
|
||||
#include "init.h"
|
||||
|
||||
#include "stm32l4xx.h"
|
||||
|
||||
uint8_t REBOOT_FLAG = 0;
|
||||
|
||||
|
||||
void BOOT_boot(void)
|
||||
void BOOT_boot(void)
|
||||
{
|
||||
typedef void (*pFunction)(void);
|
||||
|
||||
@ -69,7 +72,16 @@ int main()
|
||||
TAG_ERR
|
||||
);
|
||||
|
||||
device_init();
|
||||
// device_init();
|
||||
|
||||
init_gpio();
|
||||
|
||||
init_millisecond_timer(1);
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
init_debug_uart();
|
||||
#endif
|
||||
|
||||
printf1(TAG_GEN,"init device\n");
|
||||
|
||||
t1 = millis();
|
||||
@ -107,7 +119,13 @@ int main()
|
||||
#ifdef SOLO_HACKER
|
||||
start_bootloader:
|
||||
#endif
|
||||
SystemClock_Config();
|
||||
init_gpio();
|
||||
init_millisecond_timer(0);
|
||||
init_pwm();
|
||||
init_rng();
|
||||
usbhid_init();
|
||||
|
||||
printf1(TAG_GEN,"init usb\n");
|
||||
|
||||
ctaphid_init();
|
||||
|
@ -2,9 +2,9 @@ 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/crypto.c src/attestation.c
|
||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/nfc.c src/ams.c
|
||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c)
|
||||
SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
# FIDO2 lib
|
||||
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
||||
@ -14,6 +14,7 @@ SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.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
|
||||
|
||||
OBJ1=$(SRC:.c=.o)
|
||||
OBJ=$(OBJ1:.s=.o)
|
||||
@ -21,6 +22,7 @@ OBJ=$(OBJ1:.s=.o)
|
||||
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
|
||||
|
||||
SEARCH=-L../../tinycbor/lib
|
||||
|
||||
@ -41,12 +43,14 @@ DEBUG=0
|
||||
endif
|
||||
|
||||
DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES)
|
||||
# DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1
|
||||
|
||||
CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS)
|
||||
CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections \
|
||||
-fomit-frame-pointer $(HW) -g $(VERSION_FLAGS)
|
||||
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys
|
||||
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor
|
||||
|
||||
ECC_CFLAGS = $(CFLAGS) -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0
|
||||
|
||||
|
||||
.PRECIOUS: %.o
|
||||
|
||||
@ -57,7 +61,7 @@ all: $(TARGET).elf
|
||||
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
|
||||
|
||||
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
|
||||
$(CC) $^ $(HW) -O3 $(CFLAGS) -o $@
|
||||
$(CC) $^ $(HW) -O3 $(ECC_CFLAGS) -o $@
|
||||
|
||||
%.o: %.s
|
||||
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
|
||||
@ -66,6 +70,7 @@ all: $(TARGET).elf
|
||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: %.elf
|
||||
$(SZ) $^
|
||||
$(CP) -O ihex $^ $(TARGET).hex
|
||||
|
||||
clean:
|
||||
|
@ -5,7 +5,7 @@ SRC = bootloader/main.c bootloader/bootloader.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/crypto.c src/attestation.c
|
||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c)
|
||||
SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
# FIDO2 lib
|
||||
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/extensions/extensions.c
|
||||
@ -13,6 +13,7 @@ SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2
|
||||
|
||||
# Crypto libs
|
||||
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c
|
||||
SRC += ../../crypto/cifra/src/sha512.c ../../crypto/cifra/src/blockwise.c
|
||||
|
||||
OBJ1=$(SRC:.c=.o)
|
||||
OBJ=$(OBJ1:.s=.o)
|
||||
@ -21,6 +22,7 @@ OBJ=$(OBJ1:.s=.o)
|
||||
INC = -Ibootloader/ -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
|
||||
|
||||
ifndef LDSCRIPT
|
||||
LDSCRIPT=linker/bootloader_stm32l4xx.ld
|
||||
|
@ -3,6 +3,15 @@ CP=$(PREFIX)arm-none-eabi-objcopy
|
||||
SZ=$(PREFIX)arm-none-eabi-size
|
||||
AR=$(PREFIX)arm-none-eabi-ar
|
||||
|
||||
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 \
|
||||
lib/stm32l4xx_ll_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \
|
||||
lib/stm32l4xx_ll_usart.c lib/stm32l4xx_ll_spi.c
|
||||
|
||||
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
|
||||
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
|
||||
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c
|
||||
|
||||
VERSION:=$(shell git describe --abbrev=0 )
|
||||
VERSION_FULL:=$(shell git describe)
|
||||
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
|
||||
@ -10,7 +19,7 @@ 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) -DVERSION=\"$(VERSION_FULL)\"
|
||||
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
|
||||
|
||||
_all:
|
||||
echo $(VERSION_FULL)
|
||||
|
307
targets/stm32l432/lib/stm32l4xx_ll_spi.c
Normal file
307
targets/stm32l432/lib/stm32l4xx_ll_spi.c
Normal file
@ -0,0 +1,307 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32l4xx_ll_spi.c
|
||||
* @author MCD Application Team
|
||||
* @brief SPI LL module driver.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#if defined(USE_FULL_LL_DRIVER)
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32l4xx_ll_spi.h"
|
||||
#include "stm32l4xx_ll_bus.h"
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
#include "stm32_assert.h"
|
||||
#else
|
||||
#define assert_param(expr) ((void)0U)
|
||||
#endif
|
||||
|
||||
/** @addtogroup STM32L4xx_LL_Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined (SPI1) || defined (SPI2) || defined (SPI3)
|
||||
|
||||
/** @addtogroup SPI_LL
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private types -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* Private constants ---------------------------------------------------------*/
|
||||
/** @defgroup SPI_LL_Private_Constants SPI Private Constants
|
||||
* @{
|
||||
*/
|
||||
/* SPI registers Masks */
|
||||
#define SPI_CR1_CLEAR_MASK (SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_MSTR | \
|
||||
SPI_CR1_BR | SPI_CR1_LSBFIRST | SPI_CR1_SSI | \
|
||||
SPI_CR1_SSM | SPI_CR1_RXONLY | SPI_CR1_CRCL | \
|
||||
SPI_CR1_CRCNEXT | SPI_CR1_CRCEN | SPI_CR1_BIDIOE | \
|
||||
SPI_CR1_BIDIMODE)
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Private macros ------------------------------------------------------------*/
|
||||
/** @defgroup SPI_LL_Private_Macros SPI Private Macros
|
||||
* @{
|
||||
*/
|
||||
#define IS_LL_SPI_TRANSFER_DIRECTION(__VALUE__) (((__VALUE__) == LL_SPI_FULL_DUPLEX) \
|
||||
|| ((__VALUE__) == LL_SPI_SIMPLEX_RX) \
|
||||
|| ((__VALUE__) == LL_SPI_HALF_DUPLEX_RX) \
|
||||
|| ((__VALUE__) == LL_SPI_HALF_DUPLEX_TX))
|
||||
|
||||
#define IS_LL_SPI_MODE(__VALUE__) (((__VALUE__) == LL_SPI_MODE_MASTER) \
|
||||
|| ((__VALUE__) == LL_SPI_MODE_SLAVE))
|
||||
|
||||
#define IS_LL_SPI_DATAWIDTH(__VALUE__) (((__VALUE__) == LL_SPI_DATAWIDTH_4BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_5BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_6BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_7BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_8BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_9BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_10BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_11BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_12BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_13BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_14BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_15BIT) \
|
||||
|| ((__VALUE__) == LL_SPI_DATAWIDTH_16BIT))
|
||||
|
||||
#define IS_LL_SPI_POLARITY(__VALUE__) (((__VALUE__) == LL_SPI_POLARITY_LOW) \
|
||||
|| ((__VALUE__) == LL_SPI_POLARITY_HIGH))
|
||||
|
||||
#define IS_LL_SPI_PHASE(__VALUE__) (((__VALUE__) == LL_SPI_PHASE_1EDGE) \
|
||||
|| ((__VALUE__) == LL_SPI_PHASE_2EDGE))
|
||||
|
||||
#define IS_LL_SPI_NSS(__VALUE__) (((__VALUE__) == LL_SPI_NSS_SOFT) \
|
||||
|| ((__VALUE__) == LL_SPI_NSS_HARD_INPUT) \
|
||||
|| ((__VALUE__) == LL_SPI_NSS_HARD_OUTPUT))
|
||||
|
||||
#define IS_LL_SPI_BAUDRATE(__VALUE__) (((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV2) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV4) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV8) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV16) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV32) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV64) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV128) \
|
||||
|| ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV256))
|
||||
|
||||
#define IS_LL_SPI_BITORDER(__VALUE__) (((__VALUE__) == LL_SPI_LSB_FIRST) \
|
||||
|| ((__VALUE__) == LL_SPI_MSB_FIRST))
|
||||
|
||||
#define IS_LL_SPI_CRCCALCULATION(__VALUE__) (((__VALUE__) == LL_SPI_CRCCALCULATION_ENABLE) \
|
||||
|| ((__VALUE__) == LL_SPI_CRCCALCULATION_DISABLE))
|
||||
|
||||
#define IS_LL_SPI_CRC_POLYNOMIAL(__VALUE__) ((__VALUE__) >= 0x1U)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
/** @addtogroup SPI_LL_Exported_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup SPI_LL_EF_Init
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief De-initialize the SPI registers to their default reset values.
|
||||
* @param SPIx SPI Instance
|
||||
* @retval An ErrorStatus enumeration value:
|
||||
* - SUCCESS: SPI registers are de-initialized
|
||||
* - ERROR: SPI registers are not de-initialized
|
||||
*/
|
||||
ErrorStatus LL_SPI_DeInit(SPI_TypeDef *SPIx)
|
||||
{
|
||||
ErrorStatus status = ERROR;
|
||||
|
||||
/* Check the parameters */
|
||||
assert_param(IS_SPI_ALL_INSTANCE(SPIx));
|
||||
|
||||
#if defined(SPI1)
|
||||
if (SPIx == SPI1)
|
||||
{
|
||||
/* Force reset of SPI clock */
|
||||
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
|
||||
|
||||
/* Release reset of SPI clock */
|
||||
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
|
||||
|
||||
status = SUCCESS;
|
||||
}
|
||||
#endif /* SPI1 */
|
||||
#if defined(SPI2)
|
||||
if (SPIx == SPI2)
|
||||
{
|
||||
/* Force reset of SPI clock */
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
|
||||
|
||||
/* Release reset of SPI clock */
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
|
||||
|
||||
status = SUCCESS;
|
||||
}
|
||||
#endif /* SPI2 */
|
||||
#if defined(SPI3)
|
||||
if (SPIx == SPI3)
|
||||
{
|
||||
/* Force reset of SPI clock */
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI3);
|
||||
|
||||
/* Release reset of SPI clock */
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI3);
|
||||
|
||||
status = SUCCESS;
|
||||
}
|
||||
#endif /* SPI3 */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the SPI registers according to the specified parameters in SPI_InitStruct.
|
||||
* @note As some bits in SPI configuration registers can only be written when the SPI is disabled (SPI_CR1_SPE bit =0),
|
||||
* SPI IP should be in disabled state prior calling this function. Otherwise, ERROR result will be returned.
|
||||
* @param SPIx SPI Instance
|
||||
* @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure
|
||||
* @retval An ErrorStatus enumeration value. (Return always SUCCESS)
|
||||
*/
|
||||
ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct)
|
||||
{
|
||||
ErrorStatus status = ERROR;
|
||||
|
||||
/* Check the SPI Instance SPIx*/
|
||||
assert_param(IS_SPI_ALL_INSTANCE(SPIx));
|
||||
|
||||
/* Check the SPI parameters from SPI_InitStruct*/
|
||||
assert_param(IS_LL_SPI_TRANSFER_DIRECTION(SPI_InitStruct->TransferDirection));
|
||||
assert_param(IS_LL_SPI_MODE(SPI_InitStruct->Mode));
|
||||
assert_param(IS_LL_SPI_DATAWIDTH(SPI_InitStruct->DataWidth));
|
||||
assert_param(IS_LL_SPI_POLARITY(SPI_InitStruct->ClockPolarity));
|
||||
assert_param(IS_LL_SPI_PHASE(SPI_InitStruct->ClockPhase));
|
||||
assert_param(IS_LL_SPI_NSS(SPI_InitStruct->NSS));
|
||||
assert_param(IS_LL_SPI_BAUDRATE(SPI_InitStruct->BaudRate));
|
||||
assert_param(IS_LL_SPI_BITORDER(SPI_InitStruct->BitOrder));
|
||||
assert_param(IS_LL_SPI_CRCCALCULATION(SPI_InitStruct->CRCCalculation));
|
||||
|
||||
if (LL_SPI_IsEnabled(SPIx) == 0x00000000U)
|
||||
{
|
||||
/*---------------------------- SPIx CR1 Configuration ------------------------
|
||||
* Configure SPIx CR1 with parameters:
|
||||
* - TransferDirection: SPI_CR1_BIDIMODE, SPI_CR1_BIDIOE and SPI_CR1_RXONLY bits
|
||||
* - Master/Slave Mode: SPI_CR1_MSTR bit
|
||||
* - ClockPolarity: SPI_CR1_CPOL bit
|
||||
* - ClockPhase: SPI_CR1_CPHA bit
|
||||
* - NSS management: SPI_CR1_SSM bit
|
||||
* - BaudRate prescaler: SPI_CR1_BR[2:0] bits
|
||||
* - BitOrder: SPI_CR1_LSBFIRST bit
|
||||
* - CRCCalculation: SPI_CR1_CRCEN bit
|
||||
*/
|
||||
MODIFY_REG(SPIx->CR1,
|
||||
SPI_CR1_CLEAR_MASK,
|
||||
SPI_InitStruct->TransferDirection | SPI_InitStruct->Mode |
|
||||
SPI_InitStruct->ClockPolarity | SPI_InitStruct->ClockPhase |
|
||||
SPI_InitStruct->NSS | SPI_InitStruct->BaudRate |
|
||||
SPI_InitStruct->BitOrder | SPI_InitStruct->CRCCalculation);
|
||||
|
||||
/*---------------------------- SPIx CR2 Configuration ------------------------
|
||||
* Configure SPIx CR2 with parameters:
|
||||
* - DataWidth: DS[3:0] bits
|
||||
* - NSS management: SSOE bit
|
||||
*/
|
||||
MODIFY_REG(SPIx->CR2,
|
||||
SPI_CR2_DS | SPI_CR2_SSOE,
|
||||
SPI_InitStruct->DataWidth | (SPI_InitStruct->NSS >> 16U));
|
||||
|
||||
/*---------------------------- SPIx CRCPR Configuration ----------------------
|
||||
* Configure SPIx CRCPR with parameters:
|
||||
* - CRCPoly: CRCPOLY[15:0] bits
|
||||
*/
|
||||
if (SPI_InitStruct->CRCCalculation == LL_SPI_CRCCALCULATION_ENABLE)
|
||||
{
|
||||
assert_param(IS_LL_SPI_CRC_POLYNOMIAL(SPI_InitStruct->CRCPoly));
|
||||
LL_SPI_SetCRCPolynomial(SPIx, SPI_InitStruct->CRCPoly);
|
||||
}
|
||||
status = SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set each @ref LL_SPI_InitTypeDef field to default value.
|
||||
* @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure
|
||||
* whose fields will be set to default values.
|
||||
* @retval None
|
||||
*/
|
||||
void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct)
|
||||
{
|
||||
/* Set SPI_InitStruct fields to default values */
|
||||
SPI_InitStruct->TransferDirection = LL_SPI_FULL_DUPLEX;
|
||||
SPI_InitStruct->Mode = LL_SPI_MODE_SLAVE;
|
||||
SPI_InitStruct->DataWidth = LL_SPI_DATAWIDTH_8BIT;
|
||||
SPI_InitStruct->ClockPolarity = LL_SPI_POLARITY_LOW;
|
||||
SPI_InitStruct->ClockPhase = LL_SPI_PHASE_1EDGE;
|
||||
SPI_InitStruct->NSS = LL_SPI_NSS_HARD_INPUT;
|
||||
SPI_InitStruct->BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
|
||||
SPI_InitStruct->BitOrder = LL_SPI_MSB_FIRST;
|
||||
SPI_InitStruct->CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
|
||||
SPI_InitStruct->CRCPoly = 7U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* defined (SPI1) || defined (SPI2) || defined (SPI3) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* USE_FULL_LL_DRIVER */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
1436
targets/stm32l432/lib/stm32l4xx_ll_spi.h
Normal file
1436
targets/stm32l432/lib/stm32l4xx_ll_spi.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -821,12 +821,16 @@ void USBD_CtlError( USBD_HandleTypeDef *pdev ,
|
||||
* @param len : descriptor length
|
||||
* @retval None
|
||||
*/
|
||||
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
|
||||
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t unicode_size, uint16_t *len)
|
||||
{
|
||||
uint8_t idx = 0U;
|
||||
|
||||
if (desc != NULL)
|
||||
{
|
||||
if ((idx + 4) >= unicode_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
*len = (uint16_t)USBD_GetLen(desc) * 2U + 2U;
|
||||
unicode[idx++] = *(uint8_t *)(void *)len;
|
||||
unicode[idx++] = USB_DESC_TYPE_STRING;
|
||||
|
@ -108,7 +108,7 @@ void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
|
||||
|
||||
void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata);
|
||||
|
||||
void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len);
|
||||
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t unicode_size, uint16_t *len);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -108,7 +108,7 @@ const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC]=
|
||||
HIBYTE(USBD_LANGID_STRING),
|
||||
};
|
||||
|
||||
uint8_t USBD_StrDesc[32];
|
||||
uint8_t USBD_StrDesc[48];
|
||||
|
||||
/**
|
||||
* @brief Returns the device descriptor.
|
||||
@ -142,7 +142,7 @@ uint8_t *USBD_HID_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
*/
|
||||
uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
|
||||
USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, sizeof(USBD_StrDesc), length);
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length
|
||||
*/
|
||||
uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
|
||||
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, sizeof(USBD_StrDesc), length);
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
@ -166,6 +166,32 @@ uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *l
|
||||
*/
|
||||
uint8_t *USBD_HID_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_SERIAL_NUM, USBD_StrDesc, length);
|
||||
return USBD_StrDesc;
|
||||
// Match the same alg as the DFU to make serial number
|
||||
volatile uint8_t * UUID = (volatile uint8_t *)0x1FFF7590;
|
||||
const char hexdigit[] = "0123456789ABCDEF";
|
||||
uint8_t uuid[6];
|
||||
uint8_t uuid_str[13];
|
||||
uint8_t c;
|
||||
int i;
|
||||
uuid_str[12] = 0;
|
||||
|
||||
uuid[0] = UUID[11];
|
||||
uuid[1] = UUID[10] + UUID[2];
|
||||
uuid[2] = UUID[9];
|
||||
uuid[3] = UUID[8] + UUID[0];
|
||||
uuid[4] = UUID[7];
|
||||
uuid[5] = UUID[6];
|
||||
|
||||
// quick method to convert to hex string
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
c = (uuid[i]>>4) & 0x0f;
|
||||
uuid_str[i * 2 + 0] = hexdigit[ c ];
|
||||
c = (uuid[i]>>0) & 0x0f;
|
||||
uuid_str[i * 2 + 1] = hexdigit[ c ];
|
||||
}
|
||||
|
||||
|
||||
USBD_GetString((uint8_t *)uuid_str, USBD_StrDesc, sizeof(USBD_StrDesc), length);
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
366
targets/stm32l432/src/ams.c
Normal file
366
targets/stm32l432/src/ams.c
Normal file
@ -0,0 +1,366 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "stm32l4xx_ll_spi.h"
|
||||
|
||||
#include "ams.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "device.h"
|
||||
#include "nfc.h"
|
||||
|
||||
static void flush_rx()
|
||||
{
|
||||
while(LL_SPI_IsActiveFlag_RXNE(SPI1) != 0)
|
||||
{
|
||||
LL_SPI_ReceiveData8(SPI1);
|
||||
}
|
||||
}
|
||||
static void wait_for_tx()
|
||||
{
|
||||
// while (LL_SPI_IsActiveFlag_BSY(SPI1) == 1)
|
||||
// ;
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY)
|
||||
;
|
||||
}
|
||||
static void wait_for_rx()
|
||||
{
|
||||
while(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void ams_print_device(AMS_DEVICE * dev)
|
||||
{
|
||||
printf1(TAG_NFC, "AMS_DEVICE:\r\n");
|
||||
printf1(TAG_NFC, " io_conf: %02x\r\n",dev->regs.io_conf);
|
||||
printf1(TAG_NFC, " ic_conf0: %02x\r\n",dev->regs.ic_conf0);
|
||||
printf1(TAG_NFC, " ic_conf1: %02x\r\n",dev->regs.ic_conf1);
|
||||
printf1(TAG_NFC, " ic_conf2: %02x\r\n",dev->regs.ic_conf2);
|
||||
printf1(TAG_NFC, " rfid_status: %02x\r\n",dev->regs.rfid_status);
|
||||
printf1(TAG_NFC, " ic_status: %02x\r\n",dev->regs.ic_status);
|
||||
printf1(TAG_NFC, " mask_int0: %02x\r\n",dev->regs.mask_int0);
|
||||
printf1(TAG_NFC, " mask_int1: %02x\r\n",dev->regs.mask_int1);
|
||||
printf1(TAG_NFC, " int0: %02x\r\n",dev->regs.int0);
|
||||
printf1(TAG_NFC, " int1: %02x\r\n",dev->regs.int1);
|
||||
printf1(TAG_NFC, " buffer_status2: %02x\r\n",dev->regs.buffer_status2);
|
||||
printf1(TAG_NFC, " buffer_status1: %02x\r\n",dev->regs.buffer_status1);
|
||||
printf1(TAG_NFC, " last_nfc_addr: %02x\r\n",dev->regs.last_nfc_addr);
|
||||
printf1(TAG_NFC, " product_type: %02x\r\n",dev->regs.product_type);
|
||||
printf1(TAG_NFC, " product_subtype:%02x\r\n",dev->regs.product_subtype);
|
||||
printf1(TAG_NFC, " version_maj: %02x\r\n",dev->regs.version_maj);
|
||||
printf1(TAG_NFC, " version_min: %02x\r\n",dev->regs.version_min);
|
||||
}
|
||||
|
||||
static uint8_t send_recv(uint8_t b)
|
||||
{
|
||||
wait_for_tx();
|
||||
LL_SPI_TransmitData8(SPI1, b);
|
||||
wait_for_rx();
|
||||
b = LL_SPI_ReceiveData8(SPI1);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
void ams_write_reg(uint8_t addr, uint8_t tx)
|
||||
{
|
||||
send_recv(0x00| addr);
|
||||
send_recv(tx);
|
||||
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
|
||||
uint8_t ams_read_reg(uint8_t addr)
|
||||
{
|
||||
send_recv(0x20| (addr & 0x1f));
|
||||
uint8_t data = send_recv(0);
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// data must be 14 bytes long
|
||||
void read_reg_block(AMS_DEVICE * dev)
|
||||
{
|
||||
int i;
|
||||
uint8_t mode = 0x20 | (4 );
|
||||
flush_rx();
|
||||
|
||||
send_recv(mode);
|
||||
for (i = 0x04; i < 0x0d; i++)
|
||||
{
|
||||
dev->buf[i] = send_recv(0);
|
||||
}
|
||||
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
void ams_read_buffer(uint8_t * data, int len)
|
||||
{
|
||||
send_recv(0xa0);
|
||||
while(len--)
|
||||
{
|
||||
*data++ = send_recv(0x00);
|
||||
}
|
||||
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
void ams_write_buffer(uint8_t * data, int len)
|
||||
{
|
||||
send_recv(0x80);
|
||||
while(len--)
|
||||
{
|
||||
send_recv(*data++);
|
||||
}
|
||||
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
// data must be 4 bytes
|
||||
void ams_read_eeprom_block(uint8_t block, uint8_t * data)
|
||||
{
|
||||
send_recv(0x7f);
|
||||
send_recv(block << 1);
|
||||
|
||||
data[0] = send_recv(0);
|
||||
data[1] = send_recv(0);
|
||||
data[2] = send_recv(0);
|
||||
data[3] = send_recv(0);
|
||||
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
|
||||
// data must be 4 bytes
|
||||
void ams_write_eeprom_block(uint8_t block, uint8_t * data)
|
||||
{
|
||||
send_recv(0x40);
|
||||
send_recv(block << 1);
|
||||
|
||||
send_recv(data[0]);
|
||||
send_recv(data[1]);
|
||||
send_recv(data[2]);
|
||||
send_recv(data[3]);
|
||||
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
void ams_write_command(uint8_t cmd)
|
||||
{
|
||||
send_recv(0xc0 | cmd);
|
||||
UNSELECT();
|
||||
SELECT();
|
||||
}
|
||||
|
||||
const char * ams_get_state_string(uint8_t regval)
|
||||
{
|
||||
if (regval & AMS_STATE_INVALID)
|
||||
{
|
||||
return "STATE_INVALID";
|
||||
}
|
||||
switch (regval & AMS_STATE_MASK)
|
||||
{
|
||||
case AMS_STATE_OFF:
|
||||
return "STATE_OFF";
|
||||
case AMS_STATE_SENSE:
|
||||
return "STATE_SENSE";
|
||||
case AMS_STATE_RESOLUTION:
|
||||
return "STATE_RESOLUTION";
|
||||
case AMS_STATE_RESOLUTION_L2:
|
||||
return "STATE_RESOLUTION_L2";
|
||||
case AMS_STATE_SELECTED:
|
||||
return "STATE_SELECTED";
|
||||
case AMS_STATE_SECTOR2:
|
||||
return "STATE_SECTOR2";
|
||||
case AMS_STATE_SECTORX_2:
|
||||
return "STATE_SECTORX_2";
|
||||
case AMS_STATE_SELECTEDX:
|
||||
return "STATE_SELECTEDX";
|
||||
case AMS_STATE_SENSEX_L2:
|
||||
return "STATE_SENSEX_L2";
|
||||
case AMS_STATE_SENSEX:
|
||||
return "STATE_SENSEX";
|
||||
case AMS_STATE_SLEEP:
|
||||
return "STATE_SLEEP";
|
||||
}
|
||||
return "STATE_WRONG";
|
||||
}
|
||||
|
||||
int ams_state_is_valid(uint8_t regval)
|
||||
{
|
||||
if (regval & AMS_STATE_INVALID)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
switch (regval & AMS_STATE_MASK)
|
||||
{
|
||||
case AMS_STATE_OFF:
|
||||
case AMS_STATE_SENSE:
|
||||
case AMS_STATE_RESOLUTION:
|
||||
case AMS_STATE_RESOLUTION_L2:
|
||||
case AMS_STATE_SELECTED:
|
||||
case AMS_STATE_SECTOR2:
|
||||
case AMS_STATE_SECTORX_2:
|
||||
case AMS_STATE_SELECTEDX:
|
||||
case AMS_STATE_SENSEX_L2:
|
||||
case AMS_STATE_SENSEX:
|
||||
case AMS_STATE_SLEEP:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ams_print_int0(uint8_t int0)
|
||||
{
|
||||
#if DEBUG_LEVEL
|
||||
uint32_t tag = (TAG_NFC)|(TAG_NO_TAG);
|
||||
printf1(TAG_NFC," ");
|
||||
if (int0 & AMS_INT_XRF)
|
||||
printf1(tag," XRF");
|
||||
if (int0 & AMS_INT_TXE)
|
||||
printf1(tag," TXE");
|
||||
if (int0 & AMS_INT_RXE)
|
||||
printf1(tag," RXE");
|
||||
if (int0 & AMS_INT_EER_RF)
|
||||
printf1(tag," EER_RF");
|
||||
if (int0 & AMS_INT_EEW_RF)
|
||||
printf1(tag," EEW_RF");
|
||||
if (int0 & AMS_INT_SLP)
|
||||
printf1(tag," SLP");
|
||||
if (int0 & AMS_INT_WU_A)
|
||||
printf1(tag," WU_A");
|
||||
if (int0 & AMS_INT_INIT)
|
||||
printf1(tag," INIT");
|
||||
|
||||
printf1(tag,"\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ams_print_int1(uint8_t int0)
|
||||
{
|
||||
#if DEBUG_LEVEL
|
||||
uint32_t tag = (TAG_NFC)|(TAG_NO_TAG);
|
||||
printf1(TAG_NFC," ");
|
||||
if (int0 & AMS_INT_ACC_ERR)
|
||||
printf1(tag," ACC_ERR");
|
||||
if (int0 & AMS_INT_EEAC_ERR)
|
||||
printf1(tag," EEAC_ERR");
|
||||
if (int0 & AMS_INT_IO_EEWR)
|
||||
printf1(tag," IO_EEWR");
|
||||
if (int0 & AMS_INT_BF_ERR)
|
||||
printf1(tag," BF_ERR");
|
||||
if (int0 & AMS_INT_CRC_ERR)
|
||||
printf1(tag," CRC_ERR");
|
||||
if (int0 & AMS_INT_PAR_ERR)
|
||||
printf1(tag," PAR_ERR");
|
||||
if (int0 & AMS_INT_FRM_ERR)
|
||||
printf1(tag," FRM_ERR");
|
||||
if (int0 & AMS_INT_RXS)
|
||||
printf1(tag," RXS");
|
||||
|
||||
printf1(tag,"\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ams_init()
|
||||
{
|
||||
LL_GPIO_SetPinMode(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN,LL_GPIO_MODE_OUTPUT);
|
||||
LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN);
|
||||
|
||||
LL_SPI_SetClockPolarity(SPI1,LL_SPI_POLARITY_LOW);
|
||||
LL_SPI_SetClockPhase(SPI1,LL_SPI_PHASE_2EDGE);
|
||||
LL_SPI_SetRxFIFOThreshold(SPI1,LL_SPI_RX_FIFO_TH_QUARTER);
|
||||
LL_SPI_Enable(SPI1);
|
||||
|
||||
// delay(10);
|
||||
SELECT();
|
||||
delay(1);
|
||||
}
|
||||
|
||||
void ams_configure()
|
||||
{
|
||||
// Should not be used during passive operation.
|
||||
uint8_t block[4];
|
||||
|
||||
// check connection
|
||||
uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE);
|
||||
if (productType != 0x14)
|
||||
{
|
||||
printf1(TAG_ERR, "Have wrong product type [0x%02x]. AMS3956 connection error.\n", productType);
|
||||
}
|
||||
|
||||
printf1(TAG_NFC,"AMS3956 product type 0x%02x.\n", productType);
|
||||
|
||||
ams_read_eeprom_block(AMS_CONFIG_UID_ADDR, block);
|
||||
printf1(TAG_NFC,"UID: 3F 14 02 - "); dump_hex1(TAG_NFC,block,4);
|
||||
|
||||
ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block);
|
||||
printf1(TAG_NFC,"conf0: "); dump_hex1(TAG_NFC,block,4);
|
||||
|
||||
uint8_t sense1 = 0x44;
|
||||
uint8_t sense2 = 0x00;
|
||||
uint8_t selr = 0x20; // SAK
|
||||
|
||||
if(block[0] != sense1 || block[1] != sense2 || block[2] != selr)
|
||||
{
|
||||
printf1(TAG_NFC,"Writing config block 0\r\n");
|
||||
block[0] = sense1;
|
||||
block[1] = sense2;
|
||||
block[2] = selr;
|
||||
block[3] = 0x00;
|
||||
|
||||
ams_write_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block);
|
||||
UNSELECT();
|
||||
delay(10);
|
||||
SELECT();
|
||||
delay(10);
|
||||
|
||||
ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block);
|
||||
printf1(TAG_NFC,"conf0: "); dump_hex1(TAG_NFC,block,4);
|
||||
}
|
||||
|
||||
ams_read_eeprom_block(AMS_CONFIG_BLOCK1_ADDR, block);
|
||||
printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4);
|
||||
|
||||
uint8_t ic_cfg1 = AMS_CFG1_OUTPUT_RESISTANCE_100 | AMS_CFG1_VOLTAGE_LEVEL_2V0;
|
||||
uint8_t ic_cfg2 = AMS_CFG2_TUN_MOD;
|
||||
|
||||
if (block[0] != ic_cfg1 || block[1] != ic_cfg2)
|
||||
{
|
||||
|
||||
printf1(TAG_NFC,"Writing config block 1\r\n");
|
||||
|
||||
ams_write_reg(AMS_REG_IC_CONF1,ic_cfg1);
|
||||
ams_write_reg(AMS_REG_IC_CONF2,ic_cfg2);
|
||||
|
||||
// set IC_CFG1
|
||||
block[0] = ic_cfg1;
|
||||
|
||||
// set IC_CFG2
|
||||
block[1] = ic_cfg2;
|
||||
|
||||
// mask interrupt bits
|
||||
block[2] = 0x80;
|
||||
block[3] = 0;
|
||||
|
||||
ams_write_eeprom_block(AMS_CONFIG_BLOCK1_ADDR, block);
|
||||
|
||||
UNSELECT();
|
||||
delay(10);
|
||||
SELECT();
|
||||
delay(10);
|
||||
|
||||
ams_read_eeprom_block(0x7F, block);
|
||||
printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4);
|
||||
}
|
||||
|
||||
|
||||
}
|
162
targets/stm32l432/src/ams.h
Normal file
162
targets/stm32l432/src/ams.h
Normal file
@ -0,0 +1,162 @@
|
||||
// AS3956 interface
|
||||
// https://ams.com/as3956
|
||||
// https://ams.com/documents/20143/36005/AS3956_DS000546_7-00.pdf
|
||||
|
||||
#ifndef _AMS_H_
|
||||
#define _AMS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "stm32l4xx_ll_gpio.h"
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t buf[0x20];
|
||||
struct {
|
||||
uint8_t io_conf; // 0x00
|
||||
uint8_t ic_conf0; // 0x01
|
||||
uint8_t ic_conf1; // 0x02
|
||||
uint8_t ic_conf2; // 0x03
|
||||
uint8_t rfid_status; // 0x04
|
||||
uint8_t ic_status; // 0x05
|
||||
uint8_t _nc0[2]; // 0x06 - 0x07
|
||||
uint8_t mask_int0; // 0x08
|
||||
uint8_t mask_int1; // 0x09
|
||||
uint8_t int0; // 0x0a
|
||||
uint8_t int1; // 0x0b
|
||||
uint8_t buffer_status2; // 0x0c
|
||||
uint8_t buffer_status1; // 0x0d
|
||||
uint8_t last_nfc_addr; // 0x0e
|
||||
uint8_t _nc1[0x1b - 0x0f + 1]; // 0x0f - 0x1b
|
||||
uint8_t product_type; // 0x1c
|
||||
uint8_t product_subtype; // 0x1d
|
||||
uint8_t version_maj; // 0x1e
|
||||
uint8_t version_min; // 0x1f
|
||||
} regs;
|
||||
} __attribute__((packed)) AMS_DEVICE;
|
||||
|
||||
#define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
||||
#define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
||||
|
||||
void ams_init();
|
||||
void ams_configure();
|
||||
|
||||
void ams_read_buffer(uint8_t * data, int len);
|
||||
void ams_write_buffer(uint8_t * data, int len);
|
||||
|
||||
void ams_write_command(uint8_t cmd);
|
||||
|
||||
void read_reg_block(AMS_DEVICE * dev);
|
||||
|
||||
uint8_t ams_read_reg(uint8_t addr);
|
||||
|
||||
void ams_write_reg(uint8_t addr, uint8_t tx);
|
||||
|
||||
const char * ams_get_state_string(uint8_t regval);
|
||||
int ams_state_is_valid(uint8_t regval);
|
||||
|
||||
|
||||
#define AMS_REG_IO_CONF 0x00
|
||||
#define AMS_REG_IC_CONF0 0x01
|
||||
#define AMS_REG_IC_CONF1 0x02
|
||||
#define AMS_REG_IC_CONF2 0x03
|
||||
#define AMS_RFCFG_EN 0x80
|
||||
#define AMS_TUN_MOD 0x40
|
||||
#define AMS_REG_RFID_STATUS 0x04
|
||||
#define AMS_HF_PON 0x80
|
||||
#define AMS_STATE_MASK 0x78
|
||||
#define AMS_STATE_INVALID 0x04
|
||||
#define AMS_STATE_OFF (0 << 3)
|
||||
#define AMS_STATE_SENSE (1 << 3)
|
||||
#define AMS_STATE_RESOLUTION (3 << 3)
|
||||
#define AMS_STATE_RESOLUTION_L2 (2 << 3)
|
||||
#define AMS_STATE_SELECTED (6 << 3)
|
||||
#define AMS_STATE_SECTOR2 (7 << 3)
|
||||
#define AMS_STATE_SECTORX_2 (0xf << 3)
|
||||
#define AMS_STATE_SELECTEDX (0xe << 3)
|
||||
#define AMS_STATE_SENSEX_L2 (0xa << 3)
|
||||
#define AMS_STATE_SENSEX (0xb << 3)
|
||||
#define AMS_STATE_SLEEP (0x9 << 3)
|
||||
// ... //
|
||||
#define AMS_REG_MASK_INT0 0x08
|
||||
#define AMS_MASK0_PU (1<<7) // power up
|
||||
#define AMS_MASK0_WU_A (1<<6) // selected INT
|
||||
#define AMS_MASK0_SLP (1<<5)
|
||||
#define AMS_MASK0_EEW_RF (1<<4)
|
||||
#define AMS_MASK0_EER_RF (1<<3)
|
||||
#define AMS_MASK0_RXE (1<<2)
|
||||
#define AMS_MASK0_TXE (1<<1)
|
||||
#define AMS_MASK0_XRF (1<<0)
|
||||
#define AMS_REG_MASK_INT1 0x09
|
||||
#define AMS_REG_INT0 0x0a
|
||||
#define AMS_INT_XRF (1<<0)
|
||||
#define AMS_INT_TXE (1<<1)
|
||||
#define AMS_INT_RXE (1<<2)
|
||||
#define AMS_INT_EER_RF (1<<3)
|
||||
#define AMS_INT_EEW_RF (1<<4)
|
||||
#define AMS_INT_SLP (1<<5)
|
||||
#define AMS_INT_WU_A (1<<6)
|
||||
#define AMS_INT_INIT (1<<7)
|
||||
#define AMS_REG_INT1 0x0b
|
||||
#define AMS_INT_ACC_ERR (1<<0)
|
||||
#define AMS_INT_EEAC_ERR (1<<1)
|
||||
#define AMS_INT_IO_EEWR (1<<2)
|
||||
#define AMS_INT_BF_ERR (1<<3)
|
||||
#define AMS_INT_CRC_ERR (1<<4)
|
||||
#define AMS_INT_PAR_ERR (1<<5)
|
||||
#define AMS_INT_FRM_ERR (1<<6)
|
||||
#define AMS_INT_RXS (1<<7)
|
||||
#define AMS_REG_BUF2 0x0c
|
||||
#define AMS_BUF_LEN_MASK 0x1f
|
||||
#define AMS_BUF_INVALID 0x80
|
||||
#define AMS_REG_BUF1 0x0d
|
||||
// ... //
|
||||
#define AMS_REG_PRODUCT_TYPE 0x1c
|
||||
#define AMS_REG_PRODUCT_SUBTYPE 0x1d
|
||||
#define AMS_REG_VERSION_MAJOR 0x1e
|
||||
#define AMS_REG_VERSION_MINOR 0x1f
|
||||
|
||||
#define AMS_CONFIG_UID_ADDR 0x00
|
||||
#define AMS_CONFIG_BLOCK0_ADDR 0x7e
|
||||
#define AMS_CONFIG_BLOCK1_ADDR 0x7f
|
||||
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_1V9 (0x00<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V0 (0x01<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V1 (0x02<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V2 (0x03<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V3 (0x04<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V4 (0x05<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V5 (0x06<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V6 (0x07<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V7 (0x08<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V8 (0x09<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_2V9 (0x0a<<2)
|
||||
#define AMS_CFG1_VOLTAGE_LEVEL_3V0 (0x0b<<2)
|
||||
|
||||
#define AMS_CFG1_OUTPUT_RESISTANCE_ZZ 0x00
|
||||
#define AMS_CFG1_OUTPUT_RESISTANCE_100 0x01
|
||||
#define AMS_CFG1_OUTPUT_RESISTANCE_50 0x02
|
||||
#define AMS_CFG1_OUTPUT_RESISTANCE_25 0x03
|
||||
|
||||
#define AMS_CFG2_RFCFG_EN (1<<7)
|
||||
#define AMS_CFG2_TUN_MOD (1<<6)
|
||||
|
||||
#define AMS_CMD_DEFAULT 0x02
|
||||
#define AMS_CMD_CLEAR_BUFFER 0x04
|
||||
#define AMS_CMD_RESTART_TRANSCEIVER 0x06
|
||||
#define AMS_CMD_DIS_EN_TRANSCEIVER 0x07
|
||||
#define AMS_CMD_TRANSMIT_BUFFER 0x08
|
||||
#define AMS_CMD_TRANSMIT_ACK 0x09
|
||||
#define AMS_CMD_TRANSMIT_NACK0 0x0A
|
||||
#define AMS_CMD_TRANSMIT_NACK1 0x0B
|
||||
#define AMS_CMD_TRANSMIT_NACK4 0x0D
|
||||
#define AMS_CMD_TRANSMIT_NACK5 0x0C
|
||||
#define AMS_CMD_SLEEP 0x10
|
||||
#define AMS_CMD_SENSE 0x11
|
||||
#define AMS_CMD_SENSE_SLEEP 0x12
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -30,6 +30,7 @@
|
||||
// #define DISABLE_CTAPHID_WINK
|
||||
// #define DISABLE_CTAPHID_CBOR
|
||||
|
||||
#define ENABLE_SERIAL_PRINTING
|
||||
|
||||
#if defined(SOLO_HACKER)
|
||||
#define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION
|
||||
@ -38,7 +39,7 @@
|
||||
#endif
|
||||
|
||||
void printing_init();
|
||||
void hw_init(void);
|
||||
void hw_init(int lf);
|
||||
|
||||
//#define TEST
|
||||
//#define TEST_POWER
|
||||
@ -63,6 +64,12 @@ void hw_init(void);
|
||||
#define SOLO_BUTTON_PORT GPIOA
|
||||
#define SOLO_BUTTON_PIN LL_GPIO_PIN_0
|
||||
|
||||
#define SOLO_AMS_CS_PORT GPIOB
|
||||
#define SOLO_AMS_CS_PIN LL_GPIO_PIN_0
|
||||
|
||||
#define SOLO_AMS_IRQ_PORT GPIOC
|
||||
#define SOLO_AMS_IRQ_PIN LL_GPIO_PIN_15
|
||||
|
||||
#define SKIP_BUTTON_CHECK_WITH_DELAY 0
|
||||
#define SKIP_BUTTON_CHECK_FAST 0
|
||||
|
||||
|
@ -7,6 +7,50 @@
|
||||
#include <stdint.h>
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef USE_SOLOKEYS_CERT
|
||||
|
||||
const uint8_t attestation_cert_der[] =
|
||||
"\x30\x82\x02\xe1\x30\x82\x02\x88\xa0\x03\x02\x01\x02\x02\x01\x01\x30\x0a\x06\x08"
|
||||
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x81\x80\x31\x0b\x30\x09\x06\x03\x55\x04\x06"
|
||||
"\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4d\x61\x72\x79\x6c"
|
||||
"\x61\x6e\x64\x31\x12\x30\x10\x06\x03\x55\x04\x0a\x0c\x09\x53\x6f\x6c\x6f\x20\x4b"
|
||||
"\x65\x79\x73\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x52\x6f\x6f\x74\x20\x43"
|
||||
"\x41\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0c\x0c\x73\x6f\x6c\x6f\x6b\x65\x79\x73"
|
||||
"\x2e\x63\x6f\x6d\x31\x21\x30\x1f\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16"
|
||||
"\x12\x68\x65\x6c\x6c\x6f\x40\x73\x6f\x6c\x6f\x6b\x65\x79\x73\x2e\x63\x6f\x6d\x30"
|
||||
"\x20\x17\x0d\x31\x38\x31\x31\x31\x31\x31\x32\x35\x32\x30\x30\x5a\x18\x0f\x32\x30"
|
||||
"\x36\x38\x31\x30\x32\x39\x31\x32\x35\x32\x30\x30\x5a\x30\x81\x92\x31\x0b\x30\x09"
|
||||
"\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08"
|
||||
"\x4d\x61\x72\x79\x6c\x61\x6e\x64\x31\x12\x30\x10\x06\x03\x55\x04\x0a\x0c\x09\x53"
|
||||
"\x6f\x6c\x6f\x20\x4b\x65\x79\x73\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\x15\x30\x13\x06\x03\x55\x04\x03\x0c\x0c\x73\x6f\x6c\x6f\x6b"
|
||||
"\x65\x79\x73\x2e\x63\x6f\x6d\x31\x21\x30\x1f\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01"
|
||||
"\x09\x01\x16\x12\x68\x65\x6c\x6c\x6f\x40\x73\x6f\x6c\x6f\x6b\x65\x79\x73\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\x22\xfe\x0f\xb5\x2a\x78\xbe\xc6\x45\x37\x1a"
|
||||
"\x28\xa7\x57\x43\x49\xa4\x6f\x85\x4d\xca\x4e\x25\x1c\x9f\x75\x30\x3d\xbf\x10\xd5"
|
||||
"\xd2\xd2\x0b\xb9\x69\x2c\xdd\xb2\x5c\x14\xd8\x39\x85\x12\xf6\x23\xee\x91\xba\xc6"
|
||||
"\xac\xff\x4a\x1a\x27\xef\xe0\xc1\x54\x3f\xd4\xd9\xc5\xa3\x81\xdc\x30\x81\xd9\x30"
|
||||
"\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x3b\xe6\xd2\xc0\x6f\xf2\xe7\xb0\x7c\x9d"
|
||||
"\x9e\x28\xc0\x20\xb0\x0d\x07\xc8\x15\xc8\x30\x81\x9f\x06\x03\x55\x1d\x23\x04\x81"
|
||||
"\x97\x30\x81\x94\xa1\x81\x86\xa4\x81\x83\x30\x81\x80\x31\x0b\x30\x09\x06\x03\x55"
|
||||
"\x04\x06\x13\x02\x55\x53\x31\x11\x30\x0f\x06\x03\x55\x04\x08\x0c\x08\x4d\x61\x72"
|
||||
"\x79\x6c\x61\x6e\x64\x31\x12\x30\x10\x06\x03\x55\x04\x0a\x0c\x09\x53\x6f\x6c\x6f"
|
||||
"\x20\x4b\x65\x79\x73\x31\x10\x30\x0e\x06\x03\x55\x04\x0b\x0c\x07\x52\x6f\x6f\x74"
|
||||
"\x20\x43\x41\x31\x15\x30\x13\x06\x03\x55\x04\x03\x0c\x0c\x73\x6f\x6c\x6f\x6b\x65"
|
||||
"\x79\x73\x2e\x63\x6f\x6d\x31\x21\x30\x1f\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09"
|
||||
"\x01\x16\x12\x68\x65\x6c\x6c\x6f\x40\x73\x6f\x6c\x6f\x6b\x65\x79\x73\x2e\x63\x6f"
|
||||
"\x6d\x82\x09\x00\xc4\x47\x63\x92\x8f\xf4\xbe\x8c\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\x47\x00\x30\x44\x02\x20\x71\x10\x46\x2c\xf5"
|
||||
"\x16\x18\x97\x55\xca\x64\x50\x3b\x69\xb2\xdf\x17\x71\xab\xad\x8e\xc0\xd6\xa6\x07"
|
||||
"\x3d\x66\x8a\x3b\xbb\xfe\x61\x02\x20\x1e\x82\xef\xeb\x5e\x4e\x3a\x00\x84\x64\xd2"
|
||||
"\xf8\x84\xc3\x78\x35\x93\x63\x81\x2e\xbe\xa6\x12\x32\x6e\x29\x90\xc8\x91\x4b\x71"
|
||||
"\x52"
|
||||
;
|
||||
#else
|
||||
|
||||
// For testing/development only
|
||||
|
||||
const uint8_t attestation_cert_der[] =
|
||||
@ -50,9 +94,8 @@ const uint8_t attestation_cert_der[] =
|
||||
"\xf3\x87\x61\x82\xd8\xcd\x48\xfc\x57"
|
||||
;
|
||||
|
||||
#endif
|
||||
|
||||
const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
|
||||
|
||||
|
||||
const uint8_t attestation_key[] = "\x1b\x26\x26\xec\xc8\xf6\x9b\x0f\x69\xe3\x4f\xb2\x36\xd7\x64\x66\xba\x12\xac\x16\xc3\xab\x57\x50\xba\x06\x4e\x8b\x90\xe0\x24\x48";
|
||||
const uint16_t attestation_key_size = sizeof(attestation_key)-1;
|
||||
const uint16_t attestation_key_size = 32;
|
||||
|
@ -24,6 +24,9 @@
|
||||
#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"
|
||||
@ -48,6 +51,7 @@ typedef enum
|
||||
|
||||
|
||||
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;
|
||||
@ -62,6 +66,9 @@ void crypto_sha256_init()
|
||||
sha256_init(&sha256_ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_init() {
|
||||
cf_sha512_init(&sha512_ctx);
|
||||
}
|
||||
|
||||
void crypto_load_master_secret(uint8_t * key)
|
||||
{
|
||||
@ -86,6 +93,10 @@ 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);
|
||||
@ -96,6 +107,11 @@ 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];
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "stm32l4xx_ll_gpio.h"
|
||||
#include "stm32l4xx_ll_tim.h"
|
||||
#include "stm32l4xx_ll_usart.h"
|
||||
#include "stm32l4xx_ll_pwr.h"
|
||||
#include "usbd_hid.h"
|
||||
|
||||
#include APP_CONFIG
|
||||
@ -26,6 +27,11 @@
|
||||
#include "memory_layout.h"
|
||||
#include "stm32l4xx_ll_iwdg.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "nfc.h"
|
||||
#include "init.h"
|
||||
|
||||
#define LOW_FREQUENCY 1
|
||||
#define HIGH_FREQUENCY 0
|
||||
|
||||
void wait_for_usb_tether();
|
||||
|
||||
@ -34,6 +40,8 @@ uint32_t __90_ms = 0;
|
||||
uint32_t __device_status = 0;
|
||||
uint32_t __last_update = 0;
|
||||
extern PCD_HandleTypeDef hpcd;
|
||||
static bool haveNFC = 0;
|
||||
static bool isLowFreq = 0;
|
||||
|
||||
#define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||
|
||||
@ -50,6 +58,13 @@ void TIM6_DAC_IRQHandler()
|
||||
ctaphid_update_status(__device_status);
|
||||
}
|
||||
}
|
||||
#ifndef IS_BOOTLOADER
|
||||
// NFC sending WTX if needs
|
||||
if (device_is_nfc())
|
||||
{
|
||||
WTX_timer_exec();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Global USB interrupt handler
|
||||
@ -91,32 +106,42 @@ void device_reboot()
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void device_init()
|
||||
{
|
||||
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);
|
||||
|
||||
#ifndef IS_BOOTLOADER
|
||||
hw_init(LOW_FREQUENCY);
|
||||
isLowFreq = 0;
|
||||
|
||||
haveNFC = nfc_init();
|
||||
|
||||
if (haveNFC)
|
||||
{
|
||||
printf1(TAG_NFC, "Have NFC\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_NFC, "Have NO NFC\r\n");
|
||||
hw_init(HIGH_FREQUENCY);
|
||||
isLowFreq = 0;
|
||||
}
|
||||
|
||||
usbhid_init();
|
||||
ctaphid_init();
|
||||
ctap_init();
|
||||
|
||||
#if BOOT_TO_DFU
|
||||
flash_option_bytes_init(1);
|
||||
#else
|
||||
flash_option_bytes_init(0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf1(TAG_GEN,"hello solo\r\n");
|
||||
|
||||
}
|
||||
|
||||
void usb_init(void);
|
||||
void usbhid_init()
|
||||
bool device_is_nfc()
|
||||
{
|
||||
usb_init();
|
||||
|
||||
#if DEBUG_LEVEL>1
|
||||
wait_for_usb_tether();
|
||||
#endif
|
||||
|
||||
return haveNFC;
|
||||
}
|
||||
|
||||
void wait_for_usb_tether()
|
||||
@ -130,6 +155,26 @@ void wait_for_usb_tether()
|
||||
;
|
||||
}
|
||||
|
||||
void usbhid_init()
|
||||
{
|
||||
if (!isLowFreq)
|
||||
{
|
||||
init_usb();
|
||||
|
||||
#if DEBUG_LEVEL>1
|
||||
wait_for_usb_tether();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int usbhid_recv(uint8_t * msg)
|
||||
{
|
||||
if (fifo_hidmsg_size())
|
||||
@ -366,6 +411,7 @@ uint32_t ctap_atomic_count(int sel)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void device_manage()
|
||||
{
|
||||
#if NON_BLOCK_PRINTING
|
||||
@ -386,6 +432,10 @@ void device_manage()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef IS_BOOTLOADER
|
||||
// if(device_is_nfc())
|
||||
nfc_loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int handle_packets()
|
||||
@ -543,7 +593,7 @@ void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
|
||||
|
||||
memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey));
|
||||
flash_erase_page(page);
|
||||
flash_write(flash_addr(page), tmppage, ((sizeof(CTAP_residentKey) * (index + 1)) % PAGE_SIZE) );
|
||||
flash_write(flash_addr(page), tmppage, PAGE_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
34
targets/stm32l432/src/init.h
Normal file
34
targets/stm32l432/src/init.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2018 SoloKeys, Inc. <https://solokeys.com/>
|
||||
*
|
||||
* This file is part of Solo.
|
||||
*
|
||||
* Solo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Solo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Solo. If not, see <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This code is available under licenses for commercial use.
|
||||
* Please contact SoloKeys for more information.
|
||||
*/
|
||||
#ifndef _INIT_H_
|
||||
#define _INIT_H_
|
||||
|
||||
void init_usb();
|
||||
void init_gpio(void);
|
||||
void init_debug_uart(void);
|
||||
void init_pwm(void);
|
||||
void init_millisecond_timer(int lf);
|
||||
void init_rng(void);
|
||||
void init_spi(void);
|
||||
|
||||
|
||||
#endif
|
799
targets/stm32l432/src/nfc.c
Normal file
799
targets/stm32l432/src/nfc.c
Normal file
@ -0,0 +1,799 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "stm32l4xx.h"
|
||||
|
||||
#include "nfc.h"
|
||||
#include "ams.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "device.h"
|
||||
#include "u2f.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#include "ctap_errors.h"
|
||||
|
||||
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
|
||||
|
||||
// Capability container
|
||||
const CAPABILITY_CONTAINER NFC_CC = {
|
||||
.cclen_hi = 0x00, .cclen_lo = 0x0f,
|
||||
.version = 0x20,
|
||||
.MLe_hi = 0x00, .MLe_lo = 0x7f,
|
||||
.MLc_hi = 0x00, .MLc_lo = 0x7f,
|
||||
.tlv = { 0x04,0x06,
|
||||
0xe1,0x04,
|
||||
0x00,0x7f,
|
||||
0x00,0x00 }
|
||||
};
|
||||
|
||||
// 13 chars
|
||||
uint8_t NDEF_SAMPLE[] = "\x00\x14\xd1\x01\x0eU\x04solokeys.com/";
|
||||
|
||||
// Poor way to get some info while in passive operation
|
||||
#include <stdarg.h>
|
||||
void nprintf(const char *format, ...)
|
||||
{
|
||||
memmove((char*)NDEF_SAMPLE + sizeof(NDEF_SAMPLE) - 1 - 13," ", 13);
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
vsnprintf ((char*)NDEF_SAMPLE + sizeof(NDEF_SAMPLE) - 1 - 13, 13, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
uint8_t max_frame_size;
|
||||
uint8_t cid;
|
||||
uint8_t block_num;
|
||||
uint8_t selected_applet;
|
||||
} NFC_STATE;
|
||||
|
||||
void nfc_state_init()
|
||||
{
|
||||
memset(&NFC_STATE,0,sizeof(NFC_STATE));
|
||||
NFC_STATE.max_frame_size = 32;
|
||||
NFC_STATE.block_num = 1;
|
||||
}
|
||||
|
||||
bool nfc_init()
|
||||
{
|
||||
uint32_t t1;
|
||||
nfc_state_init();
|
||||
ams_init();
|
||||
|
||||
// Detect if we are powered by NFC field by listening for a message for
|
||||
// first 10 ms.
|
||||
t1 = millis();
|
||||
while ((millis() - t1) < 10)
|
||||
{
|
||||
if (nfc_loop() > 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Under USB power. Configure AMS chip.
|
||||
ams_configure();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_int0(uint8_t int0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ams_wait_for_tx(uint32_t timeout_ms)
|
||||
{
|
||||
uint32_t tstart = millis();
|
||||
while (tstart + timeout_ms > millis())
|
||||
{
|
||||
uint8_t int0 = ams_read_reg(AMS_REG_INT0);
|
||||
if (int0) process_int0(int0);
|
||||
if (int0 & AMS_INT_TXE)
|
||||
return true;
|
||||
|
||||
delay(1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ams_receive_with_timeout(uint32_t timeout_ms, uint8_t * data, int maxlen, int *dlen)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
*dlen = 0;
|
||||
|
||||
uint32_t tstart = millis();
|
||||
while (tstart + timeout_ms > millis())
|
||||
{
|
||||
uint8_t int0 = ams_read_reg(AMS_REG_INT0);
|
||||
uint8_t buffer_status2 = ams_read_reg(AMS_REG_BUF2);
|
||||
|
||||
if (buffer_status2 && (int0 & AMS_INT_RXE))
|
||||
{
|
||||
if (buffer_status2 & AMS_BUF_INVALID)
|
||||
{
|
||||
printf1(TAG_NFC,"Buffer being updated!\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t len = buffer_status2 & AMS_BUF_LEN_MASK;
|
||||
ams_read_buffer(buf, len);
|
||||
printf1(TAG_NFC_APDU, ">> ");
|
||||
dump_hex1(TAG_NFC_APDU, buf, len);
|
||||
|
||||
*dlen = MIN(32, MIN(maxlen, len));
|
||||
memcpy(data, buf, *dlen);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
delay(1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void nfc_write_frame(uint8_t * data, uint8_t len)
|
||||
{
|
||||
if (len > 32)
|
||||
{
|
||||
len = 32;
|
||||
}
|
||||
ams_write_command(AMS_CMD_CLEAR_BUFFER);
|
||||
ams_write_buffer(data,len);
|
||||
ams_write_command(AMS_CMD_TRANSMIT_BUFFER);
|
||||
|
||||
printf1(TAG_NFC_APDU, "<< ");
|
||||
dump_hex1(TAG_NFC_APDU, data, len);
|
||||
}
|
||||
|
||||
bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t resp)
|
||||
{
|
||||
uint8_t res[32];
|
||||
|
||||
if (len > 32 - 3)
|
||||
return false;
|
||||
|
||||
res[0] = NFC_CMD_IBLOCK | (req0 & 3);
|
||||
|
||||
if (len && data)
|
||||
memcpy(&res[1], data, len);
|
||||
|
||||
res[len + 1] = resp >> 8;
|
||||
res[len + 2] = resp & 0xff;
|
||||
nfc_write_frame(res, 3 + len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_write_response(uint8_t req0, uint16_t resp)
|
||||
{
|
||||
return nfc_write_response_ex(req0, NULL, 0, resp);
|
||||
}
|
||||
|
||||
void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
|
||||
{
|
||||
uint8_t res[32 + 2];
|
||||
int sendlen = 0;
|
||||
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 3);
|
||||
|
||||
if (len <= 31)
|
||||
{
|
||||
uint8_t res[32] = {0};
|
||||
res[0] = iBlock;
|
||||
if (len && data)
|
||||
memcpy(&res[1], data, len);
|
||||
nfc_write_frame(res, len + 1);
|
||||
} else {
|
||||
do {
|
||||
// transmit I block
|
||||
int vlen = MIN(31, len - sendlen);
|
||||
res[0] = iBlock;
|
||||
memcpy(&res[1], &data[sendlen], vlen);
|
||||
|
||||
// if not a last block
|
||||
if (vlen + sendlen < len)
|
||||
{
|
||||
res[0] |= 0x10;
|
||||
}
|
||||
|
||||
// send data
|
||||
nfc_write_frame(res, vlen + 1);
|
||||
sendlen += vlen;
|
||||
|
||||
// wait for transmit (32 bytes aprox 2,5ms)
|
||||
// if (!ams_wait_for_tx(10))
|
||||
// {
|
||||
// printf1(TAG_NFC, "TX timeout. slen: %d \r\n", sendlen);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if needs to receive R block (not a last block)
|
||||
if (res[0] & 0x10)
|
||||
{
|
||||
uint8_t recbuf[32] = {0};
|
||||
int reclen;
|
||||
if (!ams_receive_with_timeout(100, recbuf, sizeof(recbuf), &reclen))
|
||||
{
|
||||
printf1(TAG_NFC, "R block RX timeout %d/%d.\r\n",sendlen,len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reclen != 1)
|
||||
{
|
||||
printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen,sendlen,len);
|
||||
dump_hex1(TAG_NFC, recbuf, reclen);
|
||||
break;
|
||||
}
|
||||
|
||||
if (((recbuf[0] & 0x01) == (res[0] & 1)) && ((recbuf[0] & 0xf6) == 0xa2))
|
||||
{
|
||||
printf1(TAG_NFC, "R block error. txdata: %02x rxdata: %02x \r\n", res[0], recbuf[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iBlock ^= 0x01;
|
||||
} while (sendlen < len);
|
||||
}
|
||||
}
|
||||
|
||||
// WTX on/off:
|
||||
// sends/receives WTX frame to reader every `WTX_time` time in ms
|
||||
// works via timer interrupts
|
||||
// WTX: f2 01 91 40 === f2(S-block + WTX, frame without CID) 01(from iso - multiply WTX from ATS by 1) <2b crc16>
|
||||
static bool WTX_sent;
|
||||
static bool WTX_fail;
|
||||
static uint32_t WTX_timer;
|
||||
|
||||
bool WTX_process(int read_timeout);
|
||||
|
||||
void WTX_clear()
|
||||
{
|
||||
WTX_sent = false;
|
||||
WTX_fail = false;
|
||||
WTX_timer = 0;
|
||||
}
|
||||
|
||||
bool WTX_on(int WTX_time)
|
||||
{
|
||||
WTX_clear();
|
||||
WTX_timer = millis();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WTX_off()
|
||||
{
|
||||
WTX_timer = 0;
|
||||
|
||||
// read data if we sent WTX
|
||||
if (WTX_sent)
|
||||
{
|
||||
if (!WTX_process(100))
|
||||
{
|
||||
printf1(TAG_NFC, "WTX-off get last WTX error\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (WTX_fail)
|
||||
{
|
||||
printf1(TAG_NFC, "WTX-off fail\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
WTX_clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WTX_timer_exec()
|
||||
{
|
||||
// condition: (timer on) or (not expired[300ms])
|
||||
if ((WTX_timer <= 0) || WTX_timer + 300 > millis())
|
||||
return;
|
||||
|
||||
WTX_process(10);
|
||||
WTX_timer = millis();
|
||||
}
|
||||
|
||||
// executes twice a period. 1st for send WTX, 2nd for check the result
|
||||
// read timeout must be 10 ms to call from interrupt
|
||||
bool WTX_process(int read_timeout)
|
||||
{
|
||||
uint8_t wtx[] = {0xf2, 0x01};
|
||||
if (WTX_fail)
|
||||
return false;
|
||||
|
||||
if (!WTX_sent)
|
||||
{
|
||||
nfc_write_frame(wtx, sizeof(wtx));
|
||||
WTX_sent = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t data[32];
|
||||
int len;
|
||||
if (!ams_receive_with_timeout(read_timeout, data, sizeof(data), &len))
|
||||
{
|
||||
WTX_fail = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len != 2 || data[0] != 0xf2 || data[1] != 0x01)
|
||||
{
|
||||
WTX_fail = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
WTX_sent = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int answer_rats(uint8_t parameter)
|
||||
{
|
||||
|
||||
uint8_t fsdi = (parameter & 0xf0) >> 4;
|
||||
uint8_t cid = (parameter & 0x0f);
|
||||
|
||||
NFC_STATE.cid = cid;
|
||||
|
||||
if (fsdi == 0)
|
||||
NFC_STATE.max_frame_size = 16;
|
||||
else if (fsdi == 1)
|
||||
NFC_STATE.max_frame_size = 24;
|
||||
else
|
||||
NFC_STATE.max_frame_size = 32;
|
||||
|
||||
uint8_t res[3 + 11];
|
||||
res[0] = sizeof(res);
|
||||
res[1] = 2 | (1<<5); // 2 FSCI == 32 byte frame size, TB is enabled
|
||||
|
||||
// frame wait time = (256 * 16 / 13.56MHz) * 2^FWI
|
||||
// FWI=0, FMT=0.3ms (min)
|
||||
// FWI=4, FMT=4.8ms (default)
|
||||
// FWI=10, FMT=309ms
|
||||
// FWI=12, FMT=1237ms
|
||||
// FWI=14, FMT=4949ms (max)
|
||||
res[2] = (12<<4) | (0); // TB (FWI << 4) | (SGTI)
|
||||
|
||||
// historical bytes
|
||||
memcpy(&res[3], (uint8_t *)"SoloKey tap", 11);
|
||||
|
||||
|
||||
nfc_write_frame(res, sizeof(res));
|
||||
ams_wait_for_tx(10);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rblock_acknowledge()
|
||||
{
|
||||
uint8_t buf[32];
|
||||
NFC_STATE.block_num = !NFC_STATE.block_num;
|
||||
buf[0] = NFC_CMD_RBLOCK | NFC_STATE.block_num;
|
||||
nfc_write_frame(buf,1);
|
||||
}
|
||||
|
||||
// Selects application. Returns 1 if success, 0 otherwise
|
||||
int select_applet(uint8_t * aid, int len)
|
||||
{
|
||||
if (memcmp(aid,AID_FIDO,sizeof(AID_FIDO)) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_FIDO;
|
||||
return APP_FIDO;
|
||||
}
|
||||
else if (memcmp(aid,AID_NDEF_TYPE_4,sizeof(AID_NDEF_TYPE_4)) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_NDEF_TYPE_4;
|
||||
return APP_NDEF_TYPE_4;
|
||||
}
|
||||
else if (memcmp(aid,AID_CAPABILITY_CONTAINER,sizeof(AID_CAPABILITY_CONTAINER)) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_CAPABILITY_CONTAINER;
|
||||
return APP_CAPABILITY_CONTAINER;
|
||||
}
|
||||
else if (memcmp(aid,AID_NDEF_TAG,sizeof(AID_NDEF_TAG)) == 0)
|
||||
{
|
||||
NFC_STATE.selected_applet = APP_NDEF_TAG;
|
||||
return APP_NDEF_TAG;
|
||||
}
|
||||
return APP_NOTHING;
|
||||
}
|
||||
|
||||
void nfc_process_iblock(uint8_t * buf, int len)
|
||||
{
|
||||
APDU_HEADER * apdu = (APDU_HEADER *)(buf + 1);
|
||||
uint8_t * payload = buf + 1 + 5;
|
||||
uint8_t plen = apdu->lc;
|
||||
int selected;
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
int status;
|
||||
|
||||
printf1(TAG_NFC,"Iblock: ");
|
||||
dump_hex1(TAG_NFC, buf, len);
|
||||
|
||||
// TODO this needs to be organized better
|
||||
switch(apdu->ins)
|
||||
{
|
||||
case APDU_INS_SELECT:
|
||||
if (plen > len - 6)
|
||||
{
|
||||
printf1(TAG_ERR, "Truncating APDU length %d\r\n", apdu->lc);
|
||||
plen = len-6;
|
||||
}
|
||||
// if (apdu->p1 == 0 && apdu->p2 == 0x0c)
|
||||
// {
|
||||
// printf1(TAG_NFC,"Select NDEF\r\n");
|
||||
//
|
||||
// NFC_STATE.selected_applet = APP_NDEF_TAG;
|
||||
// // Select NDEF file!
|
||||
// res[0] = NFC_CMD_IBLOCK | (buf[0] & 1);
|
||||
// res[1] = SW_SUCCESS>>8;
|
||||
// res[2] = SW_SUCCESS & 0xff;
|
||||
// nfc_write_frame(res, 3);
|
||||
// printf1(TAG_NFC,"<< "); dump_hex1(TAG_NFC,res, 3);
|
||||
// }
|
||||
// else
|
||||
{
|
||||
selected = select_applet(payload, plen);
|
||||
if (selected == APP_FIDO)
|
||||
{
|
||||
// block = buf[0] & 1;
|
||||
// block = NFC_STATE.block_num;
|
||||
// block = !block;
|
||||
// NFC_STATE.block_num = block;
|
||||
// NFC_STATE.block_num = block;
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
||||
printf1(TAG_NFC, "FIDO applet selected.\r\n");
|
||||
}
|
||||
else if (selected != APP_NOTHING)
|
||||
{
|
||||
nfc_write_response(buf[0], SW_SUCCESS);
|
||||
printf1(TAG_NFC, "SELECTED %d\r\n", selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
||||
printf1(TAG_NFC, "NOT selected\r\n"); dump_hex1(TAG_NFC,payload, plen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_VERSION:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
||||
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_REGISTER:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "U2F Register command.\r\n");
|
||||
|
||||
if (plen != 64)
|
||||
{
|
||||
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", plen);
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp();
|
||||
|
||||
|
||||
// WTX_on(WTX_TIME_DEFAULT);
|
||||
// SystemClock_Config_LF32();
|
||||
// delay(300);
|
||||
device_set_clock_rate(DEVICE_LOW_POWER_FAST);;
|
||||
u2f_request_nfc(&buf[1], len, &ctap_resp);
|
||||
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);;
|
||||
// if (!WTX_off())
|
||||
// return;
|
||||
|
||||
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
|
||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||
|
||||
// printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||
|
||||
|
||||
|
||||
|
||||
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_AUTHENTICATE:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "U2F Authenticate command.\r\n");
|
||||
|
||||
if (plen != 64 + 1 + buf[6 + 64])
|
||||
{
|
||||
delay(5);
|
||||
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", plen, buf[6 + 64]);
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp();
|
||||
// WTX_on(WTX_TIME_DEFAULT);
|
||||
u2f_request_nfc(&buf[1], len, &ctap_resp);
|
||||
// if (!WTX_off())
|
||||
// return;
|
||||
|
||||
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||
printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp());
|
||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||
printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp);
|
||||
break;
|
||||
|
||||
case APDU_FIDO_NFCCTAP_MSG:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
||||
|
||||
WTX_on(WTX_TIME_DEFAULT);
|
||||
ctap_response_init(&ctap_resp);
|
||||
status = ctap_request(payload, plen, &ctap_resp);
|
||||
if (!WTX_off())
|
||||
return;
|
||||
|
||||
printf1(TAG_NFC, "CTAP resp: 0x%02<30> len: %d\r\n", status, ctap_resp.length);
|
||||
|
||||
if (status == CTAP1_ERR_SUCCESS)
|
||||
{
|
||||
memmove(&ctap_resp.data[1], &ctap_resp.data[0], ctap_resp.length);
|
||||
ctap_resp.length += 3;
|
||||
} else {
|
||||
ctap_resp.length = 3;
|
||||
}
|
||||
ctap_resp.data[0] = status;
|
||||
ctap_resp.data[ctap_resp.length - 2] = SW_SUCCESS >> 8;
|
||||
ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff;
|
||||
|
||||
printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp());
|
||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||
printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp());
|
||||
break;
|
||||
|
||||
case APDU_INS_READ_BINARY:
|
||||
|
||||
|
||||
switch(NFC_STATE.selected_applet)
|
||||
{
|
||||
case APP_CAPABILITY_CONTAINER:
|
||||
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
|
||||
if (plen > 15)
|
||||
{
|
||||
printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc);
|
||||
plen = 15;
|
||||
}
|
||||
nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, plen, SW_SUCCESS);
|
||||
ams_wait_for_tx(10);
|
||||
break;
|
||||
case APP_NDEF_TAG:
|
||||
printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
|
||||
if (plen > (sizeof(NDEF_SAMPLE) - 1))
|
||||
{
|
||||
printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc);
|
||||
plen = sizeof(NDEF_SAMPLE) - 1;
|
||||
}
|
||||
nfc_write_response_ex(buf[0], NDEF_SAMPLE, plen, SW_SUCCESS);
|
||||
ams_wait_for_tx(10);
|
||||
break;
|
||||
default:
|
||||
printf1(TAG_ERR, "No binary applet selected!\r\n");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static uint8_t ibuf[1024];
|
||||
static int ibuflen = 0;
|
||||
|
||||
void clear_ibuf()
|
||||
{
|
||||
ibuflen = 0;
|
||||
memset(ibuf, 0, sizeof(ibuf));
|
||||
}
|
||||
|
||||
void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
{
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
if (IS_PPSS_CMD(buf[0]))
|
||||
{
|
||||
printf1(TAG_NFC, "NFC_CMD_PPSS\r\n");
|
||||
}
|
||||
else if (IS_IBLOCK(buf[0]))
|
||||
{
|
||||
if (buf[0] & 0x10)
|
||||
{
|
||||
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len);
|
||||
if (ibuflen + len > sizeof(ibuf))
|
||||
{
|
||||
printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf));
|
||||
nfc_write_response(buf[0], SW_INTERNAL_EXCEPTION);
|
||||
return;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC_APDU,"i> ");
|
||||
dump_hex1(TAG_NFC_APDU, buf, len);
|
||||
|
||||
if (len)
|
||||
{
|
||||
memcpy(&ibuf[ibuflen], &buf[1], len - 1);
|
||||
ibuflen += len - 1;
|
||||
}
|
||||
|
||||
// send R block
|
||||
uint8_t rb = NFC_CMD_RBLOCK | NFC_CMD_RBLOCK_ACK | (buf[0] & 3);
|
||||
nfc_write_frame(&rb, 1);
|
||||
} else {
|
||||
if (ibuflen)
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
memcpy(&ibuf[ibuflen], &buf[1], len - 1);
|
||||
ibuflen += len - 1;
|
||||
}
|
||||
|
||||
memmove(&ibuf[1], ibuf, ibuflen);
|
||||
ibuf[0] = buf[0];
|
||||
ibuflen++;
|
||||
|
||||
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len);
|
||||
|
||||
printf1(TAG_NFC_APDU,"i> ");
|
||||
dump_hex1(TAG_NFC_APDU, buf, len);
|
||||
|
||||
nfc_process_iblock(ibuf, ibuflen);
|
||||
} else {
|
||||
// printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n");
|
||||
nfc_process_iblock(buf, len);
|
||||
}
|
||||
clear_ibuf();
|
||||
}
|
||||
}
|
||||
else if (IS_RBLOCK(buf[0]))
|
||||
{
|
||||
rblock_acknowledge();
|
||||
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
|
||||
}
|
||||
else if (IS_SBLOCK(buf[0]))
|
||||
{
|
||||
|
||||
if ((buf[0] & NFC_SBLOCK_DESELECT) == 0)
|
||||
{
|
||||
printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n");
|
||||
nfc_write_frame(buf, 1);
|
||||
ams_wait_for_tx(2);
|
||||
ams_write_command(AMS_CMD_SLEEP);
|
||||
nfc_state_init();
|
||||
clear_ibuf();
|
||||
WTX_clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_NFC, "NFC_CMD_SBLOCK, Unknown. len[%d]\r\n", len);
|
||||
}
|
||||
dump_hex1(TAG_NFC, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_NFC, "unknown NFC request\r\n len[%d]:", len);
|
||||
dump_hex1(TAG_NFC, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
int nfc_loop()
|
||||
{
|
||||
uint8_t buf[32];
|
||||
AMS_DEVICE ams;
|
||||
int len = 0;
|
||||
|
||||
|
||||
read_reg_block(&ams);
|
||||
uint8_t state = AMS_STATE_MASK & ams.regs.rfid_status;
|
||||
|
||||
if (state != AMS_STATE_SELECTED && state != AMS_STATE_SELECTEDX)
|
||||
{
|
||||
// delay(1); // sleep ?
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ams.regs.rfid_status)
|
||||
{
|
||||
// if (state != AMS_STATE_SENSE)
|
||||
// printf1(TAG_NFC," %s x%02x\r\n", ams_get_state_string(ams.regs.rfid_status), state);
|
||||
}
|
||||
if (ams.regs.int0 & AMS_INT_INIT)
|
||||
{
|
||||
nfc_state_init();
|
||||
}
|
||||
if (ams.regs.int1)
|
||||
{
|
||||
// ams_print_int1(ams.regs.int1);
|
||||
}
|
||||
|
||||
if ((ams.regs.int0 & AMS_INT_RXE))
|
||||
{
|
||||
if (ams.regs.buffer_status2)
|
||||
{
|
||||
if (ams.regs.buffer_status2 & AMS_BUF_INVALID)
|
||||
{
|
||||
printf1(TAG_NFC,"Buffer being updated!\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
len = ams.regs.buffer_status2 & AMS_BUF_LEN_MASK;
|
||||
ams_read_buffer(buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
|
||||
// ISO 14443-3
|
||||
switch(buf[0])
|
||||
{
|
||||
case NFC_CMD_REQA:
|
||||
printf1(TAG_NFC, "NFC_CMD_REQA\r\n");
|
||||
break;
|
||||
case NFC_CMD_WUPA:
|
||||
printf1(TAG_NFC, "NFC_CMD_WUPA\r\n");
|
||||
break;
|
||||
case NFC_CMD_HLTA:
|
||||
printf1(TAG_NFC, "HLTA/Halt\r\n");
|
||||
break;
|
||||
case NFC_CMD_RATS:
|
||||
|
||||
answer_rats(buf[1]);
|
||||
|
||||
NFC_STATE.block_num = 1;
|
||||
clear_ibuf();
|
||||
WTX_clear();
|
||||
break;
|
||||
default:
|
||||
|
||||
// ISO 14443-4
|
||||
nfc_process_block(buf,len);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
}
|
64
targets/stm32l432/src/nfc.h
Normal file
64
targets/stm32l432/src/nfc.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef _NFC_H_
|
||||
#define _NFC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "apdu.h"
|
||||
|
||||
// Return number of bytes read if any.
|
||||
int nfc_loop();
|
||||
|
||||
bool nfc_init();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cclen_hi;
|
||||
uint8_t cclen_lo;
|
||||
uint8_t version;
|
||||
uint8_t MLe_hi;
|
||||
uint8_t MLe_lo;
|
||||
uint8_t MLc_hi;
|
||||
uint8_t MLc_lo;
|
||||
uint8_t tlv[8];
|
||||
} __attribute__((packed)) CAPABILITY_CONTAINER;
|
||||
|
||||
// WTX time in ms
|
||||
#define WTX_TIME_DEFAULT 300
|
||||
|
||||
#define NFC_CMD_REQA 0x26
|
||||
#define NFC_CMD_WUPA 0x52
|
||||
#define NFC_CMD_HLTA 0x50
|
||||
#define NFC_CMD_RATS 0xe0
|
||||
|
||||
#define NFC_CMD_PPSS 0xd0
|
||||
#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS)
|
||||
#define NFC_CMD_IBLOCK 0x00
|
||||
#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
#define NFC_CMD_RBLOCK 0x80
|
||||
#define NFC_CMD_RBLOCK_ACK 0x20
|
||||
#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
#define NFC_CMD_SBLOCK 0xc0
|
||||
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
|
||||
#define NFC_SBLOCK_DESELECT 0x30
|
||||
#define NFC_SBLOCK_WTX 0x30
|
||||
|
||||
#define AID_NDEF_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x01"
|
||||
#define AID_NDEF_MIFARE_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x00"
|
||||
#define AID_CAPABILITY_CONTAINER "\xE1\x03"
|
||||
#define AID_NDEF_TAG "\xE1\x04"
|
||||
#define AID_FIDO "\xa0\x00\x00\x06\x47\x2f\x00\x01"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
APP_NOTHING = 0,
|
||||
APP_NDEF_TYPE_4 = 1,
|
||||
APP_MIFARE_TYPE_4,
|
||||
APP_CAPABILITY_CONTAINER,
|
||||
APP_NDEF_TAG,
|
||||
APP_FIDO,
|
||||
} APPLETS;
|
||||
|
||||
void WTX_timer_exec();
|
||||
|
||||
#endif
|
@ -24,19 +24,33 @@ void _putchar(char c)
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _write (int fd, const void *buf, long int len)
|
||||
int _write (int fd, const void *buf, unsigned long int len)
|
||||
{
|
||||
uint8_t * data = (uint8_t *) buf;
|
||||
#if DEBUG_LEVEL>1
|
||||
// static uint8_t logbuf[1000] = {0};
|
||||
// static int logbuflen = 0;
|
||||
// if (logbuflen + len > sizeof(logbuf)) {
|
||||
// int mlen = logbuflen + len - sizeof(logbuf);
|
||||
// memmove(logbuf, &logbuf[mlen], sizeof(logbuf) - mlen);
|
||||
// logbuflen -= mlen;
|
||||
// }
|
||||
// memcpy(&logbuf[logbuflen], data, len);
|
||||
// logbuflen += len;
|
||||
|
||||
// Send out USB serial
|
||||
CDC_Transmit_FS(data, len);
|
||||
|
||||
// Send out USB serial
|
||||
CDC_Transmit_FS(buf, len);
|
||||
// if (res == USBD_OK)
|
||||
// logbuflen = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_SERIAL_PRINTING
|
||||
// Send out UART serial
|
||||
while(len--)
|
||||
{
|
||||
_putchar(*data++);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* - Set the initial SP
|
||||
* - Set the initial PC == Reset_Handler,
|
||||
* - Set the vector table entries with the exceptions ISR address,
|
||||
* - Configure the clock system
|
||||
* - Configure the clock system
|
||||
* - Branches to main in the C library (which eventually
|
||||
* calls main()).
|
||||
* After Reset the Cortex-M4 processor is in Thread mode,
|
||||
@ -79,6 +79,8 @@ Reset_Handler:
|
||||
ldr sp, =_estack /* Atollic update: set stack pointer */
|
||||
|
||||
/* Copy the data segment initializers from flash to SRAM */
|
||||
/* Call the clock system intitialization function.*/
|
||||
bl SystemInit
|
||||
movs r1, #0
|
||||
b LoopCopyDataInit
|
||||
|
||||
@ -106,8 +108,7 @@ LoopFillZerobss:
|
||||
cmp r2, r3
|
||||
bcc FillZerobss
|
||||
|
||||
/* Call the clock system intitialization function.*/
|
||||
bl SystemInit
|
||||
|
||||
/* Call static constructors */
|
||||
bl __libc_init_array
|
||||
/* Call the application's entry point.*/
|
||||
@ -115,7 +116,7 @@ LoopFillZerobss:
|
||||
|
||||
LoopForever:
|
||||
b LoopForever
|
||||
|
||||
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
|
||||
/**
|
||||
@ -414,49 +415,49 @@ g_pfnVectors:
|
||||
|
||||
.weak COMP_IRQHandler
|
||||
.thumb_set COMP_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak LPTIM1_IRQHandler
|
||||
.thumb_set LPTIM1_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak LPTIM2_IRQHandler
|
||||
.thumb_set LPTIM2_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set LPTIM2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USB_IRQHandler
|
||||
.thumb_set USB_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set USB_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Channel6_IRQHandler
|
||||
.thumb_set DMA2_Channel6_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set DMA2_Channel6_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Channel7_IRQHandler
|
||||
.thumb_set DMA2_Channel7_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set DMA2_Channel7_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPUART1_IRQHandler
|
||||
.thumb_set LPUART1_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set LPUART1_IRQHandler,Default_Handler
|
||||
|
||||
.weak QUADSPI_IRQHandler
|
||||
.thumb_set QUADSPI_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set QUADSPI_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_EV_IRQHandler
|
||||
.thumb_set I2C3_EV_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set I2C3_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_ER_IRQHandler
|
||||
.thumb_set I2C3_ER_IRQHandler,Default_Handler
|
||||
|
||||
.thumb_set I2C3_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak SAI1_IRQHandler
|
||||
.thumb_set SAI1_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak SWPMI1_IRQHandler
|
||||
.thumb_set SWPMI1_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak TSC_IRQHandler
|
||||
.thumb_set TSC_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak RNG_IRQHandler
|
||||
.thumb_set RNG_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak FPU_IRQHandler
|
||||
.thumb_set FPU_IRQHandler,Default_Handler
|
||||
|
||||
|
||||
.weak CRS_IRQHandler
|
||||
.thumb_set CRS_IRQHandler,Default_Handler
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
@ -106,6 +106,8 @@
|
||||
*/
|
||||
|
||||
#include "stm32l4xx.h"
|
||||
#include "device.h"
|
||||
#include "init.h"
|
||||
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
|
||||
@ -219,6 +221,9 @@ void SystemInit(void)
|
||||
/* Disable all interrupts */
|
||||
RCC->CIER = 0x00000000U;
|
||||
|
||||
// TODO this is causing boot issues for old bootloader
|
||||
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
1061
tools/ctap_test.py
1061
tools/ctap_test.py
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,7 @@
|
||||
ecdsa
|
||||
fido2
|
||||
intelhex
|
||||
pyserial
|
||||
fido2
|
||||
solo-python
|
||||
pyusb
|
||||
wheel
|
||||
|
1060
tools/solotool.py
1060
tools/solotool.py
File diff suppressed because it is too large
Load Diff
8
tools/test_sw_token.sh
Normal file
8
tools/test_sw_token.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
./main
|
||||
|
||||
while [ $? == 100 ] ; do
|
||||
echo "Restarting software authentictor."
|
||||
./main
|
||||
done
|
19
udev/70-solokeys-access.rules
Normal file
19
udev/70-solokeys-access.rules
Normal file
@ -0,0 +1,19 @@
|
||||
# Notify ModemManager this device should be ignored
|
||||
ACTION!="add|change|move", GOTO="mm_usb_device_blacklist_end"
|
||||
SUBSYSTEM!="usb", GOTO="mm_usb_device_blacklist_end"
|
||||
ENV{DEVTYPE}!="usb_device", GOTO="mm_usb_device_blacklist_end"
|
||||
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
LABEL="mm_usb_device_blacklist_end"
|
||||
|
||||
|
||||
# Solo bootloader + firmware access
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess"
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess"
|
||||
|
||||
# ST DFU access
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess"
|
||||
|
||||
# U2F Zero
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
|
19
udev/70-solokeys-legacy-access.rules
Normal file
19
udev/70-solokeys-legacy-access.rules
Normal file
@ -0,0 +1,19 @@
|
||||
# Notify ModemManager this device should be ignored
|
||||
ACTION!="add|change|move", GOTO="mm_usb_device_blacklist_end"
|
||||
SUBSYSTEM!="usb", GOTO="mm_usb_device_blacklist_end"
|
||||
ENV{DEVTYPE}!="usb_device", GOTO="mm_usb_device_blacklist_end"
|
||||
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||
|
||||
LABEL="mm_usb_device_blacklist_end"
|
||||
|
||||
|
||||
# Solo bootloader + firmware access
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", MODE="0660", GROUP="plugdev"
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", MODE="0660", GROUP="plugdev"
|
||||
|
||||
# ST DFU access
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0660", GROUP="plugdev"
|
||||
|
||||
# U2F Zero
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", MODE="0660", GROUP="plugdev"
|
17
udev/71-solokeys-symlinks.rules
Normal file
17
udev/71-solokeys-symlinks.rules
Normal file
@ -0,0 +1,17 @@
|
||||
# TODO: would like to lookup ID_SERIAL_SHORT from `usb` SUBSYSTEM
|
||||
# but link on `hidraw` subsystem level
|
||||
# and end up with symlinks `/dev/solo[hacker|secure]-<serial>`
|
||||
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", SYMLINK+="solo-$env{ID_SERIAL_SHORT}-%n"
|
||||
## Solo Secure symlinks
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo [1-9]*", SYMLINK+="solosecure-$env{ID_SERIAL_SHORT}-%n"
|
||||
## Solo Hacker symlinks
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo Hacker [1-9]*", SYMLINK+="solohacker-$env{ID_SERIAL_SHORT}-%n"
|
||||
## Solo Serial access + symlink
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", SYMLINK+="soloserial"
|
||||
|
||||
# Non-unique rules (breakdown if multiple Solos are plugged in)
|
||||
## Solo
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", SYMLINK+="solo"
|
||||
## U2F Zero
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", SYMLINK+="u2fzero"
|
28
udev/Makefile
Normal file
28
udev/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
# On modern systems, udev has a TAG uaccess, which is used in 73-seat-late.rules
|
||||
# On older systems, we use GROUP plugdev with MODE
|
||||
# --> Try `make setup` first, if it doesn't work, try `make legacy-setup`.
|
||||
#
|
||||
# The symlinks are optional, install with `make symlinks`.
|
||||
#
|
||||
# We keep 99-solo.rules in the parent directory but deprecate it,
|
||||
# remove when documentation is updated.
|
||||
|
||||
|
||||
setup: install activate
|
||||
legacy-setup: install-legacy activate
|
||||
# symlinks: install-symlinks activate
|
||||
|
||||
RULES_PATH=/etc/udev/rules.d
|
||||
|
||||
activate:
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
|
||||
install:
|
||||
sudo ln -sf $(PWD)/70-solokeys-access.rules ${RULES_PATH}/70-solokeys-access.rules
|
||||
|
||||
install-legacy:
|
||||
sudo ln -sf $(PWD)/70-solokeys-legacy-access.rules ${RULES_PATH}/70-solokeys-access.rules
|
||||
|
||||
# install-symlinks:
|
||||
# sudo cp $(PWD)/71-solokeys-symlinks.rules ${RULES_PATH}/71-solokeys-symlinks.rules
|
Reference in New Issue
Block a user