Compare commits
155 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 | |||
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 |
10
.gitignore
vendored
10
.gitignore
vendored
@ -81,15 +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,28 +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
|
||||
|
||||
## bootloader + firmware access
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev"
|
||||
|
||||
## DFU access
|
||||
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", 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
|
@ -14,7 +14,7 @@ RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.
|
||||
RUN sha256sum -c gcc.sha256
|
||||
RUN tar -C /opt -xf gcc.tar.bz2
|
||||
|
||||
# 2. Python3.7: for solotool (merging etc.)
|
||||
# 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
|
||||
@ -24,8 +24,10 @@ RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a mini
|
||||
RUN sha256sum -c miniconda.sha256
|
||||
|
||||
RUN bash ./miniconda.sh -b -p /opt/conda
|
||||
RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python3
|
||||
RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python
|
||||
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
|
||||
|
6
Makefile
6
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
|
||||
@ -61,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
|
||||
|
||||
@ -69,7 +71,7 @@ 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
|
||||
@ -80,7 +82,7 @@ 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)
|
||||
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
|
||||
|
||||
CPPCHECK_FLAGS=--quiet --error-exitcode=2
|
||||
|
||||
|
@ -48,7 +48,8 @@ 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`.
|
||||
|
1
STABLE_VERSION
Normal file
1
STABLE_VERSION
Normal file
@ -0,0 +1 @@
|
||||
1.1.1
|
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
|
||||
|
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,6 +112,11 @@ 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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
35
fido2/ctap.c
35
fido2/ctap.c
@ -25,7 +25,6 @@
|
||||
|
||||
#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];
|
||||
@ -34,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];
|
||||
@ -336,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)
|
||||
{
|
||||
@ -558,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");
|
||||
@ -612,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);
|
||||
@ -624,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);
|
||||
@ -815,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;
|
||||
@ -1182,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())
|
||||
{
|
||||
@ -1225,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())
|
||||
{
|
||||
@ -1250,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:
|
||||
@ -1397,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);
|
||||
@ -1586,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()
|
||||
@ -1782,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()
|
||||
{
|
||||
@ -1799,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
|
||||
|
@ -91,10 +91,10 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
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)
|
||||
@ -118,7 +118,7 @@ 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;
|
||||
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,8 +7,9 @@
|
||||
#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);
|
||||
|
||||
|
@ -48,6 +48,8 @@ struct logtag tagtable[] = {
|
||||
{TAG_STOR,"[1;35mSTOR[0m"},
|
||||
{TAG_BOOT,"[1;36mBOOT[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;
|
||||
}
|
||||
|
11
fido2/log.h
11
fido2/log.h
@ -28,13 +28,13 @@ typedef enum
|
||||
TAG_GA = (1 << 2),
|
||||
TAG_CP = (1 << 3),
|
||||
TAG_ERR = (1 << 4),
|
||||
TAG_PARSE= (1 << 5),
|
||||
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_RED = (1 << 10),
|
||||
TAG_TIME = (1 << 11),
|
||||
TAG_HID = (1 << 12),
|
||||
TAG_USB = (1 << 13),
|
||||
TAG_WALLET = (1 << 14),
|
||||
@ -42,8 +42,11 @@ typedef enum
|
||||
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
|
||||
|
36
fido2/main.c
36
fido2/main.c
@ -26,39 +26,32 @@ int main()
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
// TAG_GEN|
|
||||
// TAG_MC |
|
||||
// TAG_GA |
|
||||
TAG_WALLET |
|
||||
//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_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
|
||||
|
58
fido2/u2f.c
58
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,7 +43,7 @@ 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 && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
|
||||
{
|
||||
@ -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 ||
|
||||
(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(!device_is_nfc() && up)
|
||||
{
|
||||
if (ctap_user_presence_test() == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
count = ctap_atomic_count(0);
|
||||
hash[0] = 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] = 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(!device_is_nfc())
|
||||
{
|
||||
if ( ! ctap_user_presence_test())
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1)
|
||||
{
|
||||
|
@ -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
|
||||
@ -98,6 +98,11 @@ struct u2f_authenticate_request
|
||||
// @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();
|
||||
|
@ -5,7 +5,7 @@ version=${1:-master}
|
||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
|
||||
|
||||
cd /solo/targets/stm32l432
|
||||
git fetch
|
||||
git fetch --tags
|
||||
git checkout ${version}
|
||||
version=$(git describe)
|
||||
|
||||
@ -35,3 +35,10 @@ 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,7 +5,7 @@ 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
|
||||
|
||||
@ -15,6 +15,12 @@ merge_hex=../../tools/solotool.py mergehex
|
||||
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'
|
||||
|
||||
|
@ -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,9 +21,8 @@
|
||||
#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;
|
||||
|
||||
@ -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,7 +2,7 @@ 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 += $(DRIVER_LIBS) $(USB_LIB)
|
||||
|
||||
@ -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:
|
||||
|
@ -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
|
||||
|
@ -6,7 +6,7 @@ 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_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 \
|
||||
|
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;
|
||||
}
|
||||
|
||||
@ -192,6 +192,6 @@ uint8_t *USBD_HID_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
}
|
||||
|
||||
|
||||
USBD_GetString((uint8_t *)uuid_str, USBD_StrDesc, length);
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "stm32l4xx_ll_bus.h"
|
||||
#include "stm32l4xx_ll_tim.h"
|
||||
#include "stm32l4xx_ll_rng.h"
|
||||
#include "stm32l4xx_ll_spi.h"
|
||||
#include "stm32l4xx_ll_usb.h"
|
||||
#include "stm32l4xx_hal_pcd.h"
|
||||
#include "stm32l4xx_hal.h"
|
||||
@ -29,57 +30,86 @@
|
||||
#include "usbd_composite.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "device.h"
|
||||
#include "init.h"
|
||||
#include APP_CONFIG
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
// KHz
|
||||
#define MAX_CLOCK_RATE 24000
|
||||
|
||||
/* USER CODE END Includes */
|
||||
#define SET_CLOCK_RATE2() SystemClock_Config()
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
#if MAX_CLOCK_RATE == 48000
|
||||
#define SET_CLOCK_RATE0() SystemClock_Config_LF32()
|
||||
#define SET_CLOCK_RATE1() SystemClock_Config_LF48()
|
||||
#elif MAX_CLOCK_RATE == 32000
|
||||
#define SET_CLOCK_RATE0() SystemClock_Config_LF24()
|
||||
#define SET_CLOCK_RATE1() SystemClock_Config_LF32()
|
||||
#elif MAX_CLOCK_RATE == 28000
|
||||
#define SET_CLOCK_RATE0() SystemClock_Config_LF24()
|
||||
#define SET_CLOCK_RATE1() SystemClock_Config_LF28()
|
||||
#elif MAX_CLOCK_RATE == 24000
|
||||
#define SET_CLOCK_RATE0() SystemClock_Config_LF16()
|
||||
#define SET_CLOCK_RATE1() SystemClock_Config_LF24()
|
||||
#elif MAX_CLOCK_RATE == 20000
|
||||
#define SET_CLOCK_RATE0() SystemClock_Config_LF16()
|
||||
#define SET_CLOCK_RATE1() SystemClock_Config_LF20()
|
||||
#elif MAX_CLOCK_RATE == 16000
|
||||
#define SET_CLOCK_RATE0() SystemClock_Config_LF8()
|
||||
#define SET_CLOCK_RATE1() SystemClock_Config_LF16()
|
||||
#else
|
||||
#error "Invalid clock rate selected"
|
||||
#endif
|
||||
|
||||
USBD_HandleTypeDef Solo_USBD_Device;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static void LL_Init(void);
|
||||
void SystemClock_Config(void);
|
||||
static void MX_GPIO_Init(void);
|
||||
#if DEBUG_LEVEL > 0
|
||||
static void MX_USART1_UART_Init(void);
|
||||
#endif
|
||||
static void MX_TIM2_Init(void);
|
||||
static void MX_TIM6_Init(void);
|
||||
static void MX_RNG_Init(void);
|
||||
|
||||
#define Error_Handler() _Error_Handler(__FILE__,__LINE__)
|
||||
void _Error_Handler(char *file, int line);
|
||||
|
||||
void SystemClock_Config(void);
|
||||
void SystemClock_Config_LF16(void);
|
||||
void SystemClock_Config_LF20(void);
|
||||
void SystemClock_Config_LF24(void);
|
||||
void SystemClock_Config_LF28(void);
|
||||
void SystemClock_Config_LF48(void);
|
||||
|
||||
void hw_init(void)
|
||||
void hw_init(int lowfreq)
|
||||
{
|
||||
#ifdef IS_BOOTLOADER
|
||||
SCB->VTOR = FLASH_BASE;
|
||||
#else
|
||||
#endif
|
||||
LL_Init();
|
||||
init_gpio();
|
||||
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
if (lowfreq)
|
||||
{
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); // Under voltage
|
||||
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemClock_Config();
|
||||
}
|
||||
|
||||
SystemClock_Config(); // TODO bootloader should not change clk freq.
|
||||
|
||||
MX_GPIO_Init();
|
||||
MX_TIM2_Init(); // PWM for LEDs
|
||||
|
||||
MX_TIM6_Init(); // ~1 ms timer
|
||||
if (!lowfreq)
|
||||
{
|
||||
init_pwm();
|
||||
}
|
||||
|
||||
init_millisecond_timer(lowfreq);
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
MX_USART1_UART_Init();// debug uart
|
||||
init_debug_uart();
|
||||
#endif
|
||||
|
||||
MX_RNG_Init();
|
||||
init_rng();
|
||||
init_spi();
|
||||
|
||||
TIM6->SR = 0;
|
||||
__enable_irq();
|
||||
NVIC_EnableIRQ(TIM6_IRQn);
|
||||
}
|
||||
|
||||
static void LL_Init(void)
|
||||
@ -107,12 +137,29 @@ static void LL_Init(void)
|
||||
|
||||
}
|
||||
|
||||
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
||||
{
|
||||
switch(param)
|
||||
{
|
||||
case DEVICE_LOW_POWER_IDLE:
|
||||
SET_CLOCK_RATE0();
|
||||
break;
|
||||
case DEVICE_LOW_POWER_FAST:
|
||||
SET_CLOCK_RATE1();
|
||||
break;
|
||||
case DEVICE_FAST:
|
||||
SET_CLOCK_RATE2();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
|
||||
|
||||
@ -129,8 +176,15 @@ void SystemClock_Config(void)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
@ -187,7 +241,463 @@ void SystemClock_Config(void)
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
}
|
||||
|
||||
void usb_init()
|
||||
void SystemClock_Config_LF4(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
|
||||
|
||||
LL_Init1msTick(4000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(4000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
// 8MHz
|
||||
void SystemClock_Config_LF8(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_7);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
|
||||
|
||||
LL_Init1msTick(8000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(8000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
// 16MHz
|
||||
void SystemClock_Config_LF16(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_8);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8);
|
||||
|
||||
LL_Init1msTick(16000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(16000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 24 MHz
|
||||
void SystemClock_Config_LF24(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_9);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8);
|
||||
|
||||
LL_Init1msTick(24000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(24000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
|
||||
}
|
||||
|
||||
// 32 MHz
|
||||
void SystemClock_Config_LF32(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_10);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16);
|
||||
|
||||
LL_Init1msTick(32000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(32000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
|
||||
}
|
||||
|
||||
// 28 MHz
|
||||
void SystemClock_Config_LF28(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
|
||||
LL_RCC_HSI_Enable();
|
||||
|
||||
/* Wait till HSI is ready */
|
||||
while(LL_RCC_HSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_HSI_SetCalibTrimming(16);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_2, 28, LL_RCC_PLLR_DIV_8);
|
||||
|
||||
LL_RCC_PLL_EnableDomain_SYS();
|
||||
|
||||
LL_RCC_PLL_Enable();
|
||||
|
||||
/* Wait till PLL is ready */
|
||||
while(LL_RCC_PLL_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_8);
|
||||
|
||||
LL_Init1msTick(28000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(28000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
}
|
||||
|
||||
// 48 MHz
|
||||
void SystemClock_Config_LF48(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
|
||||
|
||||
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
|
||||
LL_RCC_LSI_Enable();
|
||||
|
||||
/* Wait till LSI is ready */
|
||||
while(LL_RCC_LSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_Enable();
|
||||
|
||||
/* Wait till MSI is ready */
|
||||
while(LL_RCC_MSI_IsReady() != 1)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_MSI_EnableRangeSelection();
|
||||
|
||||
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_11);
|
||||
|
||||
LL_RCC_MSI_SetCalibTrimming(0);
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
|
||||
|
||||
/* Wait till System clock is ready */
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
|
||||
{
|
||||
|
||||
}
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_16);
|
||||
|
||||
LL_Init1msTick(48000000);
|
||||
|
||||
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
LL_SetSystemCoreClock(48000000);
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
|
||||
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_MSI);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 20 MHz
|
||||
void SystemClock_Config_LF20(void)
|
||||
{
|
||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||
}
|
||||
|
||||
void init_usb()
|
||||
{
|
||||
// enable USB power
|
||||
SET_BIT(PWR->CR2, PWR_CR2_USV);
|
||||
@ -217,8 +727,7 @@ void usb_init()
|
||||
USBD_Start(&Solo_USBD_Device);
|
||||
}
|
||||
|
||||
/* TIM2 init function */
|
||||
static void MX_TIM2_Init(void)
|
||||
void init_pwm(void)
|
||||
{
|
||||
|
||||
LL_TIM_InitTypeDef TIM_InitStruct;
|
||||
@ -289,9 +798,7 @@ static void MX_TIM2_Init(void)
|
||||
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
/* USART1 init function */
|
||||
static void MX_USART1_UART_Init(void)
|
||||
void init_debug_uart(void)
|
||||
{
|
||||
|
||||
LL_USART_InitTypeDef USART_InitStruct;
|
||||
@ -301,6 +808,8 @@ static void MX_USART1_UART_Init(void)
|
||||
/* Peripheral clock enable */
|
||||
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
|
||||
|
||||
|
||||
LL_USART_DeInit(USART1);
|
||||
/**USART1 GPIO Configuration
|
||||
PB6 ------> USART1_TX
|
||||
PB7 ------> USART1_RX
|
||||
@ -327,22 +836,37 @@ static void MX_USART1_UART_Init(void)
|
||||
LL_USART_Enable(USART1);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Pinout Configuration
|
||||
*/
|
||||
static void MX_GPIO_Init(void)
|
||||
void init_gpio(void)
|
||||
{
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
#ifdef SOLO_AMS_IRQ_PORT
|
||||
// SAVE POWER
|
||||
// LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
|
||||
// /**/
|
||||
// LL_GPIO_InitTypeDef GPIO_InitStruct;
|
||||
// GPIO_InitStruct.Pin = SOLO_AMS_IRQ_PIN;
|
||||
// GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
|
||||
// GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
// LL_GPIO_Init(SOLO_AMS_IRQ_PORT, &GPIO_InitStruct);
|
||||
//
|
||||
//
|
||||
// LL_GPIO_SetPinMode(SOLO_AMS_IRQ_PORT,SOLO_AMS_IRQ_PIN,LL_GPIO_MODE_INPUT);
|
||||
// LL_GPIO_SetPinPull(SOLO_AMS_IRQ_PORT,SOLO_AMS_IRQ_PIN,LL_GPIO_PULL_UP);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* TIM6 init function */
|
||||
static void MX_TIM6_Init(void)
|
||||
void init_millisecond_timer(int lf)
|
||||
{
|
||||
|
||||
LL_TIM_InitTypeDef TIM_InitStruct;
|
||||
@ -352,7 +876,11 @@ static void MX_TIM6_Init(void)
|
||||
|
||||
// 48 MHz sys clock --> 6 MHz timer clock
|
||||
// 48 MHz / 48000 == 1000 Hz
|
||||
if (!lf)
|
||||
TIM_InitStruct.Prescaler = 48000;
|
||||
else
|
||||
TIM_InitStruct.Prescaler = MAX_CLOCK_RATE;
|
||||
|
||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||
TIM_InitStruct.Autoreload = 90;
|
||||
LL_TIM_Init(TIM6, &TIM_InitStruct);
|
||||
@ -368,39 +896,14 @@ static void MX_TIM6_Init(void)
|
||||
|
||||
// Start immediately
|
||||
LL_TIM_EnableCounter(TIM6);
|
||||
|
||||
TIM6->SR = 0;
|
||||
__enable_irq();
|
||||
NVIC_EnableIRQ(TIM6_IRQn);
|
||||
}
|
||||
|
||||
/* TIM7 init function */
|
||||
// static void MX_TIM7_Init(void)
|
||||
// {
|
||||
//
|
||||
// LL_TIM_InitTypeDef TIM_InitStruct;
|
||||
//
|
||||
// /* Peripheral clock enable */
|
||||
// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
|
||||
//
|
||||
// // 48 MHz sys clock --> 6 MHz timer clock
|
||||
// // 6 MHz / 6000 == 1000 Hz
|
||||
// TIM_InitStruct.Prescaler = 48000;
|
||||
// TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||
// TIM_InitStruct.Autoreload = 0xffff;
|
||||
// LL_TIM_Init(TIM6, &TIM_InitStruct);
|
||||
//
|
||||
// LL_TIM_DisableARRPreload(TIM7);
|
||||
//
|
||||
// LL_TIM_SetTriggerOutput(TIM7, LL_TIM_TRGO_RESET);
|
||||
//
|
||||
// LL_TIM_DisableMasterSlaveMode(TIM7);
|
||||
//
|
||||
// // enable interrupt
|
||||
// TIM7->DIER |= 1;
|
||||
//
|
||||
// // Start immediately
|
||||
// LL_TIM_EnableCounter(TIM7);
|
||||
// }
|
||||
|
||||
/* RNG init function */
|
||||
static void MX_RNG_Init(void)
|
||||
void init_rng(void)
|
||||
{
|
||||
|
||||
/* Peripheral clock enable */
|
||||
@ -409,3 +912,45 @@ static void MX_RNG_Init(void)
|
||||
LL_RNG_Enable(RNG);
|
||||
|
||||
}
|
||||
|
||||
/* SPI1 init function */
|
||||
void init_spi(void)
|
||||
{
|
||||
|
||||
LL_SPI_InitTypeDef SPI_InitStruct;
|
||||
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct;
|
||||
|
||||
/* Peripheral clock enable */
|
||||
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
|
||||
|
||||
/**SPI1 GPIO Configuration
|
||||
PA5 ------> SPI1_SCK
|
||||
PA6 ------> SPI1_MISO
|
||||
PA7 ------> SPI1_MOSI
|
||||
*/
|
||||
GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_6|LL_GPIO_PIN_7;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* SPI1 parameter configuration*/
|
||||
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
|
||||
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
|
||||
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
|
||||
SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
|
||||
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
|
||||
SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
|
||||
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
|
||||
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
|
||||
SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
|
||||
SPI_InitStruct.CRCPoly = 7;
|
||||
LL_SPI_Init(SPI1, &SPI_InitStruct);
|
||||
|
||||
LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
|
||||
|
||||
|
||||
}
|
||||
|
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);
|
||||
|
||||
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
|
||||
|
@ -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.*/
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
1055
tools/ctap_test.py
1055
tools/ctap_test.py
File diff suppressed because it is too large
Load Diff
@ -2,5 +2,6 @@ ecdsa
|
||||
fido2
|
||||
intelhex
|
||||
pyserial
|
||||
solo-python
|
||||
pyusb
|
||||
wheel
|
||||
|
1085
tools/solotool.py
1085
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