Compare commits

..

1 Commits
ccid ... 1.1.0

Author SHA1 Message Date
6a92423f25 Create CHANGELOG.md 2019-02-17 16:16:29 -05:00
122 changed files with 17341 additions and 10793 deletions

View File

@ -1,188 +0,0 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "szszszsz",
"name": "Szczepan Zalega",
"avatar_url": "https://avatars0.githubusercontent.com/u/17005426?v=4",
"profile": "https://github.com/szszszsz",
"contributions": [
"code",
"doc",
"ideas"
]
},
{
"login": "Wesseldr",
"name": "Wessel dR",
"avatar_url": "https://avatars1.githubusercontent.com/u/4012809?v=4",
"profile": "https://github.com/Wesseldr",
"contributions": [
"doc"
]
},
{
"login": "agl",
"name": "Adam Langley",
"avatar_url": "https://avatars3.githubusercontent.com/u/21203?v=4",
"profile": "https://www.imperialviolet.org",
"contributions": [
"bug",
"code"
]
},
{
"login": "merlokk",
"name": "Oleg Moiseenko",
"avatar_url": "https://avatars2.githubusercontent.com/u/807634?v=4",
"profile": "http://www.lotteam.com",
"contributions": [
"code"
]
},
{
"login": "aseigler",
"name": "Alex Seigler",
"avatar_url": "https://avatars1.githubusercontent.com/u/6605560?v=4",
"profile": "https://github.com/aseigler",
"contributions": [
"bug"
]
},
{
"login": "dschuermann",
"name": "Dominik Schürmann",
"avatar_url": "https://avatars3.githubusercontent.com/u/321888?v=4",
"profile": "https://www.cotech.de/services/",
"contributions": [
"bug"
]
},
{
"login": "ehershey",
"name": "Ernie Hershey",
"avatar_url": "https://avatars0.githubusercontent.com/u/286008?v=4",
"profile": "https://github.com/ehershey",
"contributions": [
"doc"
]
},
{
"login": "YakBizzarro",
"name": "Andrea Corna",
"avatar_url": "https://avatars1.githubusercontent.com/u/767740?v=4",
"profile": "https://github.com/YakBizzarro",
"contributions": [
"infra"
]
},
{
"login": "pjz",
"name": "Paul Jimenez",
"avatar_url": "https://avatars3.githubusercontent.com/u/11100?v=4",
"profile": "https://place.org/~pj/",
"contributions": [
"infra",
"code"
]
},
{
"login": "yparitcher",
"name": "yparitcher",
"avatar_url": "https://avatars0.githubusercontent.com/u/38916402?v=4",
"profile": "https://github.com/yparitcher",
"contributions": [
"ideas",
"maintenance"
]
},
{
"login": "StoyanDimitrov",
"name": "StoyanDimitrov",
"avatar_url": "https://avatars1.githubusercontent.com/u/10962709?v=4",
"profile": "https://github.com/StoyanDimitrov",
"contributions": [
"doc"
]
},
{
"login": "alphathegeek",
"name": "alphathegeek",
"avatar_url": "https://avatars2.githubusercontent.com/u/51253712?v=4",
"profile": "https://github.com/alphathegeek",
"contributions": [
"ideas"
]
},
{
"login": "rgerganov",
"name": "Radoslav Gerganov",
"avatar_url": "https://avatars2.githubusercontent.com/u/271616?v=4",
"profile": "https://xakcop.com",
"contributions": [
"ideas",
"code"
]
},
{
"login": "manuel-domke",
"name": "Manuel Domke",
"avatar_url": "https://avatars3.githubusercontent.com/u/10274356?v=4",
"profile": "http://13-37.org",
"contributions": [
"ideas",
"code",
"business"
]
},
{
"login": "esden",
"name": "Piotr Esden-Tempski",
"avatar_url": "https://avatars3.githubusercontent.com/u/17334?v=4",
"profile": "http://1bitsquared.com",
"contributions": [
"business"
]
},
{
"login": "m3hm00d",
"name": "f.m3hm00d",
"avatar_url": "https://avatars1.githubusercontent.com/u/42179593?v=4",
"profile": "https://github.com/m3hm00d",
"contributions": [
"doc"
]
},
{
"login": "hughsie",
"name": "Richard Hughes",
"avatar_url": "https://avatars0.githubusercontent.com/u/151380?v=4",
"profile": "http://blogs.gnome.org/hughsie/",
"contributions": [
"ideas",
"code",
"infra",
"tool"
]
},
{
"login": "kimusan",
"name": "Kim Schulz",
"avatar_url": "https://avatars1.githubusercontent.com/u/1150049?v=4",
"profile": "http://www.schulz.dk",
"contributions": [
"business",
"ideas"
]
}
],
"contributorsPerLine": 7,
"projectName": "solo",
"projectOwner": "solokeys",
"repoType": "github",
"repoHost": "https://github.com"
}

12
.gitignore vendored
View File

@ -81,7 +81,15 @@ env3/
.tags* .tags*
targets/*/docs/ targets/*/docs/
main 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/* builds/*
tools/testing/.idea/*
tools/testing/tests/__pycache__/*

6
.gitmodules vendored
View File

@ -1,6 +1,9 @@
[submodule "tinycbor"] [submodule "tinycbor"]
path = tinycbor path = tinycbor
url = https://github.com/intel/tinycbor url = https://github.com/intel/tinycbor
[submodule "python-fido2"]
path = python-fido2
url = https://github.com/solokeys/python-fido2
[submodule "crypto/micro-ecc"] [submodule "crypto/micro-ecc"]
path = crypto/micro-ecc path = crypto/micro-ecc
url = https://github.com/kmackay/micro-ecc.git url = https://github.com/kmackay/micro-ecc.git
@ -10,6 +13,3 @@
[submodule "targets/stm32l442/dfuse-tool"] [submodule "targets/stm32l442/dfuse-tool"]
path = targets/stm32l442/dfuse-tool path = targets/stm32l442/dfuse-tool
url = https://github.com/solokeys/dfuse-tool url = https://github.com/solokeys/dfuse-tool
[submodule "crypto/cifra"]
path = crypto/cifra
url = https://github.com/solokeys/cifra.git

View File

@ -1 +0,0 @@
udev/70-solokeys-access.rules

28
99-solo.rules Normal file
View File

@ -0,0 +1,28 @@
# 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"

View File

@ -1 +0,0 @@
2.0.0

17
CHANGELOG.md Normal file
View 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

View File

@ -14,7 +14,7 @@ RUN echo "fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 gcc.
RUN sha256sum -c gcc.sha256 RUN sha256sum -c gcc.sha256
RUN tar -C /opt -xf gcc.tar.bz2 RUN tar -C /opt -xf gcc.tar.bz2
# 2. Python3.7: for solo-python (merging etc.) # 2. Python3.7: for solotool (merging etc.)
RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh RUN wget -q -O miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh
# from website # from website
RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5 RUN echo "866ae9dff53ad0874e1d1a60b1ad1ef8 miniconda.sh" > miniconda.md5
@ -24,10 +24,8 @@ RUN echo "e5e5b4cd2a918e0e96b395534222773f7241dc59d776db1b9f7fedfcb489157a mini
RUN sha256sum -c miniconda.sha256 RUN sha256sum -c miniconda.sha256
RUN bash ./miniconda.sh -b -p /opt/conda RUN bash ./miniconda.sh -b -p /opt/conda
RUN ln -s /opt/conda/bin/python /usr/local/bin/python3 RUN ln -s /opt/conda/bin/python3 /usr/local/bin/python3
RUN ln -s /opt/conda/bin/python /usr/local/bin/python RUN ln -s /opt/conda/bin/python3 /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 # 3. Source code
RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input RUN git clone --recurse-submodules https://github.com/solokeys/solo /solo --config core.autocrlf=input

View File

@ -1 +0,0 @@
Apache-2.0 OR MIT

View File

@ -9,9 +9,7 @@
ecc_platform=2 ecc_platform=2
src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard fido2/extensions/*.c) \ src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c
$(wildcard crypto/sha256/*.c) crypto/tiny-AES-c/aes.c
obj = $(src:.c=.o) crypto/micro-ecc/uECC.o obj = $(src:.c=.o) crypto/micro-ecc/uECC.o
LIBCBOR = tinycbor/lib/libtinycbor.a LIBCBOR = tinycbor/lib/libtinycbor.a
@ -22,20 +20,9 @@ else
export LDFLAGS = -Wl,--gc-sections export LDFLAGS = -Wl,--gc-sections
endif endif
LDFLAGS += $(LIBCBOR) LDFLAGS += $(LIBCBOR)
CFLAGS = -O2 -fdata-sections -ffunction-sections
VERSION:=$(shell git describe --abbrev=0 )
VERSION_FULL:=$(shell git describe)
VERSION_MAJ:=$(shell python -c 'print("$(VERSION)".split(".")[0])')
VERSION_MIN:=$(shell python -c 'print("$(VERSION)".split(".")[1])')
VERSION_PAT:=$(shell python -c 'print("$(VERSION)".split(".")[2])')
VERSION_FLAGS= -DSOLO_VERSION_MAJ=$(VERSION_MAJ) -DSOLO_VERSION_MIN=$(VERSION_MIN) \
-DSOLO_VERSION_PATCH=$(VERSION_PAT) -DSOLO_VERSION=\"$(VERSION_FULL)\"
CFLAGS = -O2 -fdata-sections -ffunction-sections $(VERSION_FLAGS) -g
INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions INCLUDES = -I./tinycbor/src -I./crypto/sha256 -I./crypto/micro-ecc/ -Icrypto/tiny-AES-c/ -I./fido2/ -I./pc -I./fido2/extensions
INCLUDES += -I./crypto/cifra/src
CFLAGS += $(INCLUDES) CFLAGS += $(INCLUDES)
# for crypto/tiny-AES-c # for crypto/tiny-AES-c
@ -53,7 +40,7 @@ tinycbor/Makefile crypto/tiny-AES-c/aes.c:
cbor: $(LIBCBOR) cbor: $(LIBCBOR)
$(LIBCBOR): $(LIBCBOR):
cd tinycbor/ && $(MAKE) clean && $(MAKE) LDFLAGS='' -j8 cd tinycbor/ && $(MAKE) clean && $(MAKE) -j8
version: version:
@git describe @git describe
@ -74,7 +61,6 @@ crypto/micro-ecc/uECC.o: ./crypto/micro-ecc/uECC.c
venv: venv:
python3 -m venv 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 -r tools/requirements.txt
venv/bin/pip -q install --upgrade black venv/bin/pip -q install --upgrade black
@ -83,7 +69,7 @@ black: venv
venv/bin/black --skip-string-normalization --check tools/ venv/bin/black --skip-string-normalization --check tools/
wink: venv wink: venv
venv/bin/solo key wink venv/bin/python tools/solotool.py solo --wink
fido2-test: venv fido2-test: venv
venv/bin/python tools/ctap_test.py venv/bin/python tools/ctap_test.py
@ -94,12 +80,7 @@ docker-build:
docker build -t $(DOCKER_IMAGE) . docker build -t $(DOCKER_IMAGE) .
docker run --rm -v "$(CURDIR)/builds:/builds" \ docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \ -v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH) $(DOCKER_IMAGE) /in-docker-build.sh $(SOLO_VERSIONISH)
uncached-docker-build:
docker build --no-cache -t $(DOCKER_IMAGE) .
docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
CPPCHECK_FLAGS=--quiet --error-exitcode=2 CPPCHECK_FLAGS=--quiet --error-exitcode=2

120
README.md
View File

@ -1,20 +1,19 @@
**NEW!** We launched a new tiny security key called Somu, it's live on Crowd Supply and you can [pre-order it now](https://solokeys.com/somu)! [![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[<img src="https://miro.medium.com/max/1400/1*PnzCPLqq_5nt1gjgSEY2LQ.png" width="600">](https://solokeys.com/somu) [![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com)
Somu is the micro version of Solo. We were inspired to make a secure Tomu, so we took its tiny form factor, we added the secure microcontroller and firmware of Solo, et voilà! Here we have Somu.
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://update.solokeys.com/)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public) [![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?style=flat-square&branch=master)](https://travis-ci.com/solokeys/solo) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield)
# Solo
Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com). Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com).
[<img src="https://static.solokeys.com/images/photos/hero-on-white-cropped.png" width="600">](https://solokeys.com)
Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe. Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe.
This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, but it is easily portable. <img src="https://solokeys.com/images/photos/hero-on-white-cropped.png" width="600">
This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, and it's ported to NRF52840 and EFM32J.
For development no hardware is needed, Solo also runs as a standalone application for Windows, Linux, and Mac OSX. If you like (or want to learn) hardware instead, you can run Solo on the NUCLEO-L432KC development board, or we make Solo for Hacker, an unlocked version of Solo that lets you customize its firmware. For development no hardware is needed, Solo also runs as a standalone application for Windows, Linux, and Mac OSX. If you like (or want to learn) hardware instead, you can run Solo on the NUCLEO-L432KC development board, or we make Solo for Hacker, an unlocked version of Solo that lets you customize its firmware.
@ -34,9 +33,9 @@ Solo is based on the STM32L432 microcontroller. It offers the following security
Solo for Hacker is a special version of Solo that let you customize its firmware, for example you can change the LED color, and even build advanced applications. Solo for Hacker is a special version of Solo that let you customize its firmware, for example you can change the LED color, and even build advanced applications.
Check out [solokeys.com](https://solokeys.com), for options on where to buy Solo. Solo Hacker can be converted to a secure version, but normal Solo cannot be converted to a Hacker version. You can only buy Solo for Hacker at [solokeys.com](https://solokeys.com), as we don't sell it on Amazon and other places to avoid confusing customers. If you buy a Hacker, you can permanently lock it into a regular Solo, but viceversa you can NOT take a regular Solo and turn it a Hacker.
If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We support Python3. If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We only support Python3.
```bash ```bash
git clone --recurse-submodules https://github.com/solokeys/solo git clone --recurse-submodules https://github.com/solokeys/solo
@ -49,22 +48,24 @@ cd ../..
make venv make venv
source venv/bin/activate source venv/bin/activate
solo program aux enter-bootloader python tools/solotool.py program targets/stm32l432/solo.hex
solo program bootloader targets/stm32l432/solo.hex
``` ```
Alternatively, run `make docker-build` and use the firmware generated in `/tmp`. Alternatively, run `make docker-build` and use the firmware generated in `/tmp`.
If you forgot the `--recurse-submodules` when cloning, simply `git submodule update --init --recursive`. If you forgot the `--recurse-submodules` when cloning, simply `git submodule update --init --recursive`.
For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/app.h#L48) and change `LED_INIT_VALUE` For example, if you want to turn off any blue light emission, you can edit [`led_rgb()`](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/led.c#L15) and force:
to be a different hex color. ```
uint32_t b = 0;
```
Then recompile, load your new firmware, and enjoy a different LED color Solo. Then recompile, load your new firmware, and enjoy a blue-light-free version of Solo.
In the Hacker version, hardware is the same but the firmware is unlocked, so you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently. In the Hacker version, hardware is the same and firmware is unlocked, in the sense that you can 1) load an unsigned application, or 2) entirely reflash the key. By contrast, in a regular Solo you can only upgrade to a firmware signed by SoloKeys, and flash is locked and debug disabled permanently.
A frequently asked question is whether Solo for Hacker is less secure than regular Solo. The answer is certainly yes, and therefore we only recommend to use Solo for Hacker for development, experimentation, and fun. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
Hacker Solo isn't really secure so you should only use it for development. An attacker with physical access to a Solo for Hacker can reflash it following the steps above, and even a malware on your computer could possibly reflash it.
# Developing Solo (No Hardware Needed) # Developing Solo (No Hardware Needed)
@ -81,7 +82,7 @@ This builds Solo as a standalone application. Solo application is set up to send
Testing can be done using our fork of Yubico's client software, python-fido2. Our fork of python-fido2 has small changes to make it send USB HID over UDP to the authenticator application. You can install our fork by running the following: Testing can be done using our fork of Yubico's client software, python-fido2. Our fork of python-fido2 has small changes to make it send USB HID over UDP to the authenticator application. You can install our fork by running the following:
```bash ```bash
pip install -r tools/requirements.txt cd python-fido2 && python setup.py install
``` ```
Run the Solo application: Run the Solo application:
@ -89,7 +90,15 @@ Run the Solo application:
./main ./main
``` ```
In another shell, you can run our [test suite](https://github.com/solokeys/fido2-tests). In another shell, you can run client software, for example our tests:
```bash
python tools/ctap_test.py
```
Or any client example such as:
```bash
python python-fido2/examples/credential.py
```
You can find more details in our [documentation](https://docs.solokeys.io/solo/), including how to build on the the NUCLEO-L432KC development board. You can find more details in our [documentation](https://docs.solokeys.io/solo/), including how to build on the the NUCLEO-L432KC development board.
@ -99,62 +108,20 @@ You can find more details in our [documentation](https://docs.solokeys.io/solo/)
Check out our [official documentation](https://docs.solokeys.io/solo/). Check out our [official documentation](https://docs.solokeys.io/solo/).
# Contributors # Contributors
Solo is an upgrade to [U2F Zero](https://github.com/conorpp/u2f-zero). It was born from Conor's passion for making secure hardware, and from our shared belief that security should be open to be trustworthy, in hardware like in software. Solo is an upgrade to [U2F Zero](https://github.com/conorpp/u2f-zero). It was born from Conor's passion for making secure hardware, and from our shared belief that security should be open to be trustworthy, in hardware like in software.
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! Contributors are welcome. The ultimate goal is to have a FIDO2 security key supporting USB, NFC, and BLE interfaces, that can run on a variety of MCUs.
The ultimate goal is to have a FIDO2 security key supporting USB, NFC, and BLE interfaces, that can run on a variety of MCUs.
Look at the issues to see what is currently being worked on. Feel free to add issues as well. Look at the issues to see what is currently being worked on. Feel free to add issues as well.
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
<table>
<tr>
<td align="center"><a href="https://github.com/szszszsz"><img src="https://avatars0.githubusercontent.com/u/17005426?v=4" width="100px;" alt="Szczepan Zalega"/><br /><sub><b>Szczepan Zalega</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=szszszsz" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=szszszsz" title="Documentation">📖</a> <a href="#ideas-szszszsz" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/Wesseldr"><img src="https://avatars1.githubusercontent.com/u/4012809?v=4" width="100px;" alt="Wessel dR"/><br /><sub><b>Wessel dR</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=Wesseldr" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.imperialviolet.org"><img src="https://avatars3.githubusercontent.com/u/21203?v=4" width="100px;" alt="Adam Langley"/><br /><sub><b>Adam Langley</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aagl" title="Bug reports">🐛</a> <a href="https://github.com/solokeys/solo/commits?author=agl" title="Code">💻</a></td>
<td align="center"><a href="http://www.lotteam.com"><img src="https://avatars2.githubusercontent.com/u/807634?v=4" width="100px;" alt="Oleg Moiseenko"/><br /><sub><b>Oleg Moiseenko</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=merlokk" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/aseigler"><img src="https://avatars1.githubusercontent.com/u/6605560?v=4" width="100px;" alt="Alex Seigler"/><br /><sub><b>Alex Seigler</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aaseigler" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://www.cotech.de/services/"><img src="https://avatars3.githubusercontent.com/u/321888?v=4" width="100px;" alt="Dominik Schürmann"/><br /><sub><b>Dominik Schürmann</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Adschuermann" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/ehershey"><img src="https://avatars0.githubusercontent.com/u/286008?v=4" width="100px;" alt="Ernie Hershey"/><br /><sub><b>Ernie Hershey</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=ehershey" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/YakBizzarro"><img src="https://avatars1.githubusercontent.com/u/767740?v=4" width="100px;" alt="Andrea Corna"/><br /><sub><b>Andrea Corna</b></sub></a><br /><a href="#infra-YakBizzarro" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center"><a href="https://place.org/~pj/"><img src="https://avatars3.githubusercontent.com/u/11100?v=4" width="100px;" alt="Paul Jimenez"/><br /><sub><b>Paul Jimenez</b></sub></a><br /><a href="#infra-pjz" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/solokeys/solo/commits?author=pjz" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/yparitcher"><img src="https://avatars0.githubusercontent.com/u/38916402?v=4" width="100px;" alt="yparitcher"/><br /><sub><b>yparitcher</b></sub></a><br /><a href="#ideas-yparitcher" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-yparitcher" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/StoyanDimitrov"><img src="https://avatars1.githubusercontent.com/u/10962709?v=4" width="100px;" alt="StoyanDimitrov"/><br /><sub><b>StoyanDimitrov</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=StoyanDimitrov" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/alphathegeek"><img src="https://avatars2.githubusercontent.com/u/51253712?v=4" width="100px;" alt="alphathegeek"/><br /><sub><b>alphathegeek</b></sub></a><br /><a href="#ideas-alphathegeek" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://xakcop.com"><img src="https://avatars2.githubusercontent.com/u/271616?v=4" width="100px;" alt="Radoslav Gerganov"/><br /><sub><b>Radoslav Gerganov</b></sub></a><br /><a href="#ideas-rgerganov" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=rgerganov" title="Code">💻</a></td>
<td align="center"><a href="http://13-37.org"><img src="https://avatars3.githubusercontent.com/u/10274356?v=4" width="100px;" alt="Manuel Domke"/><br /><sub><b>Manuel Domke</b></sub></a><br /><a href="#ideas-manuel-domke" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=manuel-domke" title="Code">💻</a> <a href="#business-manuel-domke" title="Business development">💼</a></td>
</tr>
<tr>
<td align="center"><a href="http://1bitsquared.com"><img src="https://avatars3.githubusercontent.com/u/17334?v=4" width="100px;" alt="Piotr Esden-Tempski"/><br /><sub><b>Piotr Esden-Tempski</b></sub></a><br /><a href="#business-esden" title="Business development">💼</a></td>
<td align="center"><a href="https://github.com/m3hm00d"><img src="https://avatars1.githubusercontent.com/u/42179593?v=4" width="100px;" alt="f.m3hm00d"/><br /><sub><b>f.m3hm00d</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=m3hm00d" title="Documentation">📖</a></td>
<td align="center"><a href="http://blogs.gnome.org/hughsie/"><img src="https://avatars0.githubusercontent.com/u/151380?v=4" width="100px;" alt="Richard Hughes"/><br /><sub><b>Richard Hughes</b></sub></a><br /><a href="#ideas-hughsie" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=hughsie" title="Code">💻</a> <a href="#infra-hughsie" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#tool-hughsie" title="Tools">🔧</a></td>
<td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
</table>
<!-- ALL-CONTRIBUTORS-LIST:END -->
# License # License
Solo is fully open source. Solo is fully open source.
All software, unless otherwise noted, is dual licensed under Apache 2.0 and MIT. All software, unless otherwise noted, is dual licensed under Apache 2.0 and MIT.
You may use Solo software under the terms of either the Apache 2.0 license or MIT license. You may use Solo under the terms of either the Apache 2.0 license or MIT license.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
All hardware, unless otherwise noted, is dual licensed under CERN and CC-BY-SA.
You may use Solo hardware under the terms of either the CERN 2.1 license or CC-BY-SA 4.0 license.
All documentation, unless otherwise noted, is licensed under CC-BY-SA.
You may use Solo documentation under the terms of the CC-BY-SA 4.0 license
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_large) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_large)
@ -162,20 +129,3 @@ You may use Solo documentation under the terms of the CC-BY-SA 4.0 license
# Where To Buy Solo # Where To Buy Solo
You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com). You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com).
<br/>
<hr/>
<br/>
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield)
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://github.com/solokeys/solo/releases)
[![commits since last release](https://img.shields.io/github/commits-since/solokeys/solo/latest.svg)](https://github.com/solokeys/solo/commits/master)
[![last commit](https://img.shields.io/github/last-commit/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![commit activity](https://img.shields.io/github/commit-activity/m/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![contributors](https://img.shields.io/github/contributors/solokeys/solo.svg)](https://github.com/solokeys/solo/graphs/contributors)

View File

@ -1,32 +0,0 @@
# Security Policy
## Supported Versions
We fix security issues as soon as they are found, and release firmware updates.
Each such release is accompanied by release notes, see <https://github.com/solokeys/solo/releases>.
The latest version can be determined using the file <https://github.com/solokeys/solo/blob/master/STABLE_VERSION>.
To update your key:
- either visit <https://update.solokeys.com>, or
- use our commandline tool <https://github.com/solokeys/solo-python>:
```
solo key update [--secure|--hacker]
```
## Reporting a Vulnerability
To report vulnerabilities you have found:
- preferably contact [@conor1](https://keybase.io/conor1), [@0x0ece](https://keybase.io/0x0ece) or [@nickray](https://keybase.io/nickray) via Keybase, or
- send us e-mail using OpenPGP to [security@solokeys.com](mailto:security@solokeys.com).
<https://keys.openpgp.org/vks/v1/by-fingerprint/85AFA2769F4381E5712C36A04DDFC46FEF1F7F3F>
We do not currently run a paid bug bounty program, but are happy to provide you with a bunch of Solo keys in recognition of your findings.
## Mailing List
Join our release notification mailing list to be informed about each release:
https://sendy.solokeys.com/subscription?f=9MLIqMDmox1Ucz89C892Kq09IqYMM7OB8UrBrkvtTkDI763QF3L5PMYlRhlVNo2AI892mO

View File

@ -1 +0,0 @@
2.4.3

Submodule crypto/cifra deleted from d04dd31860

View File

@ -1,51 +0,0 @@
# Booting into bootloader mode
You can put Solo into bootloader mode by holding down the button, and plugging in Solo. After 2 seconds, bootloader mode will activate.
You'll see a yellowish flashing light and you can let go of the button.
Now Solo is ready to [accept firmware updates](/solo/signed-updates). If the Solo is a secured model, it can only accept signed updates, typically in the `firmware-*.json` format.
If Solo is running a hacker build, it can be put into bootloader mode on command. This makes it easier for development.
```bash
solo program aux enter-bootloader
```
# The boot stages of Solo
Solo has 3 boot stages.
## DFU
The first stage is the DFU (Device Firmware Update) which is in a ROM on Solo. It is baked into the chip and is not implemented by us.
This is what allows the entire firmware of Solo to be programmed. **It's not recommended to develop for Solo using the DFU because
if you program broken firmware, you could brick your device**.
On hacker devices, you can boot into the DFU by holding down the button for 5 seconds, when Solo is already in bootloader mode.
You can also run this command when Solo is in bootloader mode to put it in DFU mode.
```bash
solo program aux enter-dfu
```
Note it will stay in DFU mode until to tell it to boot again. You can boot it again by running the following.
```bash
solo program aux leave-dfu
```
*Warning*: If you change the firmware to something broken, and you tell the DFU to boot it, you could brick your device.
## Solo Bootloader
The next boot stage is the "Solo bootloader". So when we say to put your Solo into bootloader mode, it is this stage.
This bootloader is written by us and allows signed firmware updates to be written. On Solo Hackers, there is no signature checking
and will allow any firmware updates.
It is safe to develop for Solo using our Solo bootloader. If broken firmware is uploaded to the device, then the Solo
bootloader can always be booted again by holding down the button when plugging in.
## Solo application
This is what contains all the important functionality of Solo. FIDO2, U2F, etc. This is what Solo will boot to by default.

View File

@ -1,34 +1,22 @@
# Building solo
To build, develop and debug the firmware for the STM32L432. This will work To build, develop and debug the firmware for the STM32L432. This will work
for Solo Hacker, the Nucleo development board, or your own homemade Solo. for Solo Hacker, the Nucleo development board, or you own homemade Solo.
There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; The board does contain a debugger, so all you need is a USB cable (and some [udev](/udev) [rules](https://rust-embedded.github.io/book/intro/install/linux.html#udev-rules)). There exists a development board [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) you can use; The board does contain a debugger, so all you need is a USB cable (and some [udev](/udev) [rules](https://rust-embedded.github.io/book/intro/install/linux.html#udev-rules)).
## Prerequisites # Prerequisites
Install the [latest ARM compiler toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) for your system. We recommend getting the latest compilers from ARM. Install the [latest ARM compiler toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) for your system. We recommend getting the latest compilers from ARM.
You can also install the ARM toolchain using a package manager like `apt-get` or `pacman`, You can also install the ARM toolchain using a package manage like `apt-get` or `pacman`,
but be warned they might be out of date. Typically it will be called `gcc-arm-none-eabi binutils-arm-none-eabi`. but be warned they might be out of date. Typically it will be called `gcc-arm-none-eabi binutils-arm-none-eabi`.
Install `solo-python` usually with `pip3 install solo-python`. The `solo` python application may also be used for [programming](#programming). To program your build, you'll need one of the following programs.
## Obtain source code and solo tool - [openocd](http://openocd.org)
- [stlink](https://github.com/texane/stlink)
- [STM32CubeProg](https://www.st.com/en/development-tools/stm32cubeprog.html)
Source code can be downloaded from: # Compilation
- [github releases list](https://github.com/solokeys/solo/releases)
- [github repository](https://github.com/solokeys/solo)
**solo** tool can be downloaded from:
- from python programs [repository](https://pypi.org/project/solo-python/) `pip install solo-python`
- from installing prerequisites `pip3 install -r tools/requirements.txt`
- github repository: [repository](https://github.com/solokeys/solo-python)
- installation python enviroment with command `make venv` from root directory of source code
## Compilation
Enter the `stm32l4xx` target directory. Enter the `stm32l4xx` target directory.
@ -48,7 +36,7 @@ enabled, like being able to jump to the bootloader on command. It then merges b
and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex` and solo builds into the same binary. I.e. it combines `bootloader.hex` and `solo.hex`
into `all.hex`. into `all.hex`.
If you're just planning to do development, **please don't try to reprogram the bootloader**, If you're just planning to do development, please don't try to reprogram the bootloader,
as this can be risky if done often. Just use `solo.hex`. as this can be risky if done often. Just use `solo.hex`.
### Building with debug messages ### Building with debug messages
@ -64,14 +52,14 @@ make build-hacker DEBUG=1
``` ```
If you use `DEBUG=2`, that means Solo will not boot until something starts reading If you use `DEBUG=2`, that means Solo will not boot until something starts reading
its debug messages. So it basically waits to tether to a serial terminal so that you don't it's debug messages. So it basically it waits to tether to a serial terminal so that you don't
miss any debug messages. miss any debug messages.
We recommend using our `solo` tool as a serial emulator since it will automatically We recommend using our `solotool.py` as a serial emulator since it will automatically
reconnect each time you program Solo. reconnect each time you program Solo.
``` ```
solo monitor <serial-port> python tools/solotool.py monitor <serial-port>
``` ```
#### Linux Users: #### Linux Users:
@ -80,8 +68,6 @@ solo monitor <serial-port>
### Building a Solo release ### Building a Solo release
To build Solo
If you want to build a release of Solo, we recommend trying a Hacker build first If you want to build a release of Solo, we recommend trying a Hacker build first
just to make sure that it's working. Otherwise it may not be as easy or possible to just to make sure that it's working. Otherwise it may not be as easy or possible to
fix any mistakes. fix any mistakes.
@ -92,13 +78,102 @@ If you're ready to program a full release, run this recipe to build.
make build-release-locked make build-release-locked
``` ```
This outputs bootloader.hex, solo.hex, and the combined all.hex. Programming `all.hex` will cause the device to permanently lock itself.
Programming `all.hex` will cause the device to permanently lock itself. This means debuggers cannot be used and signature checking
will be enforced on all future updates.
Note if you program a secured `solo.hex` file onto a Solo Hacker, it will lock the flash, but the bootloader # Programming
will still accept unsigned firmware updates. So you can switch it back to being a hacker, but you will
not be able to replace the unlocked bootloader anymore, since the permanently locked flash also disables the DFU.
[Read more on Solo's boot stages](/solo/bootloader-mode).
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
install the prerequisites:
```
pip3 install -r tools/requirements.txt
```
If you're on Windows, you must also install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/).
## Pre-programmed Solo Hacker
If your Solo device is already programmed (it flashes green when powered), we recommend
programming it using the Solo bootloader.
```
python tools/solotool.py program solo.hex
```
Make sure to program `solo.hex` and not `all.hex`. Nothing bad would happen, but you'd
see errors.
If something bad happens, you can always boot the Solo bootloader by doing the following.
1. Unplug device.
2. Hold down button.
3. Plug in device while holding down button.
4. Wait about 2 seconds for flashing yellow light. Release button.
If you hold the button for an additional 5 seconds, it will boot to the ST DFU (device firmware update).
Don't use the ST DFU unless you know what you're doing.
## ST USB DFU
If your Solo has never been programmed, it will boot the ST USB DFU. The LED is turned
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
```
Make sure to program `all.hex`, as this contains both the bootloader and the Solo application.
If all goes well, you should see a slow-flashing green light.
## Solo Hacker vs Solo
A Solo hacker device doesn't need to be in bootloader mode to be programmed, it will automatically switch.
Solo (locked) needs the button to be held down when plugged in to boot to the bootloader.
A locked Solo will only accept signed updates.
## 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
```
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
```
If your Solo isn't locked, you can always reprogram it using a debugger connected directly
to the token.
# Permanently locking the device
If you plan to be using your Solo for real, you should lock it permanently. This prevents
someone from connecting a debugger to your token and stealing credentials.
To do this, build the locked release firmware.
```
make build-release-locked
```
Now when you program `all.hex`, the device will lock itself when it first boots. You can only update it
with signed updates.
If you'd like to also permanently disable signed updates, plug in your programmed Solo and run the following:
```
# WARNING: No more signed updates.
python tools/programmer.py --disable
```

View File

@ -5,22 +5,22 @@ and easy to understand, especially when paired with a high level overview.
## FIDO2 codebase ## FIDO2 codebase
* `main.c` - calls high level functions and implements event loop. * main.c - calls high level functions and implements event loop.
* `ctaphid.c` - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO. * ctaphid.c - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO.
* `u2f.c` - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html). * u2f.c - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html).
* `ctap.c` - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html). * ctap.c - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html).
* `ctap_parse.c` - implements parsing for CTAP protocol. * ctap_parse.c - implements parsing for CTAP protocol.
* this could use some work minimizing. * this could use some work minimizing.
* `log.c` - embedded friendly debug logging. * log.c - embedded friendly debug logging.
* `crypto.c` - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in `crypto.h` should be the same. * crypto.c - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in crypto.h should be the same.
* `device.h` - definitions of functions that are platform specific and should be implemented separately. See `device.c` in any of the implementations to see examples. * device.h - definitions of functions that are platform specific and should be implemented separately. See device.c in any of the implementations to see examples.
## Data flow ## Data flow

View File

@ -1,141 +0,0 @@
# Customization
If you are interested in customizing parts of your Solo, and you have a Solo Hacker, this page is for you.
## Custom Attestation key
The attestation key is used in the FIDO2 *makeCredential* or U2F *register* requests. It signs
newly generated credentials. The certificate associated with the attestation key is output with newly created credentials.
Platforms or services can use the attestation feature to enforce specific authenticators to be used.
This is typically a use case for organizations and isn't seen in the wild for consumer use cases.
Attestation keys are typically the same for at least 100K units of a particular authenticator model.
This is so they don't contribute a significant fingerprint that platforms could use to identify the user.
If you don't want to use the default attestation key that Solo builds with, you can create your own
and program it.
### Creating your attestation key pair
Since we are generating keys, it's important to use a good entropy source.
You can use the [True RNG on your Solo](/solo/solo-extras) to generate some good random numbers.
```
# Run for 1 second, then hit control-c
solo key rng raw > seed.bin
```
First we will create a self signed key pair that acts as the root of trust. This
won't go on the authenticator, but will sign the keypair that does.
Please change the root certification information as needed. You may change the ECC curve.
```
curve=prime256v1
country=US
state=Maine
organization=OpenSourceSecurity
unit="Root CA"
CN=example.com
email=example@example.com
# generate EC private key
openssl ecparam -genkey -name "$curve" -out root_key.pem -rand seed.bin
# generate a "signing request"
openssl req -new -key root_key.pem -out root_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=example.com/emailAddress=$email"
# self sign the request
openssl x509 -trustout -req -days 18250 -in root_key.pem.csr -signkey root_key.pem -out root_cert.pem -sha256
# convert to smaller size format DER
openssl x509 -in root_cert.pem -outform der -out root_cert.der
# print out information and verify
openssl x509 -in root_cert.pem -text -noout
```
You need to create a extended certificate for the device certificate to work with FIDO2. You need to create this
file, `v3.ext`, and add these options to it.
```
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
```
Now to generate & sign the attestation key pair that will go on your device, or maybe 100,000 devices :).
Note you must use a prime256v1 curve for this step, and you must leave the unit/OU as "Authenticator Attestation".
```
country=US
state=Maine
organization=OpenSourceSecurity
unit="Authenticator Attestation"
CN=example.com
email=example@example.com
# generate EC private key
openssl ecparam -genkey -name "$curve" -out device_key.pem -rand seed.bin
# generate a "signing request"
openssl req -new -key device_key.pem -out device_key.pem.csr -subj "/C=$country/ST=$state/O=$organization/OU=$unit/CN=example.com/emailAddress=$email"
# sign the request
openssl x509 -req -days 18250 -in device_key.pem.csr -extfile v3.ext -CA root_cert.pem -CAkey root_key.pem -set_serial 01 -out device_cert.pem -sha256
# convert to smaller size format DER
openssl x509 -in device_cert.pem -outform der -out device_cert.der
# Verify the device certificate details
openssl x509 -in device_cert.pem -text -noout
```
Let's verify that the attestation key and certificate are valid, and that they can be verified with the root key pair.
```
echo 'challenge $RANDOM' > chal.txt
# check that they are valid key pairs
openssl dgst -sha256 -sign device_key.pem -out sig.txt chal.txt
openssl dgst -sha256 -verify <(openssl x509 -in device_cert.pem -pubkey -noout) -signature sig.txt chal.txt
openssl dgst -sha256 -sign "root_key.pem" -out sig.txt chal.txt
openssl dgst -sha256 -verify <(openssl x509 -in root_cert.pem -pubkey -noout) -signature sig.txt chal.txt
# Check they are a chain
openssl verify -verbose -CAfile "root_cert.pem" "device_cert.pem"
```
If the checks succeed, you are ready to program the device attestation key and certificate.
### Programming an attestation key and certificate
Convert the DER format of the device attestation certificate to "C" bytes using our utility script. You may first need to
first install prerequisite python modules (pip install -r tools/requirements.txt).
```
python tools/gencert/cbytes.py device_cert.der
```
Copy the byte string portion into the [`attestation.c` source file of Solo](https://github.com/solokeys/solo/blob/master/targets/stm32l432/src/attestation.c). Overwrite the development or "default" certificate that is already there.
Now [build the Solo firmware](/solo/building), either a secure or hacker build. You will need to produce a bootloader.hex file and a solo.hex file.
Print your attestation key in a hex string format.
```
python tools/print_x_y.py device_key.pem
```
Merge the bootloader.hex, solo.hex, and attestion key into one firmware file.
```
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex
```
Now you have a newly create `all.hex` file with a custom attestation key. You can [program this all.hex file
with Solo in DFU mode](/solo/programming#procedure).

View File

@ -3,7 +3,7 @@ Documentation of the `master` branch is deployed to Netlify automatically.
To host or develop locally: To host or develop locally:
``` ```
pip install mkdocs mkdocs-material markdown-include pip install mkdocs mkdocs-material
``` ```
`mkdocs serve` and visit [localhost:8000](http://localhost:8000). `mkdocs serve` and visit [localhost:8000](http://localhost:8000).

View File

@ -22,8 +22,8 @@ for FIDO2 operation.
When you register a service with a FIDO2 or U2F authenticator, the When you register a service with a FIDO2 or U2F authenticator, the
authenticator must generate a new keypair unique to that service. This keypair authenticator must generate a new keypair unique to that service. This keypair
could be stored on the authenticator to be used in subsequent authentications, could be stored on the authenticator to be used in subsequent authentications,
but a certain amount of memory would need to be allocated for this. On embedded but now a certain amount of memory needs to be allocated for this. On embedded
devices, there isn't much memory to spare and users would frustratingly devices, there isn't much memory to spare and users will allows frustratingly
hit the limit of this memory. hit the limit of this memory.
The answer to this problem is to do key wrapping. The authenticator just The answer to this problem is to do key wrapping. The authenticator just
@ -39,7 +39,7 @@ In essence, the following happens at registration.
3. Return `P` and `R` to service. (`R` is in `KEYID` parameter) 3. Return `P` and `R` to service. (`R` is in `KEYID` parameter)
4. Service stores `P` and `R`. 4. Service stores `P` and `R`.
Now on authentication. Now on authenication.
1. Service issues authentication request with `R` in `KEYID` parameter. 1. Service issues authentication request with `R` in `KEYID` parameter.
2. \* Authenticator generates `K` by calculating `HMAC(M,R)`. 2. \* Authenticator generates `K` by calculating `HMAC(M,R)`.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

View File

@ -1,4 +1,4 @@
Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo). Welcome to the technical documentation for [solokeys/solo](https://github.com/solokeys/solo).
Use the table of contents on the left to browse this documentation. For now, you can read the repository `README.md`, more documentation to come!

View File

@ -1,258 +0,0 @@
# Nucleo32 board preparation
Additional steps are required to run the firmware on the Nucleo32 board.
## USB-A cable
Board does not provide an USB cable / socket for the target MCU communication.
Own provided USB plug has to be connected in the following way:
| PIN / Arduino PIN | MCU leg | USB wire color | Signal |
| ----------------- | ------- | -------------- | ------ |
| D10 / PA11 | 21 | white | D- |
| D2 / PA12 | 22 | green | D+ |
| GND (near D2) | ------- | black | GND |
| **not connected** | ------- | red | 5V |
Each USB plug pin should be connected via the wire in a color defined by the standard. It might be confirmed with a
multimeter for additional safety. USB plug description:
| PIN | USB wire color | Signal |
| --- | -------------- | ------ |
| 4 | black | GND |
| 3 | green | D+ |
| 2 | white | D- |
| 1 | red | 5V |
See this [USB plug] image, and Wikipedia's [USB plug description].
Plug in [USB-A_schematic.pdf] has wrong wire order, registered as [solo-hw#1].
The power is taken from the debugger / board (unless the board is configured in another way).
Make sure 5V is not connected, and is covered from contacting with the board elements.
Based on [USB-A_schematic.pdf].
## Firmware modification
Following patch has to be applied to skip the user presence confirmation, for tests. Might be applied at a later stage.
```text
diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h
index c14a7ed..c89c3b5 100644
--- a/targets/stm32l432/src/app.h
+++ b/targets/stm32l432/src/app.h
@@ -71,6 +71,6 @@ void hw_init(void);
#define SOLO_BUTTON_PIN LL_GPIO_PIN_0
#define SKIP_BUTTON_CHECK_WITH_DELAY 0
-#define SKIP_BUTTON_CHECK_FAST 0
+#define SKIP_BUTTON_CHECK_FAST 1
#endif
```
It is possible to provide a button and connect it to the MCU pins, as instructed in [USB-A_schematic.pdf]&#x3A;
```text
PA0 / pin 6 --> button --> GND
```
In that case the mentioned patch would not be required.
## Development environment setup
Environment: Fedora 29 x64, Linux 4.19.9
See <https://docs.solokeys.io/solo/building/> for the original guide. Here details not included there will be covered.
### Install ARM tools Linux
1. Download current [ARM tools] package: [gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2].
2. Extract the archive.
3. Add full path to the `./bin` directory as first entry to the `$PATH` variable,
as in `~/gcc-arm/gcc-arm-none-eabi-8-2018-q4-major/bin/:$PATH`.
### Install ARM tools OsX using brew package manager
```bash
brew tap ArmMbed/homebrew-formulae
brew install arm-none-eabi-gcc
```
### Install flashing software
ST provides a CLI flashing tool - `STM32_Programmer_CLI`. It can be downloaded directly from the vendor's site:
1\. Go to [download site URL](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html),
go to bottom page and from STM32CubeProg row select Download button.
2\. Unzip contents of the archive.
3\. Run \*Linux setup
4\. In installation directory go to ./bin - there the ./STM32_Programmer_CLI is located
5\. Add symlink to the STM32 CLI binary to .local/bin. Make sure the latter it is in $PATH.
If you're on OsX and installed the STM32CubeProg, you need to add the following to your path:
```bash
# ~/.bash_profile
export PATH="/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/bin/":$PATH
```
## Building and flashing
### Building
Please follow <https://docs.solokeys.io/solo/building/>, as the build way changes rapidly.
Currently (8.1.19) to build the firmware, following lines should be executed
```bash
# while in the main project directory
cd targets/stm32l432
make cbor
make build-hacker DEBUG=1
```
Note: `DEBUG=2` stops the device initialization, until a serial client will be attached to its virtual port.
Do not use it, if you do not plan to do so.
### Flashing via the Makefile command
```bash
# while in the main project directory
# create Python virtual environment with required packages, and activate
make venv
. venv/bin/activate
# Run flashing
cd ./targets/stm32l432
make flash
# which runs:
# flash: solo.hex bootloader.hex
# python merge_hex.py solo.hex bootloader.hex all.hex (intelhex library required)
# STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
# STM32_Programmer_CLI -c port=SWD -halt -d all.hex -rst
```
### Manual flashing
In case you already have a firmware to flash (named `all.hex`), please run the following:
```bash
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d all.hex -rst
```
## Testing
### Internal
Project-provided tests.
#### Simulated device
A simulated device is provided to test the HID layer.
##### Build
```bash
make clean
cd tinycbor
make
cd ..
make env2
```
##### Execution
```bash
# run simulated device (will create a network UDP server)
./main
# run test 1
./env2/bin/python tools/ctap_test.py
# run test 2 (or other files in the examples directory)
./env2/bin/python python-fido2/examples/credential.py
```
#### Real device
```bash
# while in the main project directory
# not passing as of 8.1.19, due to test solution issues
make fido2-test
```
### External
#### FIDO2 test sites
1. <https://www.passwordless.dev/overview>
2. <https://webauthn.bin.coffee/>
3. <https://webauthn.org/>
#### U2F test sites
1. <https://u2f.bin.coffee/>
2. <https://demo.yubico.com/u2f>
#### FIDO2 standalone clients
1. <https://github.com/Nitrokey/u2f-ref-code>
2. <https://github.com/Yubico/libfido2>
3. <https://github.com/Yubico/python-fido2>
4. <https://github.com/google/pyu2f>
## USB serial console reading
Device opens an USB-emulated serial port to output its messages. While Nucleo board offers such already,
the Solo device provides its own.
- Provided Python tool
```bash
python3 ../../tools/solotool.py monitor /dev/solokey-serial
```
- External application
```bash
sudo picocom -b 115200 /dev/solokey-serial
```
where `/dev/solokey-serial` is an udev symlink to `/dev/ttyACM1`.
## Other
### Dumping firmware
Size is calculated using bash arithmetic.
```bash
STM32_Programmer_CLI -c port=SWD -halt -u 0x0 $((256*1024)) current.hex
```
### Software reset
```bash
STM32_Programmer_CLI -c port=SWD -rst
```
### Installing required Python packages
Client script requires some Python packages, which could be easily installed locally to the project
via the Makefile command. It is sufficient to run:
```bash
make env3
```
[solo-hw#1]: https://github.com/solokeys/solo-hw/issues/1
[usb plug]: https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/USB.svg/1200px-USB.svg.png
[usb plug description]: https://en.wikipedia.org/wiki/USB#Receptacle_(socket)_identification
[usb-a_schematic.pdf]: https://github.com/solokeys/solo-hw/releases/download/1.2/USB-A_schematic.pdf
[arm tools]: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
[gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2]: https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2?revision=d830f9dd-cd4f-406d-8672-cca9210dd220?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,8-2018-q4-major

View File

@ -1,113 +0,0 @@
# Programming
This page documents how to update or program your Solo.
## Prerequisites
To program Solo, you'll likely only need to use our Solo tool.
```python
pip3 install solo-python
```
## Updating the firmware
If you just want to update the firmware, you can run one of the following commands.
Make sure your key [is in bootloader mode](/solo/bootloader-mode#solo-bootloader) first.
```bash
solo key update <--secure | --hacker>
```
You can manually install the [latest release](https://github.com/solokeys/solo/releases), or use a build that you made.
```bash
# If it's a hacker, it will automatically boot into bootloader mode.
solo program bootloader <firmware.hex | firmware.json>
```
Note you won't be able to use `all.hex` or the `bundle-*.hex` builds, as these include the solo bootloader. You shouldn't
risk changing the Solo bootloader unless you want to make it a secure device, or [make other customizations]().
## Updating a Hacker to a Secure Solo
Updating a hacker to be a secure build overwrites the [Solo bootloader](/solo/bootloader-mode#solo-bootloader).
So it's important to not mess this up or you may brick your device.
You can use a firmware build from the [latest release](https://github.com/solokeys/solo/releases) or use
a build that you made yourself.
You need to use a firmware file that has the combined bootloader and application (or at the very least just the bootloader).
This means using the `bundle-*.hex` file or the `all.hex` from your build. If you overwrite the Solo flash with a missing bootloader,
it will be bricked.
We provide two types of bundled builds. The `bundle-hacker-*.hex` build is the hacker build. If you update with this,
you will update the bootloader and application, but nothing will be secured. The `bundle-secure-non-solokeys.hex`
is a secured build that will lock your device and it will behave just like a Secure Solo. The main difference is that
it uses a "default" attestation key in the device, rather than the SoloKeys attestation key. There is no security
concern with using our default attestation key, aside from a privacy implication that services can distinguish it from Solo Secure.
### Procedure
1. Boot into DFU mode.
# Enter Solo bootloader
solo program aux enter-bootloader
# Enter DFU
solo program aux enter-dfu
The device should be turned off.
2. Program the device
solo program dfu <bundle-secure-non-solokeys.hex | all.hex>
Double check you programmed it with bootloader + application (or just bootloader).
If you messed it up, simply don't do the next step and repeat this step correctly.
3. Boot the device
Once Solo boots a secure build, it will lock the flash permantly from debugger access. Also the bootloader
will only accept signed firmware updates.
solo program aux leave-dfu
If you are having problems with solo tool and DFU mode, you could alternatively try booting into DFU
by holding down the button while Solo is in bootloader mode. Then try another programming tool that works
with ST DFU:
* STM32CubeProg
* openocd
* stlink
Windows users need to install [libusb](https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/)
for solo-python to work with Solo's DFU.
## Programming a Solo that hasn't been programmed
A Solo that hasn't been programmed will boot into DFU mode. You can program
it by following a bootloader, or combined bootloader + application.
```
solo program dfu <bundle-*.hex | all.hex>
```
Then boot the device. Make sure it has a bootloader to boot to.
```
solo program aux leave-dfu
```
## Disable signed firmware updates
If you'd like to also permanently disable signed updates, plug in your programmed Solo and run the following:
```bash
# WARNING: No more signed updates.
solo program disable-bootloader
```
You won't be able to update to any new releases.

View File

@ -1,19 +0,0 @@
# Solo Extras
## Random number generation
Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism
that leverages natural phenomenon to generate random numbers, which is can be better than a traditional
RNG that has state and updates deterministically using cryptographic methods.
You can easily access the TRNG stream on Solo using our python tool [solo-python](https://github.com/solokeys/solo-python).
```
solo key rng raw > random.bin
```
Or you can seed the state of the RNG on your kernel (/dev/random).
```
solo key rng feedkernel
```

View File

@ -1,30 +1,17 @@
# Summary # tl;dr
On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed. 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`):
For some users, things will work automatically:
- Fedora seems to use a ["universal" udev rule for FIDO devices](https://github.com/amluto/u2f-hidraw-policy)
- Our udev rule made it into [libu2f-host](https://github.com/Yubico/libu2f-host/) v1.1.10
- Arch Linux [has this package](https://www.archlinux.org/packages/community/x86_64/libu2f-host/)
- [Debian sid](https://packages.debian.org/sid/libu2f-udev) and [Ubuntu Eon](https://packages.ubuntu.com/eoan/libu2f-udev) can use the `libu2f-udev` package
- Debian Buster and Ubuntu Disco still distribute v1.1.10, so need the manual rule
- FreeBSD has support in [u2f-devd](https://github.com/solokeys/solo/issues/144#issuecomment-500216020)
There is hope that `udev` itself will adopt the Fedora approach (which is to check for HID usage page `F1D0`, and avoids manually whitelisting each U2F/FIDO2 key): <https://github.com/systemd/systemd/issues/11996>.
Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>.
If you still need to setup a rule, a simple way to do it is:
``` ```
git clone git@github.com:solokeys/solo.git # Solo
cd solo/udev KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="solokey"
make setup
# U2F Zero
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"
``` ```
Or, manually, create a file like [`70-solokeys-access.rules`](https://github.com/solokeys/solo/blob/master/udev/70-solokeys-access.rules) in your `/etc/udev/rules.d` directory. Then run
Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
``` ```
sudo udevadm control --reload-rules && sudo udevadm trigger sudo udevadm control --reload-rules && sudo udevadm trigger
``` ```
@ -63,7 +50,7 @@ This contains rules for Yubico's keys, the U2F Zero, and many others. The releva
``` ```
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess" KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
``` ```
It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as It matches on the correct vendor/product IDs of 10c4/8acf, and adds the TAG `uaccess`. Older versions of udev use rules such as
``` ```
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", MODE="0644", GROUP="plugdev" KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", MODE="0644", GROUP="plugdev"
``` ```

View File

@ -1,122 +0,0 @@
// Copyright 2019 SoloKeys Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
// iso7816:2013. 5.3.2 Decoding conventions for command bodies
#include "apdu.h"
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
{
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any
apdu->ins = hapdu->ins;
apdu->p1 = hapdu->p1;
apdu->p2 = hapdu->p2;
apdu->lc = 0;
apdu->data = NULL;
apdu->le = 0;
apdu->extended_apdu = false;
apdu->case_type = 0x00;
uint8_t b0 = hapdu->lc[0];
// case 1
if (len == 4)
{
apdu->case_type = 0x01;
}
// case 2S (Le)
if (len == 5)
{
apdu->case_type = 0x02;
apdu->le = b0;
if (!apdu->le)
apdu->le = 0x100;
}
// case 3S (Lc + data)
if (len == 5U + b0 && b0 != 0)
{
apdu->case_type = 0x03;
apdu->lc = b0;
}
// case 4S (Lc + data + Le)
if (len == 5U + b0 + 1U && b0 != 0)
{
apdu->case_type = 0x04;
apdu->lc = b0;
apdu->le = data[len - 1];
if (!apdu->le)
apdu->le = 0x100;
}
// extended length apdu
if (len >= 7 && b0 == 0)
{
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
// case 2E (Le) - extended
if (len == 7)
{
apdu->case_type = 0x12;
apdu->extended_apdu = true;
apdu->le = extlen;
if (!apdu->le)
apdu->le = 0x10000;
}
// case 3E (Lc + data) - extended
if (len == 7U + extlen)
{
apdu->case_type = 0x13;
apdu->extended_apdu = true;
apdu->lc = extlen;
}
// case 4E (Lc + data + Le) - extended 2-byte Le
if (len == 7U + extlen + 2U)
{
apdu->case_type = 0x14;
apdu->extended_apdu = true;
apdu->lc = extlen;
apdu->le = (data[len - 2] << 8) + data[len - 1];
if (!apdu->le)
apdu->le = 0x10000;
}
// case 4E (Lc + data + Le) - extended 3-byte Le
if (len == 7U + extlen + 3U && data[len - 3] == 0)
{
apdu->case_type = 0x24;
apdu->extended_apdu = true;
apdu->lc = extlen;
apdu->le = (data[len - 2] << 8) + data[len - 1];
if (!apdu->le)
apdu->le = 0x10000;
}
}
if (!apdu->case_type)
return 1;
if (apdu->lc)
{
if (apdu->extended_apdu)
{
apdu->data = data + 7;
} else {
apdu->data = data + 5;
}
}
return 0;
}

View File

@ -1,63 +0,0 @@
#ifndef _APDU_H_
#define _APDU_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint8_t lc;
} __attribute__((packed)) APDU_HEADER;
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint8_t lc[3];
} __attribute__((packed)) EXT_APDU_HEADER;
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint16_t lc;
uint8_t *data;
uint32_t le;
bool extended_apdu;
uint8_t case_type;
} __attribute__((packed)) APDU_STRUCT;
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
#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_FIDO_U2F_VENDOR_FIRST 0xc0 // First vendor defined command
#define APDU_FIDO_U2F_VENDOR_LAST 0xff // Last vendor defined command
#define APDU_SOLO_RESET 0xee
#define APDU_INS_SELECT 0xA4
#define APDU_INS_READ_BINARY 0xB0
#define APDU_GET_RESPONSE 0xC0
#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_INCORRECT_P1P2 0x6a86
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
#define SW_CLA_INVALID 0x6e00
#define SW_INTERNAL_EXCEPTION 0x6f00
#endif //_APDU_H_

View File

@ -16,7 +16,7 @@
#define COSE_KEY_KTY_EC2 2 #define COSE_KEY_KTY_EC2 2
#define COSE_KEY_CRV_P256 1 #define COSE_KEY_CRV_P256 1
#define COSE_ALG_ES256 -7
#define COSE_ALG_ECDH_ES_HKDF_256 -25 #define COSE_ALG_ES256 -7
#endif #endif

View File

@ -60,7 +60,7 @@ static const uint8_t * _signing_key = NULL;
static int _key_len = 0; static int _key_len = 0;
// Secrets for testing only // Secrets for testing only
static uint8_t master_secret[64]; static uint8_t master_secret[32];
static uint8_t transport_secret[32]; static uint8_t transport_secret[32];
@ -73,17 +73,13 @@ void crypto_sha256_init()
void crypto_reset_master_secret() void crypto_reset_master_secret()
{ {
ctap_generate_rng(master_secret, 64); ctap_generate_rng(master_secret, 32);
ctap_generate_rng(transport_secret, 32);
} }
void crypto_load_master_secret(uint8_t * key) void crypto_load_master_secret(uint8_t * key)
{ {
#if KEY_SPACE_BYTES < 96 memmove(master_secret, key, 32);
#error "need more key bytes" memmove(transport_secret, key+32, 32);
#endif
memmove(master_secret, key, 64);
memmove(transport_secret, key+64, 32);
} }
void crypto_sha256_update(uint8_t * data, size_t len) void crypto_sha256_update(uint8_t * data, size_t len)
@ -112,12 +108,7 @@ void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
key = master_secret; key = master_secret;
klen = sizeof(master_secret); klen = sizeof(master_secret);
} }
else if (key == CRYPTO_TRANSPORT_KEY)
{
key = transport_secret;
klen = 32;
}
if(klen > 64) if(klen > 64)
{ {
printf2(TAG_ERR,"Error, key size must be <= 64\n"); printf2(TAG_ERR,"Error, key size must be <= 64\n");
@ -262,11 +253,6 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(y,pubkey+32,32); memmove(y,pubkey+32,32);
} }
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
uECC_compute_public_key(privkey, pubkey, _es256_curve);
}
void crypto_load_external_key(uint8_t * key, int len) void crypto_load_external_key(uint8_t * key, int len)
{ {
_signing_key = key; _signing_key = key;

View File

@ -19,14 +19,9 @@ 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_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_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_init();
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y); void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y);
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey);
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2); void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2);
void crypto_ecc256_load_attestation_key(); void crypto_ecc256_load_attestation_key();
@ -39,7 +34,6 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey); void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret); void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
#define CRYPTO_TRANSPORT_KEY2 ((uint8_t*)2)
#define CRYPTO_TRANSPORT_KEY ((uint8_t*)1) #define CRYPTO_TRANSPORT_KEY ((uint8_t*)1)
#define CRYPTO_MASTER_KEY ((uint8_t*)0) #define CRYPTO_MASTER_KEY ((uint8_t*)0)

File diff suppressed because it is too large Load Diff

View File

@ -54,13 +54,6 @@
#define CP_getKeyAgreement 0x07 #define CP_getKeyAgreement 0x07
#define CP_getRetries 0x08 #define CP_getRetries 0x08
#define EXT_HMAC_SECRET_COSE_KEY 0x01
#define EXT_HMAC_SECRET_SALT_ENC 0x02
#define EXT_HMAC_SECRET_SALT_AUTH 0x03
#define EXT_HMAC_SECRET_REQUESTED 0x01
#define EXT_HMAC_SECRET_PARSED 0x02
#define RESP_versions 0x1 #define RESP_versions 0x1
#define RESP_extensions 0x2 #define RESP_extensions 0x2
#define RESP_aaguid 0x3 #define RESP_aaguid 0x3
@ -112,8 +105,6 @@
#define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes #define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes
#define PUB_KEY_CRED_PUB_KEY 0x01 #define PUB_KEY_CRED_PUB_KEY 0x01
#define PUB_KEY_CRED_CTAP1 0x41
#define PUB_KEY_CRED_CUSTOM 0x42
#define PUB_KEY_CRED_UNKNOWN 0x3F #define PUB_KEY_CRED_UNKNOWN 0x3F
#define CREDENTIAL_IS_SUPPORTED 1 #define CREDENTIAL_IS_SUPPORTED 1
@ -131,8 +122,6 @@
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total #define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot #define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
#define CTAP2_UP_DELAY_MS 29000
typedef struct typedef struct
{ {
uint8_t id[USER_ID_MAX_SIZE]; uint8_t id[USER_ID_MAX_SIZE];
@ -153,13 +142,9 @@ struct Credential {
CredentialId id; CredentialId id;
CTAP_userEntity user; CTAP_userEntity user;
}; };
typedef struct Credential CTAP_residentKey; typedef struct Credential CTAP_residentKey;
typedef struct
{
uint8_t type;
struct Credential credential;
} CTAP_credentialDescriptor;
typedef struct typedef struct
{ {
@ -196,67 +181,34 @@ struct rpId
uint8_t name[RP_NAME_LIMIT]; uint8_t name[RP_NAME_LIMIT];
}; };
typedef struct
{
struct{
uint8_t x[32];
uint8_t y[32];
} pubkey;
int kty;
int crv;
} COSE_key;
typedef struct
{
uint8_t saltLen;
uint8_t saltEnc[64];
uint8_t saltAuth[32];
COSE_key keyAgreement;
struct Credential * credential;
} CTAP_hmac_secret;
typedef struct
{
uint8_t hmac_secret_present;
CTAP_hmac_secret hmac_secret;
} CTAP_extensions;
typedef struct
{
CTAP_userEntity user;
uint8_t publicKeyCredentialType;
int32_t COSEAlgorithmIdentifier;
uint8_t rk;
} CTAP_credInfo;
typedef struct typedef struct
{ {
uint32_t paramsParsed; uint32_t paramsParsed;
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE]; uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
struct rpId rp; struct rpId rp;
CTAP_userEntity user;
CTAP_credInfo credInfo; uint8_t publicKeyCredentialType;
int32_t COSEAlgorithmIdentifier;
CborValue excludeList; CborValue excludeList;
size_t excludeListSize; size_t excludeListSize;
uint8_t rk;
uint8_t uv; uint8_t uv;
uint8_t up; uint8_t up;
uint8_t pinAuth[16]; uint8_t pinAuth[16];
uint8_t pinAuthPresent; uint8_t pinAuthPresent;
// pinAuthEmpty is true iff an empty bytestring was provided as pinAuth.
// This is exclusive with |pinAuthPresent|. It exists because an empty
// pinAuth is a special signal to block for touch. See
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorMakeCredential
uint8_t pinAuthEmpty;
int pinProtocol; int pinProtocol;
CTAP_extensions extensions;
} CTAP_makeCredential; } CTAP_makeCredential;
typedef struct
{
uint8_t type;
struct Credential credential;
} CTAP_credentialDescriptor;
typedef struct typedef struct
{ {
@ -274,25 +226,26 @@ typedef struct
uint8_t pinAuth[16]; uint8_t pinAuth[16];
uint8_t pinAuthPresent; uint8_t pinAuthPresent;
// pinAuthEmpty is true iff an empty bytestring was provided as pinAuth.
// This is exclusive with |pinAuthPresent|. It exists because an empty
// pinAuth is a special signal to block for touch. See
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorGetAssertion
uint8_t pinAuthEmpty;
int pinProtocol; int pinProtocol;
CTAP_credentialDescriptor * creds; CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
uint8_t allowListPresent; uint8_t allowListPresent;
CTAP_extensions extensions;
} CTAP_getAssertion; } CTAP_getAssertion;
typedef struct typedef struct
{ {
int pinProtocol; int pinProtocol;
int subCommand; int subCommand;
COSE_key keyAgreement; struct
{
struct{
uint8_t x[32];
uint8_t y[32];
} pubkey;
int kty;
int crv;
} keyAgreement;
uint8_t keyAgreementPresent; uint8_t keyAgreementPresent;
uint8_t pinAuth[16]; uint8_t pinAuth[16];
uint8_t pinAuthPresent; uint8_t pinAuthPresent;
@ -305,19 +258,6 @@ typedef struct
} CTAP_clientPin; } CTAP_clientPin;
struct _getAssertionState {
CTAP_authDataHeader authData;
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
uint8_t lastcmd;
uint32_t count;
uint32_t index;
uint32_t time;
uint8_t user_verified;
uint8_t customCredId[256];
uint8_t customCredIdSize;
};
void ctap_response_init(CTAP_RESPONSE * resp); void ctap_response_init(CTAP_RESPONSE * resp);
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp); uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);

View File

@ -49,7 +49,6 @@
#define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37 #define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37
#define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38 #define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38
#define CTAP2_ERR_REQUEST_TOO_LARGE 0x39 #define CTAP2_ERR_REQUEST_TOO_LARGE 0x39
#define CTAP2_ERR_ACTION_TIMEOUT 0x3A
#define CTAP1_ERR_OTHER 0x7F #define CTAP1_ERR_OTHER 0x7F
#define CTAP2_ERR_SPEC_LAST 0xDF #define CTAP2_ERR_SPEC_LAST 0xDF
#define CTAP2_ERR_EXTENSION_FIRST 0xE0 #define CTAP2_ERR_EXTENSION_FIRST 0xE0

View File

@ -9,14 +9,12 @@
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#include "u2f.h"
#include "ctap_parse.h" #include "ctap_parse.h"
#include "ctap_errors.h" #include "ctap_errors.h"
#include "cose_key.h" #include "cose_key.h"
#include "util.h" #include "util.h"
#include "log.h" #include "log.h"
extern struct _getAssertionState getAssertionState;
void _check_ret(CborError ret, int line, const char * filename) void _check_ret(CborError ret, int line, const char * filename)
{ {
@ -130,13 +128,14 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
} }
sz = USER_ID_MAX_SIZE; sz = USER_ID_MAX_SIZE;
ret = cbor_value_copy_byte_string(&map, MC->credInfo.user.id, &sz, NULL); ret = cbor_value_copy_byte_string(&map, MC->user.id, &sz, NULL);
if (ret == CborErrorOutOfMemory) if (ret == CborErrorOutOfMemory)
{ {
printf2(TAG_ERR,"Error, USER_ID is too large\n"); printf2(TAG_ERR,"Error, USER_ID is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED; return CTAP2_ERR_LIMIT_EXCEEDED;
} }
MC->credInfo.user.id_size = sz; MC->user.id_size = sz;
printf1(TAG_GREEN,"parsed id_size: %d\r\n", MC->user.id_size);
check_ret(ret); check_ret(ret);
} }
else if (strcmp((const char *)key, "name") == 0) else if (strcmp((const char *)key, "name") == 0)
@ -147,12 +146,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
sz = USER_NAME_LIMIT; sz = USER_NAME_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->credInfo.user.name, &sz, NULL); ret = cbor_value_copy_text_string(&map, (char *)MC->user.name, &sz, NULL);
if (ret != CborErrorOutOfMemory) if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay { // Just truncate the name it's okay
check_ret(ret); check_ret(ret);
} }
MC->credInfo.user.name[USER_NAME_LIMIT - 1] = 0; MC->user.name[USER_NAME_LIMIT - 1] = 0;
} }
else if (strcmp((const char *)key, "displayName") == 0) else if (strcmp((const char *)key, "displayName") == 0)
{ {
@ -162,12 +161,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
sz = DISPLAY_NAME_LIMIT; sz = DISPLAY_NAME_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->credInfo.user.displayName, &sz, NULL); ret = cbor_value_copy_text_string(&map, (char *)MC->user.displayName, &sz, NULL);
if (ret != CborErrorOutOfMemory) if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay { // Just truncate the name it's okay
check_ret(ret); check_ret(ret);
} }
MC->credInfo.user.displayName[DISPLAY_NAME_LIMIT - 1] = 0; MC->user.displayName[DISPLAY_NAME_LIMIT - 1] = 0;
} }
else if (strcmp((const char *)key, "icon") == 0) else if (strcmp((const char *)key, "icon") == 0)
{ {
@ -177,12 +176,12 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
sz = ICON_LIMIT; sz = ICON_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->credInfo.user.icon, &sz, NULL); ret = cbor_value_copy_text_string(&map, (char *)MC->user.icon, &sz, NULL);
if (ret != CborErrorOutOfMemory) if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay { // Just truncate the name it's okay
check_ret(ret); check_ret(ret);
} }
MC->credInfo.user.icon[ICON_LIMIT - 1] = 0; MC->user.icon[ICON_LIMIT - 1] = 0;
} }
else else
@ -306,8 +305,8 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
{ {
if (pub_key_cred_param_supported(cred_type, alg_type) == CREDENTIAL_IS_SUPPORTED) if (pub_key_cred_param_supported(cred_type, alg_type) == CREDENTIAL_IS_SUPPORTED)
{ {
MC->credInfo.publicKeyCredentialType = cred_type; MC->publicKeyCredentialType = cred_type;
MC->credInfo.COSEAlgorithmIdentifier = alg_type; MC->COSEAlgorithmIdentifier = alg_type;
MC->paramsParsed |= PARAM_pubKeyCredParams; MC->paramsParsed |= PARAM_pubKeyCredParams;
return 0; return 0;
} }
@ -522,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) if (cbor_value_get_type(&map) != CborBooleanType)
{ {
printf2(TAG_ERR,"Error, expecting bool type for option map value\n"); printf2(TAG_ERR,"Error, expecting text string type for rp map value\n");
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
@ -557,154 +556,6 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
return 0; return 0;
} }
uint8_t ctap_parse_hmac_secret(CborValue * val, CTAP_hmac_secret * hs)
{
size_t map_length;
size_t salt_len;
uint8_t parsed_count = 0;
int key;
int ret;
unsigned int i;
CborValue map;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(val,&map);
check_ret(ret);
ret = cbor_value_get_map_length(val, &map_length);
check_ret(ret);
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting CborIntegerTypefor hmac-secret map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
switch(key)
{
case EXT_HMAC_SECRET_COSE_KEY:
ret = parse_cose_key(&map, &hs->keyAgreement);
check_retr(ret);
parsed_count++;
break;
case EXT_HMAC_SECRET_SALT_ENC:
salt_len = 64;
ret = cbor_value_copy_byte_string(&map, hs->saltEnc, &salt_len, NULL);
if ((salt_len != 32 && salt_len != 64) || ret == CborErrorOutOfMemory)
{
return CTAP1_ERR_INVALID_LENGTH;
}
check_ret(ret);
hs->saltLen = salt_len;
parsed_count++;
break;
case EXT_HMAC_SECRET_SALT_AUTH:
salt_len = 32;
ret = cbor_value_copy_byte_string(&map, hs->saltAuth, &salt_len, NULL);
check_ret(ret);
parsed_count++;
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
if (parsed_count != 3)
{
printf2(TAG_ERR, "ctap_parse_hmac_secret missing parameter. Got %d.\r\n", parsed_count);
return CTAP2_ERR_MISSING_PARAMETER;
}
return 0;
}
uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext)
{
CborValue map;
size_t sz, map_length;
char key[16];
int ret;
unsigned int i;
bool b;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(val, &map);
check_ret(ret);
ret = cbor_value_get_map_length(val, &map_length);
check_ret(ret);
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborTextStringType)
{
printf2(TAG_ERR,"Error, expecting text string type for options map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
sz = sizeof(key);
ret = cbor_value_copy_text_string(&map, key, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, rp map key is too large. Ignoring.\n");
cbor_value_advance(&map);
cbor_value_advance(&map);
continue;
}
check_ret(ret);
key[sizeof(key) - 1] = 0;
ret = cbor_value_advance(&map);
check_ret(ret);
if (strncmp(key, "hmac-secret",11) == 0)
{
if (cbor_value_get_type(&map) == CborBooleanType)
{
ret = cbor_value_get_boolean(&map, &b);
check_ret(ret);
if (b) ext->hmac_secret_present = EXT_HMAC_SECRET_REQUESTED;
printf1(TAG_CTAP, "set hmac_secret_present to %d\r\n", b);
}
else if (cbor_value_get_type(&map) == CborMapType)
{
ret = ctap_parse_hmac_secret(&map, &ext->hmac_secret);
check_retr(ret);
ext->hmac_secret_present = EXT_HMAC_SECRET_PARSED;
printf1(TAG_CTAP, "parsed hmac_secret request\r\n");
}
else
{
printf1(TAG_RED, "warning: hmac_secret request ignored for being wrong type\r\n");
}
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length) uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length)
{ {
int ret; int ret;
@ -780,8 +631,8 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
ret = parse_user(MC, &map); ret = parse_user(MC, &map);
printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->credInfo.user.id, MC->credInfo.user.id_size); printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->user.id, MC->user.id_size);
printf1(TAG_MC," name: %s\n", MC->credInfo.user.name); printf1(TAG_MC," name: %s\n", MC->user.name);
break; break;
case MC_pubKeyCredParams: case MC_pubKeyCredParams:
@ -789,8 +640,8 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
ret = parse_pub_key_cred_params(MC, &map); ret = parse_pub_key_cred_params(MC, &map);
printf1(TAG_MC," cred_type: 0x%02x\n", MC->credInfo.publicKeyCredentialType); printf1(TAG_MC," cred_type: 0x%02x\n", MC->publicKeyCredentialType);
printf1(TAG_MC," alg_type: %d\n", MC->credInfo.COSEAlgorithmIdentifier); printf1(TAG_MC," alg_type: %d\n", MC->COSEAlgorithmIdentifier);
break; break;
case MC_excludeList: case MC_excludeList:
@ -814,31 +665,21 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
{ {
return CTAP2_ERR_INVALID_CBOR_TYPE; return CTAP2_ERR_INVALID_CBOR_TYPE;
} }
ret = ctap_parse_extensions(&map, &MC->extensions);
check_retr(ret);
break; break;
case MC_options: case MC_options:
printf1(TAG_MC,"CTAP_options\n"); printf1(TAG_MC,"CTAP_options\n");
ret = parse_options(&map, &MC->credInfo.rk, &MC->uv, &MC->up); ret = parse_options(&map, &MC->rk, &MC->uv, &MC->up);
check_retr(ret); check_retr(ret);
break; break;
case MC_pinAuth: { case MC_pinAuth:
printf1(TAG_MC,"CTAP_pinAuth\n"); printf1(TAG_MC,"CTAP_pinAuth\n");
size_t pinSize;
if (cbor_value_get_type(&map) == CborByteStringType &&
cbor_value_get_string_length(&map, &pinSize) == CborNoError &&
pinSize == 0)
{
MC->pinAuthEmpty = 1;
break;
}
ret = parse_fixed_byte_string(&map, MC->pinAuth, 16); ret = parse_fixed_byte_string(&map, MC->pinAuth, 16);
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
{ {
check_retr(ret); check_retr(ret);
} }
else else
{ {
@ -846,7 +687,6 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
} }
MC->pinAuthPresent = 1; MC->pinAuthPresent = 1;
break; break;
}
case MC_pinProtocol: case MC_pinProtocol:
printf1(TAG_MC,"CTAP_pinProtocol\n"); printf1(TAG_MC,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
@ -883,8 +723,6 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
size_t buflen; size_t buflen;
char type[12]; char type[12];
CborValue val; CborValue val;
cred->type = 0;
if (cbor_value_get_type(arr) != CborMapType) if (cbor_value_get_type(arr) != CborMapType)
{ {
printf2(TAG_ERR,"Error, CborMapType expected in credential\n"); printf2(TAG_ERR,"Error, CborMapType expected in credential\n");
@ -901,22 +739,12 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
} }
buflen = sizeof(CredentialId); buflen = sizeof(CredentialId);
ret = cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL); cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
if (buflen != sizeof(CredentialId))
if (buflen == U2F_KEY_HANDLE_SIZE)
{ {
printf2(TAG_PARSE,"CTAP1 credential\n"); printf2(TAG_ERR,"Ignoring credential is incorrect length\n");
cred->type = PUB_KEY_CRED_CTAP1; //return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail?
} }
else if (buflen != sizeof(CredentialId))
{
printf2(TAG_ERR,"Ignoring credential is incorrect length, treating as custom\n");
cred->type = PUB_KEY_CRED_CUSTOM;
buflen = 256;
ret = cbor_value_copy_byte_string(&val, getAssertionState.customCredId, &buflen, NULL);
getAssertionState.customCredIdSize = buflen;
}
check_ret(ret);
ret = cbor_value_map_find_value(arr, "type", &val); ret = cbor_value_map_find_value(arr, "type", &val);
check_ret(ret); check_ret(ret);
@ -928,23 +756,11 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
} }
buflen = sizeof(type); buflen = sizeof(type);
ret = cbor_value_copy_text_string(&val, type, &buflen, NULL); cbor_value_copy_text_string(&val, type, &buflen, NULL);
if (ret == CborErrorOutOfMemory)
{
cred->type = PUB_KEY_CRED_UNKNOWN;
}
else
{
check_ret(ret);
}
if (strncmp(type, "public-key",11) == 0) if (strncmp(type, "public-key",11) == 0)
{ {
if (0 == cred->type) cred->type = PUB_KEY_CRED_PUB_KEY;
{
cred->type = PUB_KEY_CRED_PUB_KEY;
}
} }
else else
{ {
@ -1009,8 +825,6 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
CborValue it,map; CborValue it,map;
memset(GA, 0, sizeof(CTAP_getAssertion)); memset(GA, 0, sizeof(CTAP_getAssertion));
GA->creds = getAssertionState.creds; // Save stack memory
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it); ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret); check_ret(ret);
@ -1072,8 +886,6 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
break; break;
case GA_extensions: case GA_extensions:
printf1(TAG_GA,"GA_extensions\n"); printf1(TAG_GA,"GA_extensions\n");
ret = ctap_parse_extensions(&map, &GA->extensions);
check_retr(ret);
break; break;
case GA_options: case GA_options:
@ -1081,18 +893,9 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up); ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up);
check_retr(ret); check_retr(ret);
break; break;
case GA_pinAuth: { case GA_pinAuth:
printf1(TAG_GA,"CTAP_pinAuth\n"); printf1(TAG_GA,"CTAP_pinAuth\n");
size_t pinSize;
if (cbor_value_get_type(&map) == CborByteStringType &&
cbor_value_get_string_length(&map, &pinSize) == CborNoError &&
pinSize == 0)
{
GA->pinAuthEmpty = 1;
break;
}
ret = parse_fixed_byte_string(&map, GA->pinAuth, 16); ret = parse_fixed_byte_string(&map, GA->pinAuth, 16);
if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft if (CTAP1_ERR_INVALID_LENGTH != ret) // damn microsoft
{ {
@ -1108,7 +911,6 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
GA->pinAuthPresent = 1; GA->pinAuthPresent = 1;
break; break;
}
case GA_pinProtocol: case GA_pinProtocol:
printf1(TAG_GA,"CTAP_pinProtocol\n"); printf1(TAG_GA,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
@ -1138,15 +940,15 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
return 0; return 0;
} }
uint8_t parse_cose_key(CborValue * it, COSE_key * cose) uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv)
{ {
CborValue map; CborValue map;
size_t map_length; size_t map_length;
int ret,key; int ret,key;
unsigned int i; unsigned int i;
int xkey = 0,ykey = 0; int xkey = 0,ykey = 0;
cose->kty = 0; *kty = 0;
cose->crv = 0; *crv = 0;
CborType type = cbor_value_get_type(it); CborType type = cbor_value_get_type(it);
@ -1184,7 +986,7 @@ uint8_t parse_cose_key(CborValue * it, COSE_key * cose)
printf1(TAG_PARSE,"COSE_KEY_LABEL_KTY\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_KTY\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
{ {
ret = cbor_value_get_int_checked(&map, &cose->kty); ret = cbor_value_get_int_checked(&map, kty);
check_ret(ret); check_ret(ret);
} }
else else
@ -1199,7 +1001,7 @@ uint8_t parse_cose_key(CborValue * it, COSE_key * cose)
printf1(TAG_PARSE,"COSE_KEY_LABEL_CRV\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_CRV\n");
if (cbor_value_get_type(&map) == CborIntegerType) if (cbor_value_get_type(&map) == CborIntegerType)
{ {
ret = cbor_value_get_int_checked(&map, &cose->crv); ret = cbor_value_get_int_checked(&map, crv);
check_ret(ret); check_ret(ret);
} }
else else
@ -1209,14 +1011,14 @@ uint8_t parse_cose_key(CborValue * it, COSE_key * cose)
break; break;
case COSE_KEY_LABEL_X: case COSE_KEY_LABEL_X:
printf1(TAG_PARSE,"COSE_KEY_LABEL_X\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_X\n");
ret = parse_fixed_byte_string(&map, cose->pubkey.x, 32); ret = parse_fixed_byte_string(&map, x, 32);
check_retr(ret); check_retr(ret);
xkey = 1; xkey = 1;
break; break;
case COSE_KEY_LABEL_Y: case COSE_KEY_LABEL_Y:
printf1(TAG_PARSE,"COSE_KEY_LABEL_Y\n"); printf1(TAG_PARSE,"COSE_KEY_LABEL_Y\n");
ret = parse_fixed_byte_string(&map, cose->pubkey.y, 32); ret = parse_fixed_byte_string(&map, y, 32);
check_retr(ret); check_retr(ret);
ykey = 1; ykey = 1;
@ -1228,7 +1030,7 @@ uint8_t parse_cose_key(CborValue * it, COSE_key * cose)
ret = cbor_value_advance(&map); ret = cbor_value_advance(&map);
check_ret(ret); check_ret(ret);
} }
if (xkey == 0 || ykey == 0 || cose->kty == 0 || cose->crv == 0) if (xkey == 0 || ykey == 0 || *kty == 0 || *crv == 0)
{ {
return CTAP2_ERR_MISSING_PARAMETER; return CTAP2_ERR_MISSING_PARAMETER;
} }
@ -1308,7 +1110,7 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
break; break;
case CP_keyAgreement: case CP_keyAgreement:
printf1(TAG_CP,"CP_keyAgreement\n"); printf1(TAG_CP,"CP_keyAgreement\n");
ret = parse_cose_key(&map, &CP->keyAgreement); ret = parse_cose_key(&map, CP->keyAgreement.pubkey.x, CP->keyAgreement.pubkey.y, &CP->keyAgreement.kty, &CP->keyAgreement.crv);
check_retr(ret); check_retr(ret);
CP->keyAgreementPresent = 1; CP->keyAgreementPresent = 1;
break; break;

View File

@ -30,7 +30,7 @@ uint8_t parse_rp(struct rpId * rp, CborValue * val);
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up); uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up);
uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it); uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it);
uint8_t parse_cose_key(CborValue * it, COSE_key * cose); uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv);
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length); uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length);

View File

@ -16,12 +16,6 @@
#include "util.h" #include "util.h"
#include "log.h" #include "log.h"
#include "extensions.h" #include "extensions.h"
// move custom SHA512 command out,
// and the following headers too
#include "sha2.h"
#include "crypto.h"
#include APP_CONFIG #include APP_CONFIG
typedef enum typedef enum
@ -534,10 +528,6 @@ static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * ci
return buffer_status(); 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 ctaphid_handle_packet(uint8_t * pkt_raw)
{ {
uint8_t cmd; uint8_t cmd;
@ -728,155 +718,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
ctaphid_write(&wb, NULL, 0); ctaphid_write(&wb, NULL, 0);
is_busy = 0; is_busy = 0;
break; 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 #endif
default: default:
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd()); printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());

View File

@ -28,8 +28,6 @@
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51) #define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52) #define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
#define CTAPHID_GETRNG (TYPE_INIT | 0x60) #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_CMD 0x01
#define ERR_INVALID_PAR 0x02 #define ERR_INVALID_PAR 0x02

View File

@ -9,7 +9,7 @@
#include "storage.h" #include "storage.h"
void device_init(int argc, char *argv[]); void device_init();
uint32_t millis(); uint32_t millis();
@ -30,7 +30,6 @@ void main_loop_delay();
void heartbeat(); void heartbeat();
void device_reboot();
void authenticator_read_state(AuthenticatorState * ); void authenticator_read_state(AuthenticatorState * );
@ -54,11 +53,11 @@ int device_is_button_pressed();
// Test for user presence // Test for user presence
// Return 1 for user is present, 0 user not present, -1 if cancel is requested. // Return 1 for user is present, 0 user not present, -1 if cancel is requested.
int ctap_user_presence_test(uint32_t delay); extern int ctap_user_presence_test();
// Generate @num bytes of random numbers to @dest // Generate @num bytes of random numbers to @dest
// return 1 if success, error otherwise // return 1 if success, error otherwise
int ctap_generate_rng(uint8_t * dst, size_t num); extern int ctap_generate_rng(uint8_t * dst, size_t num);
// Increment atomic counter and return it. // Increment atomic counter and return it.
// Must support two counters, @sel selects counter0 or counter1. // Must support two counters, @sel selects counter0 or counter1.
@ -66,11 +65,11 @@ uint32_t ctap_atomic_count(int sel);
// Verify the user // Verify the user
// return 1 if user is verified, 0 if not // return 1 if user is verified, 0 if not
int ctap_user_verification(uint8_t arg); extern int ctap_user_verification(uint8_t arg);
// Must be implemented by application // Must be implemented by application
// data is HID_MESSAGE_SIZE long in bytes // data is HID_MESSAGE_SIZE long in bytes
void ctaphid_write_block(uint8_t * data); extern void ctaphid_write_block(uint8_t * data);
// Resident key // Resident key
@ -87,27 +86,5 @@ void boot_st_bootloader();
// HID wink command // HID wink command
void device_wink(); 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 NFC_IS_NA, NFC_IS_ACTIVE, or NFC_IS_AVAILABLE
#define NFC_IS_NA 0
#define NFC_IS_ACTIVE 1
#define NFC_IS_AVAILABLE 2
int device_is_nfc();
void request_from_nfc(bool request_active);
void device_init_button();
#endif #endif

View File

@ -35,28 +35,6 @@ int extension_needs_atomic_count(uint8_t klen, uint8_t * keyh)
|| ((wallet_request *) keyh)->operation == WalletSign; || ((wallet_request *) keyh)->operation == WalletSign;
} }
static uint8_t * output_buffer_ptr;
uint8_t output_buffer_offset;
uint8_t output_buffer_size;
void extension_writeback_init(uint8_t * buffer, uint8_t size)
{
output_buffer_ptr = buffer;
output_buffer_offset = 0;
output_buffer_size = size;
}
void extension_writeback(uint8_t * buf, uint8_t size)
{
if ((output_buffer_offset + size) > output_buffer_size)
{
return;
}
memmove(output_buffer_ptr + output_buffer_offset, buf, size);
output_buffer_offset += size;
}
int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh) int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
{ {
int8_t ret = 0; int8_t ret = 0;
@ -77,6 +55,8 @@ int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen
u2f_response_writeback((uint8_t *)&ret,1); u2f_response_writeback((uint8_t *)&ret,1);
#ifdef IS_BOOTLOADER #ifdef IS_BOOTLOADER
ret = bootloader_bridge(klen, keyh); ret = bootloader_bridge(klen, keyh);
#elif defined(WALLET_EXTENSION)
ret = bridge_u2f_to_wallet(_chal, _appid, klen, keyh);
#else #else
ret = bridge_u2f_to_solo(sig, keyh, klen); ret = bridge_u2f_to_solo(sig, keyh, klen);
u2f_response_writeback(sig,72); u2f_response_writeback(sig,72);
@ -102,7 +82,6 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output)
{ {
if (is_extension_request((uint8_t*)credid, sizeof(CredentialId))) if (is_extension_request((uint8_t*)credid, sizeof(CredentialId)))
{ {
printf1(TAG_EXT,"IS EXT REQ\r\n");
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId)); output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
return 1; return 1;
} }
@ -112,10 +91,10 @@ int16_t extend_fido2(CredentialId * credid, uint8_t * output)
} }
} }
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len) int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
{ {
struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) payload; struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) req->payload;
uint16_t rcode; uint16_t rcode;
if (req->ins == U2F_AUTHENTICATE) if (req->ins == U2F_AUTHENTICATE)
@ -139,7 +118,7 @@ int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len)
{ {
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{ {
rcode = U2F_SW_WRONG_DATA; rcode = U2F_SW_WRONG_PAYLOAD;
printf1(TAG_EXT, "Ignoring U2F auth request\n"); printf1(TAG_EXT, "Ignoring U2F auth request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl); dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end; goto end;

View File

@ -7,14 +7,8 @@
#ifndef EXTENSIONS_H_ #ifndef EXTENSIONS_H_
#define EXTENSIONS_H_ #define EXTENSIONS_H_
#include "u2f.h" #include "u2f.h"
#include "apdu.h"
int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh); int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len);
// return 1 if request is a wallet request
int is_extension_request(uint8_t * req, int len);
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len);
int16_t extend_fido2(CredentialId * credid, uint8_t * output); int16_t extend_fido2(CredentialId * credid, uint8_t * output);
@ -22,8 +16,4 @@ int bootloader_bridge(int klen, uint8_t * keyh);
int is_extension_request(uint8_t * kh, int len); int is_extension_request(uint8_t * kh, int len);
void extension_writeback_init(uint8_t * buffer, uint8_t size);
void extension_writeback(uint8_t * buf, uint8_t size);
#endif /* EXTENSIONS_H_ */ #endif /* EXTENSIONS_H_ */

View File

@ -31,15 +31,12 @@
#include "log.h" #include "log.h"
#include APP_CONFIG #include APP_CONFIG
// output must be at least 71 bytes // output must be at least 71 bytes
int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen) int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
{ {
int8_t ret = 0; int8_t ret = 0;
wallet_request * req = (wallet_request *) keyh; wallet_request * req = (wallet_request *) keyh;
extension_writeback_init(output, 71);
printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen); printf1(TAG_WALLET, "u2f-solo [%d]: ", keylen); dump_hex1(TAG_WALLET, keyh, keylen);
@ -64,14 +61,6 @@ int16_t bridge_u2f_to_solo(uint8_t * output, uint8_t * keyh, int keylen)
break; break;
#ifdef ENABLE_WALLET
case WalletSign:
case WalletRegister:
case WalletPin:
case WalletReset:
return bridge_to_wallet(keyh, keylen);
#endif
default: default:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation); printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
ret = CTAP1_ERR_INVALID_COMMAND; ret = CTAP1_ERR_INVALID_COMMAND;

View File

@ -14,8 +14,8 @@
#include "util.h" #include "util.h"
#include "storage.h" #include "storage.h"
#include "device.h" #include "device.h"
#include "extensions.h"
#if defined(USING_PC) || defined(IS_BOOTLOADER)
typedef enum typedef enum
{ {
MBEDTLS_ECP_DP_NONE = 0, MBEDTLS_ECP_DP_NONE = 0,
@ -32,7 +32,9 @@ typedef enum
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
} mbedtls_ecp_group_id; } mbedtls_ecp_group_id;
#else
#include "ecp.h"
#endif
// return 1 if hash is valid, 0 otherwise // return 1 if hash is valid, 0 otherwise
@ -68,14 +70,14 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
extension_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB)); u2f_response_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64); printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64);
break; break;
case CP_cmdGetRetries: case CP_cmdGetRetries:
printf1(TAG_WALLET,"cmdGetRetries\n"); printf1(TAG_WALLET,"cmdGetRetries\n");
pinTokenEnc[0] = ctap_leftover_pin_attempts(); pinTokenEnc[0] = ctap_leftover_pin_attempts();
extension_writeback(pinTokenEnc,1); u2f_response_writeback(pinTokenEnc,1);
break; break;
case CP_cmdSetPin: case CP_cmdSetPin:
@ -85,7 +87,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
if (!ctap_user_presence_test(5000)) if (!ctap_user_presence_test())
{ {
return CTAP2_ERR_OPERATION_DENIED; return CTAP2_ERR_OPERATION_DENIED;
} }
@ -111,7 +113,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
if (!ctap_user_presence_test(5000)) if (!ctap_user_presence_test())
{ {
return CTAP2_ERR_OPERATION_DENIED; return CTAP2_ERR_OPERATION_DENIED;
} }
@ -133,7 +135,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
if (!ctap_user_presence_test(5000)) if (!ctap_user_presence_test())
{ {
return CTAP2_ERR_OPERATION_DENIED; return CTAP2_ERR_OPERATION_DENIED;
} }
@ -143,7 +145,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return ret; return ret;
printf1(TAG_WALLET,"pinToken: "); dump_hex1(TAG_WALLET, PIN_TOKEN, 16); printf1(TAG_WALLET,"pinToken: "); dump_hex1(TAG_WALLET, PIN_TOKEN, 16);
extension_writeback(pinTokenEnc, PIN_TOKEN_SIZE); u2f_response_writeback(pinTokenEnc, PIN_TOKEN_SIZE);
break; break;
@ -157,7 +159,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
return 0; return 0;
} }
int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen) int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
{ {
static uint8_t msg_buf[WALLET_MAX_BUFFER]; static uint8_t msg_buf[WALLET_MAX_BUFFER];
int reqlen = klen; int reqlen = klen;
@ -257,7 +259,7 @@ int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen)
crypto_load_external_key(key, keysize); crypto_load_external_key(key, keysize);
crypto_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256K1); crypto_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256K1);
extension_writeback(sig,64); u2f_response_writeback(sig,64);
break; break;
case WalletRegister: case WalletRegister:
@ -359,7 +361,7 @@ int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen)
} }
} }
if (ctap_user_presence_test(5000)) if (ctap_user_presence_test())
{ {
printf1(TAG_WALLET,"Reseting device!\n"); printf1(TAG_WALLET,"Reseting device!\n");
ctap_reset(); ctap_reset();
@ -372,7 +374,39 @@ int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen)
break; break;
case WalletVersion:
u2f_response_writeback((uint8_t*)WALLET_VERSION, sizeof(WALLET_VERSION)-1);
break;
case WalletRng:
printf1(TAG_WALLET,"WalletRng\n");
if ( ctap_device_locked() )
{
printf1(TAG_ERR,"device locked\n");
ret = CTAP2_ERR_NOT_ALLOWED;
goto cleanup;
}
if ( ctap_is_pin_set() )
{
if ( ! check_pinhash(req->pinAuth, msg_buf, reqlen))
{
printf2(TAG_ERR,"pinAuth is NOT valid\n");
dump_hex1(TAG_ERR,msg_buf,reqlen);
ret = CTAP2_ERR_PIN_AUTH_INVALID;
goto cleanup;
}
}
ret = ctap_generate_rng(sig, 72);
if (ret != 1)
{
printf1(TAG_WALLET,"Rng failed\n");
ret = CTAP2_ERR_PROCESSING;
goto cleanup;
}
ret = 0;
u2f_response_writeback((uint8_t *)sig,72);
break;
default: default:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation); printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);

View File

@ -87,7 +87,10 @@ typedef enum
} WalletOperation; } WalletOperation;
int16_t bridge_to_wallet(uint8_t * keyh, uint8_t klen); int16_t bridge_u2f_to_extensions(uint8_t * chal, uint8_t * appid, uint8_t klen, uint8_t * keyh);
// return 1 if request is a wallet request
int is_extension_request(uint8_t * req, int len);
void wallet_init(); void wallet_init();

View File

@ -48,9 +48,6 @@ struct logtag tagtable[] = {
{TAG_STOR,"STOR"}, {TAG_STOR,"STOR"},
{TAG_BOOT,"BOOT"}, {TAG_BOOT,"BOOT"},
{TAG_EXT,"EXT"}, {TAG_EXT,"EXT"},
{TAG_NFC,"NFC"},
{TAG_NFC_APDU, "NAPDU"},
{TAG_CCID, "CCID"},
}; };
@ -71,7 +68,7 @@ void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...)
{ {
if (tag & tagtable[i].tagn) if (tag & tagtable[i].tagn)
{ {
if (tagtable[i].tag[0] && !(tag & TAG_NO_TAG)) printf("[%s] ", tagtable[i].tag); if (tagtable[i].tag[0]) printf("[%s] ", tagtable[i].tag);
i = 0; i = 0;
break; break;
} }

View File

@ -23,31 +23,27 @@ void set_logging_tag(uint32_t tag);
typedef enum typedef enum
{ {
TAG_GEN = (1 << 0), TAG_GEN = (1 << 0),
TAG_MC = (1 << 1), TAG_MC = (1 << 1),
TAG_GA = (1 << 2), TAG_GA = (1 << 2),
TAG_CP = (1 << 3), TAG_CP = (1 << 3),
TAG_ERR = (1 << 4), TAG_ERR = (1 << 4),
TAG_PARSE = (1 << 5), TAG_PARSE= (1 << 5),
TAG_CTAP = (1 << 6), TAG_CTAP = (1 << 6),
TAG_U2F = (1 << 7), TAG_U2F = (1 << 7),
TAG_DUMP = (1 << 8), TAG_DUMP = (1 << 8),
TAG_GREEN = (1 << 9), TAG_GREEN = (1 << 9),
TAG_RED = (1 << 10), TAG_RED= (1 << 10),
TAG_TIME = (1 << 11), TAG_TIME= (1 << 11),
TAG_HID = (1 << 12), TAG_HID = (1 << 12),
TAG_USB = (1 << 13), TAG_USB = (1 << 13),
TAG_WALLET = (1 << 14), TAG_WALLET = (1 << 14),
TAG_STOR = (1 << 15), TAG_STOR = (1 << 15),
TAG_DUMP2 = (1 << 16), TAG_DUMP2 = (1 << 16),
TAG_BOOT = (1 << 17), TAG_BOOT = (1 << 17),
TAG_EXT = (1 << 18), TAG_EXT = (1 << 18),
TAG_NFC = (1 << 19),
TAG_NFC_APDU = (1 << 20),
TAG_CCID = (1 << 21),
TAG_NO_TAG = (1UL << 30), TAG_FILENO = (1u << 31)
TAG_FILENO = (1UL << 31)
} LOG_TAG; } LOG_TAG;
#if DEBUG_LEVEL > 0 #if DEBUG_LEVEL > 0

View File

@ -7,8 +7,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include "cbor.h" #include "cbor.h"
#include "device.h" #include "device.h"
@ -21,39 +19,47 @@
#if !defined(TEST) #if !defined(TEST)
int main()
int main(int argc, char *argv[])
{ {
uint8_t hidmsg[64]; uint8_t hidmsg[64];
uint32_t t1 = 0; uint32_t t1 = 0;
set_logging_mask( set_logging_mask(
/*0*/ /*0*/
//TAG_GEN| // TAG_GEN|
// TAG_MC | // TAG_MC |
// TAG_GA | // TAG_GA |
TAG_WALLET | TAG_WALLET |
TAG_STOR | TAG_STOR |
//TAG_NFC_APDU | // TAG_CP |
TAG_NFC | // TAG_CTAP|
//TAG_CP | // TAG_HID|
// TAG_CTAP| /*TAG_U2F|*/
//TAG_HID| // TAG_PARSE |
TAG_U2F| // TAG_TIME|
//TAG_PARSE | // TAG_DUMP|
//TAG_TIME| TAG_GREEN|
// TAG_DUMP| TAG_RED|
TAG_GREEN| TAG_ERR
TAG_RED| );
TAG_EXT|
TAG_CCID|
TAG_ERR
);
device_init(argc, argv); 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)); memset(hidmsg,0,sizeof(hidmsg));
printf1(TAG_GEN,"recv'ing hid msg \n");
while(1) while(1)
{ {
@ -74,7 +80,6 @@ int main(int argc, char *argv[])
{ {
} }
ctaphid_check_timeouts(); ctaphid_check_timeouts();
} }
// Should never get here // Should never get here

View File

@ -7,11 +7,9 @@
#include <stdlib.h> #include <stdlib.h>
#include "u2f.h" #include "u2f.h"
#include "ctap.h" #include "ctap.h"
#include "ctaphid.h"
#include "crypto.h" #include "crypto.h"
#include "log.h" #include "log.h"
#include "device.h" #include "device.h"
#include "apdu.h"
#include "wallet.h" #include "wallet.h"
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
#include "extensions.h" #include "extensions.h"
@ -29,12 +27,12 @@ void u2f_reset_response();
static CTAP_RESPONSE * _u2f_resp = NULL; static CTAP_RESPONSE * _u2f_resp = NULL;
void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPONSE * resp) void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
{ {
uint16_t rcode = 0; uint16_t rcode = 0;
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
uint8_t byte; uint8_t byte;
ctap_response_init(resp);
u2f_set_writeback_buffer(resp); u2f_set_writeback_buffer(resp);
if (req->cla != 0) if (req->cla != 0)
@ -44,7 +42,7 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO
goto end; goto end;
} }
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
rcode = extend_u2f(req, payload, len); rcode = extend_u2f(req, len);
#endif #endif
if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything... if (rcode != U2F_SW_NO_ERROR && rcode != U2F_SW_CONDITIONS_NOT_SATISFIED) // If the extension didn't do anything...
{ {
@ -61,7 +59,7 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO
{ {
timestamp(); timestamp();
rcode = u2f_register((struct u2f_register_request*)payload); rcode = u2f_register((struct u2f_register_request*)req->payload);
printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp()); printf1(TAG_TIME,"u2f_register time: %d ms\n", timestamp());
} }
@ -69,7 +67,7 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO
case U2F_AUTHENTICATE: case U2F_AUTHENTICATE:
printf1(TAG_U2F, "U2F_AUTHENTICATE\n"); printf1(TAG_U2F, "U2F_AUTHENTICATE\n");
timestamp(); timestamp();
rcode = u2f_authenticate((struct u2f_authenticate_request*)payload, req->p1); rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1);
printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp()); printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", timestamp());
break; break;
case U2F_VERSION: case U2F_VERSION:
@ -96,8 +94,6 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO
#endif #endif
} }
device_set_status(CTAPHID_STATUS_IDLE);
end: end:
if (rcode != U2F_SW_NO_ERROR) if (rcode != U2F_SW_NO_ERROR)
{ {
@ -113,22 +109,6 @@ end:
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length); printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
} }
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp)
{
if (!header)
return;
request_from_nfc(true); // disable presence test
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
request_from_nfc(false); // enable presence test
}
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) int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len)
{ {
@ -176,7 +156,7 @@ static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE); memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
} }
int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey) static 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); ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE);
u2f_make_auth_tag(kh, appid, kh->tag); u2f_make_auth_tag(kh, appid, kh->tag);
@ -186,25 +166,26 @@ int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pu
} }
// Return 1 if authenticate, 0 if not.
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid) static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid)
{ {
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE]; uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
u2f_make_auth_tag(kh, appid, tag); u2f_make_auth_tag(kh, appid, tag);
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0) if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
{ {
return 1; return 0;
} }
else else
{ {
printf1(TAG_U2F, "key handle + appid not authentic\n"); printf1(TAG_U2F, "key handle + appid not authentic\n");
printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE); printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE);
printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE); printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
return 0; return -1;
} }
} }
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control)
{ {
@ -215,8 +196,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
if (control == U2F_AUTHENTICATE_CHECK) if (control == U2F_AUTHENTICATE_CHECK)
{ {
printf1(TAG_U2F, "CHECK-ONLY\r\n"); if (u2f_appid_eq(&req->kh, req->app) == 0)
if (u2f_authenticate_credential(&req->kh, req->app))
{ {
return U2F_SW_CONDITIONS_NOT_SATISFIED; return U2F_SW_CONDITIONS_NOT_SATISFIED;
} }
@ -226,47 +206,42 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
} }
} }
if ( if (
(control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) || control != U2F_AUTHENTICATE_SIGN ||
req->khl != U2F_KEY_HANDLE_SIZE || req->khl != U2F_KEY_HANDLE_SIZE ||
(!u2f_authenticate_credential(&req->kh, req->app)) || // Order of checks is important u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important
u2f_load_key(&req->kh, req->app) != 0 u2f_load_key(&req->kh, req->app) != 0
) )
{ {
return U2F_SW_WRONG_DATA; return U2F_SW_WRONG_PAYLOAD;
} }
// dont-enforce-user-presence-and-sign
if (control == U2F_AUTHENTICATE_SIGN_NO_USER)
up = 0;
if(up)
{ if (ctap_user_presence_test() == 0)
if (ctap_user_presence_test(750) == 0) {
{ return U2F_SW_CONDITIONS_NOT_SATISFIED;
return U2F_SW_CONDITIONS_NOT_SATISFIED; }
}
}
count = ctap_atomic_count(0); count = ctap_atomic_count(0);
hash[0] = (count >> 24) & 0xff; hash[0] = 0xff;
hash[1] = (count >> 16) & 0xff; hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff; hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff; hash[3] = (count >> 0) & 0xff;
crypto_sha256_init(); crypto_sha256_init();
crypto_sha256_update(req->app, 32); crypto_sha256_update(req->app,32);
crypto_sha256_update(&up, 1); crypto_sha256_update(&up,1);
crypto_sha256_update(hash, 4); crypto_sha256_update(hash,4);
crypto_sha256_update(req->chal, 32); crypto_sha256_update(req->chal,32);
crypto_sha256_final(hash); 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); crypto_ecc256_sign(hash, 32, sig);
u2f_response_writeback(&up,1); u2f_response_writeback(&up,1);
hash[0] = (count >> 24) & 0xff; hash[0] = 0xff;
hash[1] = (count >> 16) & 0xff; hash[1] = (count >> 16) & 0xff;
hash[2] = (count >> 8) & 0xff; hash[2] = (count >> 8) & 0xff;
hash[3] = (count >> 0) & 0xff; hash[3] = (count >> 0) & 0xff;
@ -288,10 +263,10 @@ static int16_t u2f_register(struct u2f_register_request * req)
const uint16_t attest_size = attestation_cert_der_size; const uint16_t attest_size = attestation_cert_der_size;
if ( ! ctap_user_presence_test(750)) if ( ! ctap_user_presence_test())
{ {
return U2F_SW_CONDITIONS_NOT_SATISFIED; return U2F_SW_CONDITIONS_NOT_SATISFIED;
} }
if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1) if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1)
{ {
@ -325,6 +300,8 @@ static int16_t u2f_register(struct u2f_register_request * req)
dump_signature_der(sig); dump_signature_der(sig);
/*printf1(TAG_U2F, "dersig: "); dump_hex1(TAG_U2F,sig,74);*/
return U2F_SW_NO_ERROR; return U2F_SW_NO_ERROR;
} }

View File

@ -38,16 +38,16 @@
// U2F Authenticate // U2F Authenticate
#define U2F_AUTHENTICATE_CHECK 0x7 #define U2F_AUTHENTICATE_CHECK 0x7
#define U2F_AUTHENTICATE_SIGN 0x3 #define U2F_AUTHENTICATE_SIGN 0x3
#define U2F_AUTHENTICATE_SIGN_NO_USER 0x8
// Command status responses // Command status responses
#define U2F_SW_NO_ERROR 0x9000 #define U2F_SW_NO_ERROR 0x9000
#define U2F_SW_WRONG_DATA 0x6984
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 #define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00 #define U2F_SW_INS_NOT_SUPPORTED 0x6d00
#define U2F_SW_WRONG_LENGTH 0x6700 #define U2F_SW_WRONG_LENGTH 0x6700
#define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00 #define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00
#define U2F_SW_WRONG_DATA 0x6a80 #define U2F_SW_WRONG_PAYLOAD 0x6a80
#define U2F_SW_INSUFFICIENT_MEMORY 0x9210 #define U2F_SW_INSUFFICIENT_MEMORY 0x9210
// Delay in milliseconds to wait for user input // Delay in milliseconds to wait for user input
@ -95,15 +95,9 @@ struct u2f_authenticate_request
}; };
// u2f_request send a U2F message to U2F protocol // u2f_request send a U2F message to U2F protocol
// @req U2F message // @req U2F message
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp); 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 * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
void u2f_reset_response(); void u2f_reset_response();

View File

@ -5,9 +5,8 @@ version=${1:-master}
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/ export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
cd /solo/targets/stm32l432 cd /solo/targets/stm32l432
git fetch --tags git fetch
git checkout ${version} git checkout ${version}
git submodule update --init --recursive
version=$(git describe) version=$(git describe)
make cbor make cbor
@ -35,21 +34,4 @@ function build() {
build bootloader nonverifying build bootloader nonverifying
build bootloader verifying build bootloader verifying
build firmware hacker solo build firmware hacker solo
build firmware hacker-debug-1 solo
build firmware hacker-debug-2 solo
build firmware secure solo build firmware secure solo
build firmware secure-non-solokeys solo
pip install -U pip
pip install -U solo-python
cd ${out_dir}
bundle="bundle-hacker-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2
bundle="bundle-hacker-debug-1-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-1-${version}.hex ${bundle}.hex
bundle="bundle-hacker-debug-2-${version}"
/opt/conda/bin/solo mergehex bootloader-nonverifying-${version}.hex firmware-hacker-debug-2-${version}.hex ${bundle}.hex
bundle="bundle-secure-non-solokeys-${version}"
/opt/conda/bin/solo mergehex bootloader-verifying-${version}.hex firmware-secure-non-solokeys-${version}.hex ${bundle}.hex
sha256sum ${bundle}.hex > ${bundle}.sha2

View File

@ -20,9 +20,6 @@
], ],
"userVerificationDetails": [ "userVerificationDetails": [
[ [
{
"userVerification": 1
},
{ {
"userVerification": 4 "userVerification": 4
} }

View File

@ -11,11 +11,6 @@ nav:
- FIDO2 Implementation: solo/fido2-impl.md - FIDO2 Implementation: solo/fido2-impl.md
- Metadata Statements: solo/metadata-statements.md - Metadata Statements: solo/metadata-statements.md
- Build instructions: solo/building.md - Build instructions: solo/building.md
- Programming instructions: solo/programming.md
- Bootloader mode: solo/bootloader-mode.md
- Customization: solo/customization.md
- Solo Extras: solo/solo-extras.md
- Running on Nucleo32 board: solo/nucleo32-board.md
- Signed update process: solo/signed-updates.md - Signed update process: solo/signed-updates.md
- Code documentation: solo/code-overview.md - Code documentation: solo/code-overview.md
- Contributing Code: solo/contributing.md - Contributing Code: solo/contributing.md

View File

@ -7,7 +7,6 @@
#ifndef SRC_APP_H_ #ifndef SRC_APP_H_
#define SRC_APP_H_ #define SRC_APP_H_
#include <stdbool.h>
#define USING_DEV_BOARD #define USING_DEV_BOARD
@ -16,13 +15,11 @@
#define DEBUG_LEVEL 1 #define DEBUG_LEVEL 1
#define ENABLE_U2F #define ENABLE_U2F
#define ENABLE_U2F_EXTENSIONS
//#define BRIDGE_TO_WALLET //#define BRIDGE_TO_WALLET
void printing_init(); void printing_init();
extern bool use_udp;
// 0xRRGGBB // 0xRRGGBB
#define LED_INIT_VALUE 0x000800 #define LED_INIT_VALUE 0x000800
#define LED_WINK_VALUE 0x000008 #define LED_WINK_VALUE 0x000008

View File

@ -15,7 +15,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <fcntl.h>
#include "device.h" #include "device.h"
#include "cbor.h" #include "cbor.h"
@ -23,13 +22,6 @@
#include "log.h" #include "log.h"
#include "ctaphid.h" #include "ctaphid.h"
#define RK_NUM 50
bool use_udp = true;
struct ResidentKeyStore {
CTAP_residentKey rks[RK_NUM];
} RK_STORE;
void authenticator_initialize(); void authenticator_initialize();
@ -43,11 +35,7 @@ void device_set_status(uint32_t status)
__device_status = status; __device_status = status;
} }
void device_reboot()
{
printf1(TAG_RED, "REBOOT command recieved!\r\n");
exit(100);
}
int udp_server() int udp_server()
{ {
@ -125,6 +113,12 @@ void udp_send(int fd, uint8_t * buf, int size)
} }
} }
void udp_close(int fd)
{
close(fd);
}
uint32_t millis() uint32_t millis()
{ {
@ -135,79 +129,35 @@ uint32_t millis()
} }
static int fd = 0; static int serverfd = 0;
void usbhid_init() void usbhid_init()
{ {
if (use_udp) // just bridge to UDP for now for pure software testing
{ serverfd = udp_server();
fd = udp_server();
}
else
{
fd = open("/dev/hidg0", O_RDWR);
if (fd < 0)
{
perror("hidg open");
exit(1);
}
}
} }
// Receive 64 byte USB HID message, don't block, return size of packet, return 0 if nothing // Receive 64 byte USB HID message, don't block, return size of packet, return 0 if nothing
int usbhid_recv(uint8_t * msg) int usbhid_recv(uint8_t * msg)
{ {
int l = 0; int l = udp_recv(serverfd, msg, HID_MESSAGE_SIZE);
if (use_udp) /*if (l && l != HID_MESSAGE_SIZE)*/
{ /*{*/
l = udp_recv(fd, msg, HID_MESSAGE_SIZE); /*printf("Error, recv'd message of wrong size %d", l);*/
} /*exit(1);*/
else /*}*/
{
l = read(fd, msg, HID_MESSAGE_SIZE); /* Flawfinder: ignore */
if (l < 0)
{
perror("hidg read");
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; return l;
} }
// Send 64 byte USB HID message // Send 64 byte USB HID message
void usbhid_send(uint8_t * msg) void usbhid_send(uint8_t * msg)
{ {
if (use_udp) udp_send(serverfd, msg, HID_MESSAGE_SIZE);
{
udp_send(fd, msg, HID_MESSAGE_SIZE);
}
else
{
if (write(fd, msg, HID_MESSAGE_SIZE) < 0)
{
perror("hidg write");
exit(1);
}
}
} }
void usbhid_close() void usbhid_close()
{ {
close(fd); udp_close(serverfd);
} }
void int_handler(int i) void int_handler(int i)
@ -217,54 +167,13 @@ void int_handler(int i)
exit(0); exit(0);
} }
void device_init()
void usage(const char * cmd)
{ {
fprintf(stderr, "Usage: %s [-b udp|hidg]\n", cmd);
fprintf(stderr, " -b backing implementation: udp(default) or hidg\n");
exit(1);
}
void device_init(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "b:")) != -1)
{
switch (opt)
{
case 'b':
if (strcmp("udp", optarg) == 0)
{
use_udp = true;
}
else if (strcmp("hidg", optarg) == 0)
{
use_udp = false;
}
else
{
usage(argv[0]);
}
break;
default:
usage(argv[0]);
break;
}
}
signal(SIGINT, int_handler); signal(SIGINT, int_handler);
printf1(TAG_GREEN, "Using %s backing\n", use_udp ? "UDP" : "hidg");
usbhid_init(); usbhid_init();
authenticator_initialize(); authenticator_initialize();
ctaphid_init();
ctap_init( 1 );
} }
@ -272,15 +181,7 @@ void main_loop_delay()
{ {
struct timespec ts; struct timespec ts;
ts.tv_sec = 0; ts.tv_sec = 0;
ts.tv_nsec = 1000*1000*100; ts.tv_nsec = 1000*1000*25;
nanosleep(&ts,NULL);
}
void delay(uint32_t ms)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 1000*1000*ms;
nanosleep(&ts,NULL); nanosleep(&ts,NULL);
} }
@ -297,7 +198,7 @@ void ctaphid_write_block(uint8_t * data)
} }
int ctap_user_presence_test(uint32_t d) int ctap_user_presence_test()
{ {
return 1; return 1;
} }
@ -346,7 +247,6 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
const char * state_file = "authenticator_state.bin"; const char * state_file = "authenticator_state.bin";
const char * backup_file = "authenticator_state2.bin"; const char * backup_file = "authenticator_state2.bin";
const char * rk_file = "resident_keys.bin";
void authenticator_read_state(AuthenticatorState * state) void authenticator_read_state(AuthenticatorState * state)
{ {
@ -466,24 +366,6 @@ 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() void authenticator_initialize()
{ {
uint8_t header[16]; uint8_t header[16];
@ -507,22 +389,6 @@ void authenticator_initialize()
perror("fwrite"); perror("fwrite");
exit(1); 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 else
{ {
@ -561,12 +427,6 @@ void authenticator_initialize()
exit(1); exit(1);
} }
// resident_keys
memset(&RK_STORE,0xff,sizeof(RK_STORE));
sync_rk();
} }
} }
@ -575,65 +435,29 @@ void device_manage()
} }
void ctap_reset_rk() void ctap_reset_rk()
{ {
memset(&RK_STORE,0xff,sizeof(RK_STORE));
sync_rk();
} }
uint32_t ctap_rk_size() uint32_t ctap_rk_size()
{ {
return RK_NUM; printf("Warning: rk not implemented\n");
return 0;
} }
void ctap_store_rk(int index,CTAP_residentKey * rk)
void ctap_store_rk(int index, CTAP_residentKey * rk)
{ {
if (index < RK_NUM) printf("Warning: rk not implemented\n");
{
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)
{ {
memmove(rk, RK_STORE.rks + index, sizeof(CTAP_residentKey)); printf("Warning: rk not implemented\n");
} }
void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
void ctap_overwrite_rk(int index, CTAP_residentKey * rk)
{ {
if (index < RK_NUM) printf("Warning: rk not implemented\n");
{
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() void device_wink()
{ {
printf("*WINK*\n"); printf("*WINK*\n");
} }
int device_is_nfc()
{
return 0;
}
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
{
}

1
python-fido2 Submodule

Submodule python-fido2 added at 329434fdd4

View File

@ -5,7 +5,7 @@ endif
APPMAKE=build/application.mk APPMAKE=build/application.mk
BOOTMAKE=build/bootloader.mk BOOTMAKE=build/bootloader.mk
merge_hex=solo mergehex merge_hex=../../tools/solotool.py 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 .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,15 +15,6 @@ merge_hex=solo mergehex
firmware-hacker: firmware-hacker:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 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-non-solokeys:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DFLASH_ROP=2'
firmware-secure: firmware-secure:
$(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2' $(MAKE) -f $(APPMAKE) -j8 solo.hex PREFIX=$(PREFIX) DEBUG=0 EXTRA_DEFINES='-DUSE_SOLOKEYS_CERT -DFLASH_ROP=2'
@ -62,6 +53,7 @@ boot-no-sig:
build-release-locked: cbor clean2 boot-sig-checking clean all-locked build-release-locked: cbor clean2 boot-sig-checking clean all-locked
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex $(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
rm -f solo.hex bootloader.hex # don't program solo.hex ...
build-release: cbor clean2 boot-sig-checking clean all build-release: cbor clean2 boot-sig-checking clean all
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex $(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
@ -95,11 +87,6 @@ flashboot: solo.hex bootloader.hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
flash-firmware:
arm-none-eabi-size -A solo.elf
solo program aux enter-bootloader
solo program bootloader solo.hex
# tell ST DFU to enter application # tell ST DFU to enter application
detach: detach:
STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1 STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1

View File

@ -0,0 +1,73 @@
CC=arm-none-eabi-gcc
CP=arm-none-eabi-objcopy
SZ=arm-none-eabi-size
AR=arm-none-eabi-ar
# ST related
SRC = src/main.c src/init.c src/flash.c src/led.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += lib/stm32l4xx_ll_gpio.c lib/stm32l4xx_ll_pwr.c lib/stm32l4xx_ll_rcc.c lib/stm32l4xx_ll_tim.c lib/stm32l4xx_ll_utils.c
OBJ1=$(SRC:.c=.o)
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
SEARCH=-L../../tinycbor/lib
LDSCRIPT=stm32l432xx.ld
CFLAGS= $(INC)
TARGET=solo
HW=-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
# Solo or Nucleo board
CHIP=STM32L432xx
DEFINES = -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER
DEFINES += -DTEST_SOLO_STM32 -DTEST
CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW)
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref
.PRECIOUS: %.o
all: $(TARGET).elf
$(SZ) $^
%.o: %.c
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
$(CC) $^ $(HW) -O3 $(CFLAGS) -o $@
%.o: %.s
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
%.elf: $(OBJ)
$(CC) $^ $(HW) $(LDFLAGS) -o $@
%.hex: %.elf
$(CP) -O ihex $^ $(TARGET).hex
$(CP) -O binary $^ $(TARGET).bin
clean:
rm -f *.o src/*.o src/*.elf *.elf *.hex $(OBJ)
flash: $(TARGET).hex
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
STM32_Programmer_CLI -c port=SWD -halt -d $(TARGET).hex -rst
detach:
STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1
cbor:
cd ../../tinycbor/ && make clean
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
LDFLAGS="$(LDFLAGS_LIB)" \
CFLAGS="$(CFLAGS)"

View File

@ -55,7 +55,7 @@
#define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION #define SOLO_PRODUCT_NAME "Solo Bootloader " SOLO_VERSION
void printing_init(); void printing_init();
void hw_init(int lf); void hw_init(void);
// Trigger software reset // Trigger software reset
void device_reboot(); void device_reboot();

View File

@ -8,10 +8,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx.h"
#include "cbor.h" #include "cbor.h"
#include "device.h" #include "device.h"
#include "ctaphid.h" #include "ctaphid.h"
@ -21,14 +17,14 @@
#include "ctap.h" #include "ctap.h"
#include "app.h" #include "app.h"
#include "memory_layout.h" #include "memory_layout.h"
#include "init.h" #include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx.h"
uint8_t REBOOT_FLAG = 0; uint8_t REBOOT_FLAG = 0;
void SystemClock_Config(void);
void BOOT_boot(void) void BOOT_boot(void)
{ {
typedef void (*pFunction)(void); typedef void (*pFunction)(void);
@ -73,18 +69,7 @@ int main()
TAG_ERR TAG_ERR
); );
// device_init(); device_init();
init_gpio();
init_millisecond_timer(1);
#if DEBUG_LEVEL > 0
init_debug_uart();
#endif
device_init_button();
printf1(TAG_GEN,"init device\n"); printf1(TAG_GEN,"init device\n");
t1 = millis(); t1 = millis();
@ -122,13 +107,7 @@ int main()
#ifdef SOLO_HACKER #ifdef SOLO_HACKER
start_bootloader: start_bootloader:
#endif #endif
SystemClock_Config();
init_gpio();
init_millisecond_timer(0);
init_pwm();
init_rng();
usbhid_init(); usbhid_init();
printf1(TAG_GEN,"init usb\n"); printf1(TAG_GEN,"init usb\n");
ctaphid_init(); ctaphid_init();

View File

@ -2,20 +2,18 @@ include build/common.mk
# ST related # 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/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/nfc.c src/ams.c src/sense.c SRC += src/fifo.c src/crypto.c src/attestation.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_LIB) SRC += $(DRIVER_LIBS) $(USB_LIB)
# FIDO2 lib # FIDO2 lib
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
SRC += ../../fido2/extensions/wallet.c
# Crypto libs # Crypto libs
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c 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) OBJ1=$(SRC:.c=.o)
OBJ=$(OBJ1:.s=.o) OBJ=$(OBJ1:.s=.o)
@ -23,7 +21,6 @@ OBJ=$(OBJ1:.s=.o)
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
INC += -I../../crypto/tiny-AES-c INC += -I../../crypto/tiny-AES-c
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
SEARCH=-L../../tinycbor/lib SEARCH=-L../../tinycbor/lib
@ -44,14 +41,12 @@ DEBUG=0
endif endif
DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAPP_CONFIG=\"app.h\" $(EXTRA_DEFINES) 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 \ CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections $(HW) -g $(VERSION_FLAGS)
-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_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor 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 .PRECIOUS: %.o
@ -62,7 +57,7 @@ all: $(TARGET).elf
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@ $(CC) $^ $(HW) -Os $(CFLAGS) -o $@
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c ../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
$(CC) $^ $(HW) -O3 $(ECC_CFLAGS) -o $@ $(CC) $^ $(HW) -O3 $(CFLAGS) -o $@
%.o: %.s %.o: %.s
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@ $(CC) $^ $(HW) -Os $(CFLAGS) -o $@
@ -71,7 +66,6 @@ all: $(TARGET).elf
$(CC) $^ $(HW) $(LDFLAGS) -o $@ $(CC) $^ $(HW) $(LDFLAGS) -o $@
%.hex: %.elf %.hex: %.elf
$(SZ) $^
$(CP) -O ihex $^ $(TARGET).hex $(CP) -O ihex $^ $(TARGET).hex
clean: clean:
@ -82,4 +76,4 @@ cbor:
cd ../../tinycbor/ && make clean cd ../../tinycbor/ && make clean
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \ cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
LDFLAGS="$(LDFLAGS_LIB)" \ LDFLAGS="$(LDFLAGS_LIB)" \
CFLAGS="$(CFLAGS) -Os" CFLAGS="$(CFLAGS)"

View File

@ -3,7 +3,7 @@ include build/common.mk
# ST related # ST related
SRC = bootloader/main.c bootloader/bootloader.c SRC = bootloader/main.c bootloader/bootloader.c
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c SRC += src/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/sense.c SRC += src/fifo.c src/crypto.c src/attestation.c
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_LIB) SRC += $(DRIVER_LIBS) $(USB_LIB)
@ -13,7 +13,6 @@ SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2
# Crypto libs # Crypto libs
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c 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) OBJ1=$(SRC:.c=.o)
OBJ=$(OBJ1:.s=.o) OBJ=$(OBJ1:.s=.o)
@ -22,7 +21,6 @@ OBJ=$(OBJ1:.s=.o)
INC = -Ibootloader/ -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions 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../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
INC += -I../../crypto/tiny-AES-c INC += -I../../crypto/tiny-AES-c
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
ifndef LDSCRIPT ifndef LDSCRIPT
LDSCRIPT=linker/bootloader_stm32l4xx.ld LDSCRIPT=linker/bootloader_stm32l4xx.ld

View File

@ -6,12 +6,11 @@ AR=$(PREFIX)arm-none-eabi-ar
DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_ll_gpio.c \ 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_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_usb.c lib/stm32l4xx_ll_utils.c lib/stm32l4xx_ll_pwr.c \
lib/stm32l4xx_ll_usart.c lib/stm32l4xx_ll_spi.c lib/stm32l4xx_ll_exti.c lib/stm32l4xx_ll_usart.c
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \ USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \ lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \ lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c
lib/usbd/usbd_ccid.c
VERSION:=$(shell git describe --abbrev=0 ) VERSION:=$(shell git describe --abbrev=0 )
VERSION_FULL:=$(shell git describe) VERSION_FULL:=$(shell git describe)

View File

@ -1,844 +0,0 @@
/**
******************************************************************************
* @file stm32l4xx_hal_tsc.h
* @author MCD Application Team
* @brief Header file of TSC HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32L4xx_HAL_TSC_H
#define STM32L4xx_HAL_TSC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal_def.h"
/** @addtogroup STM32L4xx_HAL_Driver
* @{
*/
/** @addtogroup TSC
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup TSC_Exported_Types TSC Exported Types
* @{
*/
/**
* @brief TSC state structure definition
*/
typedef enum
{
HAL_TSC_STATE_RESET = 0x00UL, /*!< TSC registers have their reset value */
HAL_TSC_STATE_READY = 0x01UL, /*!< TSC registers are initialized or acquisition is completed with success */
HAL_TSC_STATE_BUSY = 0x02UL, /*!< TSC initialization or acquisition is on-going */
HAL_TSC_STATE_ERROR = 0x03UL /*!< Acquisition is completed with max count error */
} HAL_TSC_StateTypeDef;
/**
* @brief TSC group status structure definition
*/
typedef enum
{
TSC_GROUP_ONGOING = 0x00UL, /*!< Acquisition on group is on-going or not started */
TSC_GROUP_COMPLETED = 0x01UL /*!< Acquisition on group is completed with success (no max count error) */
} TSC_GroupStatusTypeDef;
/**
* @brief TSC init structure definition
*/
typedef struct
{
uint32_t CTPulseHighLength; /*!< Charge-transfer high pulse length
This parameter can be a value of @ref TSC_CTPulseHL_Config */
uint32_t CTPulseLowLength; /*!< Charge-transfer low pulse length
This parameter can be a value of @ref TSC_CTPulseLL_Config */
uint32_t SpreadSpectrum; /*!< Spread spectrum activation
This parameter can be a value of @ref TSC_CTPulseLL_Config */
uint32_t SpreadSpectrumDeviation; /*!< Spread spectrum deviation
This parameter must be a number between Min_Data = 0 and Max_Data = 127 */
uint32_t SpreadSpectrumPrescaler; /*!< Spread spectrum prescaler
This parameter can be a value of @ref TSC_SpreadSpec_Prescaler */
uint32_t PulseGeneratorPrescaler; /*!< Pulse generator prescaler
This parameter can be a value of @ref TSC_PulseGenerator_Prescaler */
uint32_t MaxCountValue; /*!< Max count value
This parameter can be a value of @ref TSC_MaxCount_Value */
uint32_t IODefaultMode; /*!< IO default mode
This parameter can be a value of @ref TSC_IO_Default_Mode */
uint32_t SynchroPinPolarity; /*!< Synchro pin polarity
This parameter can be a value of @ref TSC_Synchro_Pin_Polarity */
uint32_t AcquisitionMode; /*!< Acquisition mode
This parameter can be a value of @ref TSC_Acquisition_Mode */
uint32_t MaxCountInterrupt; /*!< Max count interrupt activation
This parameter can be set to ENABLE or DISABLE. */
uint32_t ChannelIOs; /*!< Channel IOs mask */
uint32_t ShieldIOs; /*!< Shield IOs mask */
uint32_t SamplingIOs; /*!< Sampling IOs mask */
} TSC_InitTypeDef;
/**
* @brief TSC IOs configuration structure definition
*/
typedef struct
{
uint32_t ChannelIOs; /*!< Channel IOs mask */
uint32_t ShieldIOs; /*!< Shield IOs mask */
uint32_t SamplingIOs; /*!< Sampling IOs mask */
} TSC_IOConfigTypeDef;
/**
* @brief TSC handle Structure definition
*/
typedef struct __TSC_HandleTypeDef
{
TSC_TypeDef *Instance; /*!< Register base address */
TSC_InitTypeDef Init; /*!< Initialization parameters */
__IO HAL_TSC_StateTypeDef State; /*!< Peripheral state */
HAL_LockTypeDef Lock; /*!< Lock feature */
__IO uint32_t ErrorCode; /*!< I2C Error code */
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
void (* ConvCpltCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Conversion complete callback */
void (* ErrorCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Error callback */
void (* MspInitCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Msp Init callback */
void (* MspDeInitCallback)(struct __TSC_HandleTypeDef *htsc); /*!< TSC Msp DeInit callback */
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
} TSC_HandleTypeDef;
/**
* @brief TSC Group Index Structure definition
*/
typedef enum
{
TSC_GROUP1_IDX = 0x00UL,
TSC_GROUP2_IDX,
TSC_GROUP3_IDX,
TSC_GROUP4_IDX,
#if defined(TSC_IOCCR_G5_IO1)
TSC_GROUP5_IDX,
#endif
#if defined(TSC_IOCCR_G6_IO1)
TSC_GROUP6_IDX,
#endif
#if defined(TSC_IOCCR_G7_IO1)
TSC_GROUP7_IDX,
#endif
#if defined(TSC_IOCCR_G8_IO1)
TSC_GROUP8_IDX,
#endif
TSC_NB_OF_GROUPS
}TSC_GroupIndexTypeDef;
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
/**
* @brief HAL TSC Callback ID enumeration definition
*/
typedef enum
{
HAL_TSC_CONV_COMPLETE_CB_ID = 0x00UL, /*!< TSC Conversion completed callback ID */
HAL_TSC_ERROR_CB_ID = 0x01UL, /*!< TSC Error callback ID */
HAL_TSC_MSPINIT_CB_ID = 0x02UL, /*!< TSC Msp Init callback ID */
HAL_TSC_MSPDEINIT_CB_ID = 0x03UL /*!< TSC Msp DeInit callback ID */
} HAL_TSC_CallbackIDTypeDef;
/**
* @brief HAL TSC Callback pointer definition
*/
typedef void (*pTSC_CallbackTypeDef)(TSC_HandleTypeDef *htsc); /*!< pointer to an TSC callback function */
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup TSC_Exported_Constants TSC Exported Constants
* @{
*/
/** @defgroup TSC_Error_Code_definition TSC Error Code definition
* @brief TSC Error Code definition
* @{
*/
#define HAL_TSC_ERROR_NONE 0x00000000UL /*!< No error */
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
#define HAL_TSC_ERROR_INVALID_CALLBACK 0x00000001UL /*!< Invalid Callback error */
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup TSC_CTPulseHL_Config CTPulse High Length
* @{
*/
#define TSC_CTPH_1CYCLE 0x00000000UL /*!< Charge transfer pulse high during 1 cycle (PGCLK) */
#define TSC_CTPH_2CYCLES TSC_CR_CTPH_0 /*!< Charge transfer pulse high during 2 cycles (PGCLK) */
#define TSC_CTPH_3CYCLES TSC_CR_CTPH_1 /*!< Charge transfer pulse high during 3 cycles (PGCLK) */
#define TSC_CTPH_4CYCLES (TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 4 cycles (PGCLK) */
#define TSC_CTPH_5CYCLES TSC_CR_CTPH_2 /*!< Charge transfer pulse high during 5 cycles (PGCLK) */
#define TSC_CTPH_6CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 6 cycles (PGCLK) */
#define TSC_CTPH_7CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 7 cycles (PGCLK) */
#define TSC_CTPH_8CYCLES (TSC_CR_CTPH_2 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 8 cycles (PGCLK) */
#define TSC_CTPH_9CYCLES TSC_CR_CTPH_3 /*!< Charge transfer pulse high during 9 cycles (PGCLK) */
#define TSC_CTPH_10CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 10 cycles (PGCLK) */
#define TSC_CTPH_11CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 11 cycles (PGCLK) */
#define TSC_CTPH_12CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 12 cycles (PGCLK) */
#define TSC_CTPH_13CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2) /*!< Charge transfer pulse high during 13 cycles (PGCLK) */
#define TSC_CTPH_14CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 14 cycles (PGCLK) */
#define TSC_CTPH_15CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_1) /*!< Charge transfer pulse high during 15 cycles (PGCLK) */
#define TSC_CTPH_16CYCLES (TSC_CR_CTPH_3 | TSC_CR_CTPH_2 | TSC_CR_CTPH_1 | TSC_CR_CTPH_0) /*!< Charge transfer pulse high during 16 cycles (PGCLK) */
/**
* @}
*/
/** @defgroup TSC_CTPulseLL_Config CTPulse Low Length
* @{
*/
#define TSC_CTPL_1CYCLE 0x00000000UL /*!< Charge transfer pulse low during 1 cycle (PGCLK) */
#define TSC_CTPL_2CYCLES TSC_CR_CTPL_0 /*!< Charge transfer pulse low during 2 cycles (PGCLK) */
#define TSC_CTPL_3CYCLES TSC_CR_CTPL_1 /*!< Charge transfer pulse low during 3 cycles (PGCLK) */
#define TSC_CTPL_4CYCLES (TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 4 cycles (PGCLK) */
#define TSC_CTPL_5CYCLES TSC_CR_CTPL_2 /*!< Charge transfer pulse low during 5 cycles (PGCLK) */
#define TSC_CTPL_6CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 6 cycles (PGCLK) */
#define TSC_CTPL_7CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 7 cycles (PGCLK) */
#define TSC_CTPL_8CYCLES (TSC_CR_CTPL_2 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 8 cycles (PGCLK) */
#define TSC_CTPL_9CYCLES TSC_CR_CTPL_3 /*!< Charge transfer pulse low during 9 cycles (PGCLK) */
#define TSC_CTPL_10CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 10 cycles (PGCLK) */
#define TSC_CTPL_11CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 11 cycles (PGCLK) */
#define TSC_CTPL_12CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 12 cycles (PGCLK) */
#define TSC_CTPL_13CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2) /*!< Charge transfer pulse low during 13 cycles (PGCLK) */
#define TSC_CTPL_14CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 14 cycles (PGCLK) */
#define TSC_CTPL_15CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_1) /*!< Charge transfer pulse low during 15 cycles (PGCLK) */
#define TSC_CTPL_16CYCLES (TSC_CR_CTPL_3 | TSC_CR_CTPL_2 | TSC_CR_CTPL_1 | TSC_CR_CTPL_0) /*!< Charge transfer pulse low during 16 cycles (PGCLK) */
/**
* @}
*/
/** @defgroup TSC_SpreadSpec_Prescaler Spread Spectrum Prescaler
* @{
*/
#define TSC_SS_PRESC_DIV1 0x00000000UL /*!< Spread Spectrum Prescaler Div1 */
#define TSC_SS_PRESC_DIV2 TSC_CR_SSPSC /*!< Spread Spectrum Prescaler Div2 */
/**
* @}
*/
/** @defgroup TSC_PulseGenerator_Prescaler Pulse Generator Prescaler
* @{
*/
#define TSC_PG_PRESC_DIV1 0x00000000UL /*!< Pulse Generator HCLK Div1 */
#define TSC_PG_PRESC_DIV2 TSC_CR_PGPSC_0 /*!< Pulse Generator HCLK Div2 */
#define TSC_PG_PRESC_DIV4 TSC_CR_PGPSC_1 /*!< Pulse Generator HCLK Div4 */
#define TSC_PG_PRESC_DIV8 (TSC_CR_PGPSC_1 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div8 */
#define TSC_PG_PRESC_DIV16 TSC_CR_PGPSC_2 /*!< Pulse Generator HCLK Div16 */
#define TSC_PG_PRESC_DIV32 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div32 */
#define TSC_PG_PRESC_DIV64 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_1) /*!< Pulse Generator HCLK Div64 */
#define TSC_PG_PRESC_DIV128 (TSC_CR_PGPSC_2 | TSC_CR_PGPSC_1 | TSC_CR_PGPSC_0) /*!< Pulse Generator HCLK Div128 */
/**
* @}
*/
/** @defgroup TSC_MaxCount_Value Max Count Value
* @{
*/
#define TSC_MCV_255 0x00000000UL /*!< 255 maximum number of charge transfer pulses */
#define TSC_MCV_511 TSC_CR_MCV_0 /*!< 511 maximum number of charge transfer pulses */
#define TSC_MCV_1023 TSC_CR_MCV_1 /*!< 1023 maximum number of charge transfer pulses */
#define TSC_MCV_2047 (TSC_CR_MCV_1 | TSC_CR_MCV_0) /*!< 2047 maximum number of charge transfer pulses */
#define TSC_MCV_4095 TSC_CR_MCV_2 /*!< 4095 maximum number of charge transfer pulses */
#define TSC_MCV_8191 (TSC_CR_MCV_2 | TSC_CR_MCV_0) /*!< 8191 maximum number of charge transfer pulses */
#define TSC_MCV_16383 (TSC_CR_MCV_2 | TSC_CR_MCV_1) /*!< 16383 maximum number of charge transfer pulses */
/**
* @}
*/
/** @defgroup TSC_IO_Default_Mode IO Default Mode
* @{
*/
#define TSC_IODEF_OUT_PP_LOW 0x00000000UL /*!< I/Os are forced to output push-pull low */
#define TSC_IODEF_IN_FLOAT TSC_CR_IODEF /*!< I/Os are in input floating */
/**
* @}
*/
/** @defgroup TSC_Synchro_Pin_Polarity Synchro Pin Polarity
* @{
*/
#define TSC_SYNC_POLARITY_FALLING 0x00000000UL /*!< Falling edge only */
#define TSC_SYNC_POLARITY_RISING TSC_CR_SYNCPOL /*!< Rising edge and high level */
/**
* @}
*/
/** @defgroup TSC_Acquisition_Mode Acquisition Mode
* @{
*/
#define TSC_ACQ_MODE_NORMAL 0x00000000UL /*!< Normal acquisition mode (acquisition starts as soon as START bit is set) */
#define TSC_ACQ_MODE_SYNCHRO TSC_CR_AM /*!< Synchronized acquisition mode (acquisition starts if START bit is set and when the selected signal is detected on the SYNC input pin) */
/**
* @}
*/
/** @defgroup TSC_interrupts_definition Interrupts definition
* @{
*/
#define TSC_IT_EOA TSC_IER_EOAIE /*!< End of acquisition interrupt enable */
#define TSC_IT_MCE TSC_IER_MCEIE /*!< Max count error interrupt enable */
/**
* @}
*/
/** @defgroup TSC_flags_definition Flags definition
* @{
*/
#define TSC_FLAG_EOA TSC_ISR_EOAF /*!< End of acquisition flag */
#define TSC_FLAG_MCE TSC_ISR_MCEF /*!< Max count error flag */
/**
* @}
*/
/** @defgroup TSC_Group_definition Group definition
* @{
*/
#define TSC_GROUP1 (uint32_t)(0x1UL << TSC_GROUP1_IDX)
#define TSC_GROUP2 (uint32_t)(0x1UL << TSC_GROUP2_IDX)
#define TSC_GROUP3 (uint32_t)(0x1UL << TSC_GROUP3_IDX)
#define TSC_GROUP4 (uint32_t)(0x1UL << TSC_GROUP4_IDX)
#if defined(TSC_IOCCR_G5_IO1)
#define TSC_GROUP5 (uint32_t)(0x1UL << TSC_GROUP5_IDX)
#endif
#if defined(TSC_IOCCR_G6_IO1)
#define TSC_GROUP6 (uint32_t)(0x1UL << TSC_GROUP6_IDX)
#endif
#if defined(TSC_IOCCR_G7_IO1)
#define TSC_GROUP7 (uint32_t)(0x1UL << TSC_GROUP7_IDX)
#endif
#if defined(TSC_IOCCR_G8_IO1)
#define TSC_GROUP8 (uint32_t)(0x1UL << TSC_GROUP8_IDX)
#endif
#define TSC_GROUPX_NOT_SUPPORTED 0xFF000000UL /*!< TSC GroupX not supported */
#define TSC_GROUP1_IO1 TSC_IOCCR_G1_IO1 /*!< TSC Group1 IO1 */
#define TSC_GROUP1_IO2 TSC_IOCCR_G1_IO2 /*!< TSC Group1 IO2 */
#define TSC_GROUP1_IO3 TSC_IOCCR_G1_IO3 /*!< TSC Group1 IO3 */
#define TSC_GROUP1_IO4 TSC_IOCCR_G1_IO4 /*!< TSC Group1 IO4 */
#define TSC_GROUP2_IO1 TSC_IOCCR_G2_IO1 /*!< TSC Group2 IO1 */
#define TSC_GROUP2_IO2 TSC_IOCCR_G2_IO2 /*!< TSC Group2 IO2 */
#define TSC_GROUP2_IO3 TSC_IOCCR_G2_IO3 /*!< TSC Group2 IO3 */
#define TSC_GROUP2_IO4 TSC_IOCCR_G2_IO4 /*!< TSC Group2 IO4 */
#define TSC_GROUP3_IO1 TSC_IOCCR_G3_IO1 /*!< TSC Group3 IO1 */
#define TSC_GROUP3_IO2 TSC_IOCCR_G3_IO2 /*!< TSC Group3 IO2 */
#define TSC_GROUP3_IO3 TSC_IOCCR_G3_IO3 /*!< TSC Group3 IO3 */
#define TSC_GROUP3_IO4 TSC_IOCCR_G3_IO4 /*!< TSC Group3 IO4 */
#define TSC_GROUP4_IO1 TSC_IOCCR_G4_IO1 /*!< TSC Group4 IO1 */
#define TSC_GROUP4_IO2 TSC_IOCCR_G4_IO2 /*!< TSC Group4 IO2 */
#define TSC_GROUP4_IO3 TSC_IOCCR_G4_IO3 /*!< TSC Group4 IO3 */
#define TSC_GROUP4_IO4 TSC_IOCCR_G4_IO4 /*!< TSC Group4 IO4 */
#if defined(TSC_IOCCR_G5_IO1)
#define TSC_GROUP5_IO1 TSC_IOCCR_G5_IO1 /*!< TSC Group5 IO1 */
#define TSC_GROUP5_IO2 TSC_IOCCR_G5_IO2 /*!< TSC Group5 IO2 */
#define TSC_GROUP5_IO3 TSC_IOCCR_G5_IO3 /*!< TSC Group5 IO3 */
#define TSC_GROUP5_IO4 TSC_IOCCR_G5_IO4 /*!< TSC Group5 IO4 */
#else
#define TSC_GROUP5_IO1 (uint32_t)(0x00000010UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group5 IO1 not supported */
#define TSC_GROUP5_IO2 TSC_GROUP5_IO1 /*!< TSC Group5 IO2 not supported */
#define TSC_GROUP5_IO3 TSC_GROUP5_IO1 /*!< TSC Group5 IO3 not supported */
#define TSC_GROUP5_IO4 TSC_GROUP5_IO1 /*!< TSC Group5 IO4 not supported */
#endif
#if defined(TSC_IOCCR_G6_IO1)
#define TSC_GROUP6_IO1 TSC_IOCCR_G6_IO1 /*!< TSC Group6 IO1 */
#define TSC_GROUP6_IO2 TSC_IOCCR_G6_IO2 /*!< TSC Group6 IO2 */
#define TSC_GROUP6_IO3 TSC_IOCCR_G6_IO3 /*!< TSC Group6 IO3 */
#define TSC_GROUP6_IO4 TSC_IOCCR_G6_IO4 /*!< TSC Group6 IO4 */
#else
#define TSC_GROUP6_IO1 (uint32_t)(0x00000020UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group6 IO1 not supported */
#define TSC_GROUP6_IO2 TSC_GROUP6_IO1 /*!< TSC Group6 IO2 not supported */
#define TSC_GROUP6_IO3 TSC_GROUP6_IO1 /*!< TSC Group6 IO3 not supported */
#define TSC_GROUP6_IO4 TSC_GROUP6_IO1 /*!< TSC Group6 IO4 not supported */
#endif
#if defined(TSC_IOCCR_G7_IO1)
#define TSC_GROUP7_IO1 TSC_IOCCR_G7_IO1 /*!< TSC Group7 IO1 */
#define TSC_GROUP7_IO2 TSC_IOCCR_G7_IO2 /*!< TSC Group7 IO2 */
#define TSC_GROUP7_IO3 TSC_IOCCR_G7_IO3 /*!< TSC Group7 IO3 */
#define TSC_GROUP7_IO4 TSC_IOCCR_G7_IO4 /*!< TSC Group7 IO4 */
#else
#define TSC_GROUP7_IO1 (uint32_t)(0x00000040UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group7 IO1 not supported */
#define TSC_GROUP7_IO2 TSC_GROUP7_IO1 /*!< TSC Group7 IO2 not supported */
#define TSC_GROUP7_IO3 TSC_GROUP7_IO1 /*!< TSC Group7 IO3 not supported */
#define TSC_GROUP7_IO4 TSC_GROUP7_IO1 /*!< TSC Group7 IO4 not supported */
#endif
#if defined(TSC_IOCCR_G8_IO1)
#define TSC_GROUP8_IO1 TSC_IOCCR_G8_IO1 /*!< TSC Group8 IO1 */
#define TSC_GROUP8_IO2 TSC_IOCCR_G8_IO2 /*!< TSC Group8 IO2 */
#define TSC_GROUP8_IO3 TSC_IOCCR_G8_IO3 /*!< TSC Group8 IO3 */
#define TSC_GROUP8_IO4 TSC_IOCCR_G8_IO4 /*!< TSC Group8 IO4 */
#else
#define TSC_GROUP8_IO1 (uint32_t)(0x00000080UL | TSC_GROUPX_NOT_SUPPORTED) /*!< TSC Group8 IO1 not supported */
#define TSC_GROUP8_IO2 TSC_GROUP8_IO1 /*!< TSC Group8 IO2 not supported */
#define TSC_GROUP8_IO3 TSC_GROUP8_IO1 /*!< TSC Group8 IO3 not supported */
#define TSC_GROUP8_IO4 TSC_GROUP8_IO1 /*!< TSC Group8 IO4 not supported */
#endif
/**
* @}
*/
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup TSC_Exported_Macros TSC Exported Macros
* @{
*/
/** @brief Reset TSC handle state.
* @param __HANDLE__ TSC handle
* @retval None
*/
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
#define __HAL_TSC_RESET_HANDLE_STATE(__HANDLE__) do{ \
(__HANDLE__)->State = HAL_TSC_STATE_RESET; \
(__HANDLE__)->MspInitCallback = NULL; \
(__HANDLE__)->MspDeInitCallback = NULL; \
} while(0)
#else
#define __HAL_TSC_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_TSC_STATE_RESET)
#endif
/**
* @brief Enable the TSC peripheral.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_TSCE)
/**
* @brief Disable the TSC peripheral.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_TSCE))
/**
* @brief Start acquisition.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_START_ACQ(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_START)
/**
* @brief Stop acquisition.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_STOP_ACQ(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_START))
/**
* @brief Set IO default mode to output push-pull low.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_IODEF_OUTPPLOW(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_IODEF))
/**
* @brief Set IO default mode to input floating.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_IODEF_INFLOAT(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_IODEF)
/**
* @brief Set synchronization polarity to falling edge.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_SYNC_POL_FALL(__HANDLE__) ((__HANDLE__)->Instance->CR &= (uint32_t)(~TSC_CR_SYNCPOL))
/**
* @brief Set synchronization polarity to rising edge and high level.
* @param __HANDLE__ TSC handle
* @retval None
*/
#define __HAL_TSC_SET_SYNC_POL_RISE_HIGH(__HANDLE__) ((__HANDLE__)->Instance->CR |= TSC_CR_SYNCPOL)
/**
* @brief Enable TSC interrupt.
* @param __HANDLE__ TSC handle
* @param __INTERRUPT__ TSC interrupt
* @retval None
*/
#define __HAL_TSC_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER |= (__INTERRUPT__))
/**
* @brief Disable TSC interrupt.
* @param __HANDLE__ TSC handle
* @param __INTERRUPT__ TSC interrupt
* @retval None
*/
#define __HAL_TSC_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER &= (uint32_t)(~(__INTERRUPT__)))
/** @brief Check whether the specified TSC interrupt source is enabled or not.
* @param __HANDLE__ TSC Handle
* @param __INTERRUPT__ TSC interrupt
* @retval SET or RESET
*/
#define __HAL_TSC_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->IER & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET)
/**
* @brief Check whether the specified TSC flag is set or not.
* @param __HANDLE__ TSC handle
* @param __FLAG__ TSC flag
* @retval SET or RESET
*/
#define __HAL_TSC_GET_FLAG(__HANDLE__, __FLAG__) ((((__HANDLE__)->Instance->ISR & (__FLAG__)) == (__FLAG__)) ? SET : RESET)
/**
* @brief Clear the TSC's pending flag.
* @param __HANDLE__ TSC handle
* @param __FLAG__ TSC flag
* @retval None
*/
#define __HAL_TSC_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))
/**
* @brief Enable schmitt trigger hysteresis on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_ENABLE_HYSTERESIS(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOHCR |= (__GX_IOY_MASK__))
/**
* @brief Disable schmitt trigger hysteresis on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_DISABLE_HYSTERESIS(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOHCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Open analog switch on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_OPEN_ANALOG_SWITCH(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOASCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Close analog switch on a group of IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_CLOSE_ANALOG_SWITCH(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOASCR |= (__GX_IOY_MASK__))
/**
* @brief Enable a group of IOs in channel mode.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_ENABLE_CHANNEL(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOCCR |= (__GX_IOY_MASK__))
/**
* @brief Disable a group of channel IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_DISABLE_CHANNEL(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOCCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Enable a group of IOs in sampling mode.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_ENABLE_SAMPLING(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOSCR |= (__GX_IOY_MASK__))
/**
* @brief Disable a group of sampling IOs.
* @param __HANDLE__ TSC handle
* @param __GX_IOY_MASK__ IOs mask
* @retval None
*/
#define __HAL_TSC_DISABLE_SAMPLING(__HANDLE__, __GX_IOY_MASK__) ((__HANDLE__)->Instance->IOSCR &= (uint32_t)(~(__GX_IOY_MASK__)))
/**
* @brief Enable acquisition groups.
* @param __HANDLE__ TSC handle
* @param __GX_MASK__ Groups mask
* @retval None
*/
#define __HAL_TSC_ENABLE_GROUP(__HANDLE__, __GX_MASK__) ((__HANDLE__)->Instance->IOGCSR |= (__GX_MASK__))
/**
* @brief Disable acquisition groups.
* @param __HANDLE__ TSC handle
* @param __GX_MASK__ Groups mask
* @retval None
*/
#define __HAL_TSC_DISABLE_GROUP(__HANDLE__, __GX_MASK__) ((__HANDLE__)->Instance->IOGCSR &= (uint32_t)(~(__GX_MASK__)))
/** @brief Gets acquisition group status.
* @param __HANDLE__ TSC Handle
* @param __GX_INDEX__ Group index
* @retval SET or RESET
*/
#define __HAL_TSC_GET_GROUP_STATUS(__HANDLE__, __GX_INDEX__) \
((((__HANDLE__)->Instance->IOGCSR & (uint32_t)(1UL << (((__GX_INDEX__) & (uint32_t)TSC_NB_OF_GROUPS) + 16UL))) == (uint32_t)(1UL << (((__GX_INDEX__) & (uint32_t)TSC_NB_OF_GROUPS) + 16UL))) ? TSC_GROUP_COMPLETED : TSC_GROUP_ONGOING)
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup TSC_Private_Macros TSC Private Macros
* @{
*/
#define IS_TSC_CTPH(__VALUE__) (((__VALUE__) == TSC_CTPH_1CYCLE) || \
((__VALUE__) == TSC_CTPH_2CYCLES) || \
((__VALUE__) == TSC_CTPH_3CYCLES) || \
((__VALUE__) == TSC_CTPH_4CYCLES) || \
((__VALUE__) == TSC_CTPH_5CYCLES) || \
((__VALUE__) == TSC_CTPH_6CYCLES) || \
((__VALUE__) == TSC_CTPH_7CYCLES) || \
((__VALUE__) == TSC_CTPH_8CYCLES) || \
((__VALUE__) == TSC_CTPH_9CYCLES) || \
((__VALUE__) == TSC_CTPH_10CYCLES) || \
((__VALUE__) == TSC_CTPH_11CYCLES) || \
((__VALUE__) == TSC_CTPH_12CYCLES) || \
((__VALUE__) == TSC_CTPH_13CYCLES) || \
((__VALUE__) == TSC_CTPH_14CYCLES) || \
((__VALUE__) == TSC_CTPH_15CYCLES) || \
((__VALUE__) == TSC_CTPH_16CYCLES))
#define IS_TSC_CTPL(__VALUE__) (((__VALUE__) == TSC_CTPL_1CYCLE) || \
((__VALUE__) == TSC_CTPL_2CYCLES) || \
((__VALUE__) == TSC_CTPL_3CYCLES) || \
((__VALUE__) == TSC_CTPL_4CYCLES) || \
((__VALUE__) == TSC_CTPL_5CYCLES) || \
((__VALUE__) == TSC_CTPL_6CYCLES) || \
((__VALUE__) == TSC_CTPL_7CYCLES) || \
((__VALUE__) == TSC_CTPL_8CYCLES) || \
((__VALUE__) == TSC_CTPL_9CYCLES) || \
((__VALUE__) == TSC_CTPL_10CYCLES) || \
((__VALUE__) == TSC_CTPL_11CYCLES) || \
((__VALUE__) == TSC_CTPL_12CYCLES) || \
((__VALUE__) == TSC_CTPL_13CYCLES) || \
((__VALUE__) == TSC_CTPL_14CYCLES) || \
((__VALUE__) == TSC_CTPL_15CYCLES) || \
((__VALUE__) == TSC_CTPL_16CYCLES))
#define IS_TSC_SS(__VALUE__) (((FunctionalState)(__VALUE__) == DISABLE) || ((FunctionalState)(__VALUE__) == ENABLE))
#define IS_TSC_SSD(__VALUE__) (((__VALUE__) == 0UL) || (((__VALUE__) > 0UL) && ((__VALUE__) < 128UL)))
#define IS_TSC_SS_PRESC(__VALUE__) (((__VALUE__) == TSC_SS_PRESC_DIV1) || ((__VALUE__) == TSC_SS_PRESC_DIV2))
#define IS_TSC_PG_PRESC(__VALUE__) (((__VALUE__) == TSC_PG_PRESC_DIV1) || \
((__VALUE__) == TSC_PG_PRESC_DIV2) || \
((__VALUE__) == TSC_PG_PRESC_DIV4) || \
((__VALUE__) == TSC_PG_PRESC_DIV8) || \
((__VALUE__) == TSC_PG_PRESC_DIV16) || \
((__VALUE__) == TSC_PG_PRESC_DIV32) || \
((__VALUE__) == TSC_PG_PRESC_DIV64) || \
((__VALUE__) == TSC_PG_PRESC_DIV128))
#define IS_TSC_MCV(__VALUE__) (((__VALUE__) == TSC_MCV_255) || \
((__VALUE__) == TSC_MCV_511) || \
((__VALUE__) == TSC_MCV_1023) || \
((__VALUE__) == TSC_MCV_2047) || \
((__VALUE__) == TSC_MCV_4095) || \
((__VALUE__) == TSC_MCV_8191) || \
((__VALUE__) == TSC_MCV_16383))
#define IS_TSC_IODEF(__VALUE__) (((__VALUE__) == TSC_IODEF_OUT_PP_LOW) || ((__VALUE__) == TSC_IODEF_IN_FLOAT))
#define IS_TSC_SYNC_POL(__VALUE__) (((__VALUE__) == TSC_SYNC_POLARITY_FALLING) || ((__VALUE__) == TSC_SYNC_POLARITY_RISING))
#define IS_TSC_ACQ_MODE(__VALUE__) (((__VALUE__) == TSC_ACQ_MODE_NORMAL) || ((__VALUE__) == TSC_ACQ_MODE_SYNCHRO))
#define IS_TSC_MCE_IT(__VALUE__) (((FunctionalState)(__VALUE__) == DISABLE) || ((FunctionalState)(__VALUE__) == ENABLE))
#define IS_TSC_GROUP_INDEX(__VALUE__) (((__VALUE__) == 0UL) || (((__VALUE__) > 0UL) && ((__VALUE__) < (uint32_t)TSC_NB_OF_GROUPS)))
#define IS_TSC_GROUP(__VALUE__) ((((__VALUE__) & TSC_GROUPX_NOT_SUPPORTED) != TSC_GROUPX_NOT_SUPPORTED) && \
((((__VALUE__) & TSC_GROUP1_IO1) == TSC_GROUP1_IO1) ||\
(((__VALUE__) & TSC_GROUP1_IO2) == TSC_GROUP1_IO2) ||\
(((__VALUE__) & TSC_GROUP1_IO3) == TSC_GROUP1_IO3) ||\
(((__VALUE__) & TSC_GROUP1_IO4) == TSC_GROUP1_IO4) ||\
(((__VALUE__) & TSC_GROUP2_IO1) == TSC_GROUP2_IO1) ||\
(((__VALUE__) & TSC_GROUP2_IO2) == TSC_GROUP2_IO2) ||\
(((__VALUE__) & TSC_GROUP2_IO3) == TSC_GROUP2_IO3) ||\
(((__VALUE__) & TSC_GROUP2_IO4) == TSC_GROUP2_IO4) ||\
(((__VALUE__) & TSC_GROUP3_IO1) == TSC_GROUP3_IO1) ||\
(((__VALUE__) & TSC_GROUP3_IO2) == TSC_GROUP3_IO2) ||\
(((__VALUE__) & TSC_GROUP3_IO3) == TSC_GROUP3_IO3) ||\
(((__VALUE__) & TSC_GROUP3_IO4) == TSC_GROUP3_IO4) ||\
(((__VALUE__) & TSC_GROUP4_IO1) == TSC_GROUP4_IO1) ||\
(((__VALUE__) & TSC_GROUP4_IO2) == TSC_GROUP4_IO2) ||\
(((__VALUE__) & TSC_GROUP4_IO3) == TSC_GROUP4_IO3) ||\
(((__VALUE__) & TSC_GROUP4_IO4) == TSC_GROUP4_IO4) ||\
(((__VALUE__) & TSC_GROUP5_IO1) == TSC_GROUP5_IO1) ||\
(((__VALUE__) & TSC_GROUP5_IO2) == TSC_GROUP5_IO2) ||\
(((__VALUE__) & TSC_GROUP5_IO3) == TSC_GROUP5_IO3) ||\
(((__VALUE__) & TSC_GROUP5_IO4) == TSC_GROUP5_IO4) ||\
(((__VALUE__) & TSC_GROUP6_IO1) == TSC_GROUP6_IO1) ||\
(((__VALUE__) & TSC_GROUP6_IO2) == TSC_GROUP6_IO2) ||\
(((__VALUE__) & TSC_GROUP6_IO3) == TSC_GROUP6_IO3) ||\
(((__VALUE__) & TSC_GROUP6_IO4) == TSC_GROUP6_IO4) ||\
(((__VALUE__) & TSC_GROUP7_IO1) == TSC_GROUP7_IO1) ||\
(((__VALUE__) & TSC_GROUP7_IO2) == TSC_GROUP7_IO2) ||\
(((__VALUE__) & TSC_GROUP7_IO3) == TSC_GROUP7_IO3) ||\
(((__VALUE__) & TSC_GROUP7_IO4) == TSC_GROUP7_IO4) ||\
(((__VALUE__) & TSC_GROUP8_IO1) == TSC_GROUP8_IO1) ||\
(((__VALUE__) & TSC_GROUP8_IO2) == TSC_GROUP8_IO2) ||\
(((__VALUE__) & TSC_GROUP8_IO3) == TSC_GROUP8_IO3) ||\
(((__VALUE__) & TSC_GROUP8_IO4) == TSC_GROUP8_IO4)))
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup TSC_Exported_Functions
* @{
*/
/** @addtogroup TSC_Exported_Functions_Group1 Initialization and de-initialization functions
* @{
*/
/* Initialization and de-initialization functions *****************************/
HAL_StatusTypeDef HAL_TSC_Init(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_DeInit(TSC_HandleTypeDef *htsc);
void HAL_TSC_MspInit(TSC_HandleTypeDef *htsc);
void HAL_TSC_MspDeInit(TSC_HandleTypeDef *htsc);
/* Callbacks Register/UnRegister functions ***********************************/
#if (USE_HAL_TSC_REGISTER_CALLBACKS == 1)
HAL_StatusTypeDef HAL_TSC_RegisterCallback(TSC_HandleTypeDef *htsc, HAL_TSC_CallbackIDTypeDef CallbackID, pTSC_CallbackTypeDef pCallback);
HAL_StatusTypeDef HAL_TSC_UnRegisterCallback(TSC_HandleTypeDef *htsc, HAL_TSC_CallbackIDTypeDef CallbackID);
#endif /* USE_HAL_TSC_REGISTER_CALLBACKS */
/**
* @}
*/
/** @addtogroup TSC_Exported_Functions_Group2 Input and Output operation functions
* @{
*/
/* IO operation functions *****************************************************/
HAL_StatusTypeDef HAL_TSC_Start(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_Start_IT(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_Stop(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_Stop_IT(TSC_HandleTypeDef *htsc);
HAL_StatusTypeDef HAL_TSC_PollForAcquisition(TSC_HandleTypeDef *htsc);
TSC_GroupStatusTypeDef HAL_TSC_GroupGetStatus(TSC_HandleTypeDef *htsc, uint32_t gx_index);
uint32_t HAL_TSC_GroupGetValue(TSC_HandleTypeDef *htsc, uint32_t gx_index);
/**
* @}
*/
/** @addtogroup TSC_Exported_Functions_Group3 Peripheral Control functions
* @{
*/
/* Peripheral Control functions ***********************************************/
HAL_StatusTypeDef HAL_TSC_IOConfig(TSC_HandleTypeDef *htsc, TSC_IOConfigTypeDef *config);
HAL_StatusTypeDef HAL_TSC_IODischarge(TSC_HandleTypeDef *htsc, uint32_t choice);
/**
* @}
*/
/** @addtogroup TSC_Exported_Functions_Group4 Peripheral State and Errors functions
* @{
*/
/* Peripheral State and Error functions ***************************************/
HAL_TSC_StateTypeDef HAL_TSC_GetState(TSC_HandleTypeDef *htsc);
/**
* @}
*/
/** @addtogroup TSC_IRQ_Handler_and_Callbacks IRQ Handler and Callbacks
* @{
*/
/******* TSC IRQHandler and Callbacks used in Interrupt mode */
void HAL_TSC_IRQHandler(TSC_HandleTypeDef *htsc);
void HAL_TSC_ConvCpltCallback(TSC_HandleTypeDef *htsc);
void HAL_TSC_ErrorCallback(TSC_HandleTypeDef *htsc);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* STM32L4xx_HAL_TSC_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -1,290 +0,0 @@
/**
******************************************************************************
* @file stm32l4xx_ll_exti.c
* @author MCD Application Team
* @brief EXTI LL module driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_ll_exti.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif
/** @addtogroup STM32L4xx_LL_Driver
* @{
*/
#if defined (EXTI)
/** @defgroup EXTI_LL EXTI
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup EXTI_LL_Private_Macros
* @{
*/
#define IS_LL_EXTI_LINE_0_31(__VALUE__) (((__VALUE__) & ~LL_EXTI_LINE_ALL_0_31) == 0x00000000U)
#define IS_LL_EXTI_LINE_32_63(__VALUE__) (((__VALUE__) & ~LL_EXTI_LINE_ALL_32_63) == 0x00000000U)
#define IS_LL_EXTI_MODE(__VALUE__) (((__VALUE__) == LL_EXTI_MODE_IT) \
|| ((__VALUE__) == LL_EXTI_MODE_EVENT) \
|| ((__VALUE__) == LL_EXTI_MODE_IT_EVENT))
#define IS_LL_EXTI_TRIGGER(__VALUE__) (((__VALUE__) == LL_EXTI_TRIGGER_NONE) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_RISING) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_FALLING) \
|| ((__VALUE__) == LL_EXTI_TRIGGER_RISING_FALLING))
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup EXTI_LL_Exported_Functions
* @{
*/
/** @addtogroup EXTI_LL_EF_Init
* @{
*/
/**
* @brief De-initialize the EXTI registers to their default reset values.
* @retval An ErrorStatus enumeration value:
* - 0x00: EXTI registers are de-initialized
*/
uint32_t LL_EXTI_DeInit(void)
{
/* Interrupt mask register set to default reset values */
LL_EXTI_WriteReg(IMR1, 0xFF820000U);
/* Event mask register set to default reset values */
LL_EXTI_WriteReg(EMR1, 0x00000000U);
/* Rising Trigger selection register set to default reset values */
LL_EXTI_WriteReg(RTSR1, 0x00000000U);
/* Falling Trigger selection register set to default reset values */
LL_EXTI_WriteReg(FTSR1, 0x00000000U);
/* Software interrupt event register set to default reset values */
LL_EXTI_WriteReg(SWIER1, 0x00000000U);
/* Pending register clear */
LL_EXTI_WriteReg(PR1, 0x007DFFFFU);
/* Interrupt mask register 2 set to default reset values */
#if defined(LL_EXTI_LINE_40)
LL_EXTI_WriteReg(IMR2, 0x00000187U);
#else
LL_EXTI_WriteReg(IMR2, 0x00000087U);
#endif
/* Event mask register 2 set to default reset values */
LL_EXTI_WriteReg(EMR2, 0x00000000U);
/* Rising Trigger selection register 2 set to default reset values */
LL_EXTI_WriteReg(RTSR2, 0x00000000U);
/* Falling Trigger selection register 2 set to default reset values */
LL_EXTI_WriteReg(FTSR2, 0x00000000U);
/* Software interrupt event register 2 set to default reset values */
LL_EXTI_WriteReg(SWIER2, 0x00000000U);
/* Pending register 2 clear */
LL_EXTI_WriteReg(PR2, 0x00000078U);
return 0x00u;
}
/**
* @brief Initialize the EXTI registers according to the specified parameters in EXTI_InitStruct.
* @param EXTI_InitStruct pointer to a @ref LL_EXTI_InitTypeDef structure.
* @retval An ErrorStatus enumeration value:
* - 0x00: EXTI registers are initialized
* - any other calue : wrong configuration
*/
uint32_t LL_EXTI_Init(LL_EXTI_InitTypeDef *EXTI_InitStruct)
{
uint32_t status = 0x00u;
/* Check the parameters */
assert_param(IS_LL_EXTI_LINE_0_31(EXTI_InitStruct->Line_0_31));
assert_param(IS_LL_EXTI_LINE_32_63(EXTI_InitStruct->Line_32_63));
assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->LineCommand));
assert_param(IS_LL_EXTI_MODE(EXTI_InitStruct->Mode));
/* ENABLE LineCommand */
if (EXTI_InitStruct->LineCommand != DISABLE)
{
assert_param(IS_LL_EXTI_TRIGGER(EXTI_InitStruct->Trigger));
/* Configure EXTI Lines in range from 0 to 31 */
if (EXTI_InitStruct->Line_0_31 != LL_EXTI_LINE_NONE)
{
switch (EXTI_InitStruct->Mode)
{
case LL_EXTI_MODE_IT:
/* First Disable Event on provided Lines */
LL_EXTI_DisableEvent_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableIT_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_MODE_EVENT:
/* First Disable IT on provided Lines */
LL_EXTI_DisableIT_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Event on provided Lines */
LL_EXTI_EnableEvent_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_MODE_IT_EVENT:
/* Directly Enable IT & Event on provided Lines */
LL_EXTI_EnableIT_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_EnableEvent_0_31(EXTI_InitStruct->Line_0_31);
break;
default:
status = 0x01u;
break;
}
if (EXTI_InitStruct->Trigger != LL_EXTI_TRIGGER_NONE)
{
switch (EXTI_InitStruct->Trigger)
{
case LL_EXTI_TRIGGER_RISING:
/* First Disable Falling Trigger on provided Lines */
LL_EXTI_DisableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Rising Trigger on provided Lines */
LL_EXTI_EnableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_TRIGGER_FALLING:
/* First Disable Rising Trigger on provided Lines */
LL_EXTI_DisableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
/* Then Enable Falling Trigger on provided Lines */
LL_EXTI_EnableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
case LL_EXTI_TRIGGER_RISING_FALLING:
LL_EXTI_EnableRisingTrig_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_EnableFallingTrig_0_31(EXTI_InitStruct->Line_0_31);
break;
default:
status |= 0x02u;
break;
}
}
}
/* Configure EXTI Lines in range from 32 to 63 */
if (EXTI_InitStruct->Line_32_63 != LL_EXTI_LINE_NONE)
{
switch (EXTI_InitStruct->Mode)
{
case LL_EXTI_MODE_IT:
/* First Disable Event on provided Lines */
LL_EXTI_DisableEvent_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableIT_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_MODE_EVENT:
/* First Disable IT on provided Lines */
LL_EXTI_DisableIT_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable Event on provided Lines */
LL_EXTI_EnableEvent_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_MODE_IT_EVENT:
/* Directly Enable IT & Event on provided Lines */
LL_EXTI_EnableIT_32_63(EXTI_InitStruct->Line_32_63);
LL_EXTI_EnableEvent_32_63(EXTI_InitStruct->Line_32_63);
break;
default:
status |= 0x04u;
break;
}
if (EXTI_InitStruct->Trigger != LL_EXTI_TRIGGER_NONE)
{
switch (EXTI_InitStruct->Trigger)
{
case LL_EXTI_TRIGGER_RISING:
/* First Disable Falling Trigger on provided Lines */
LL_EXTI_DisableFallingTrig_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable IT on provided Lines */
LL_EXTI_EnableRisingTrig_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_TRIGGER_FALLING:
/* First Disable Rising Trigger on provided Lines */
LL_EXTI_DisableRisingTrig_32_63(EXTI_InitStruct->Line_32_63);
/* Then Enable Falling Trigger on provided Lines */
LL_EXTI_EnableFallingTrig_32_63(EXTI_InitStruct->Line_32_63);
break;
case LL_EXTI_TRIGGER_RISING_FALLING:
LL_EXTI_EnableRisingTrig_32_63(EXTI_InitStruct->Line_32_63);
LL_EXTI_EnableFallingTrig_32_63(EXTI_InitStruct->Line_32_63);
break;
default:
status = ERROR;
break;
}
}
}
}
/* DISABLE LineCommand */
else
{
/* De-configure EXTI Lines in range from 0 to 31 */
LL_EXTI_DisableIT_0_31(EXTI_InitStruct->Line_0_31);
LL_EXTI_DisableEvent_0_31(EXTI_InitStruct->Line_0_31);
/* De-configure EXTI Lines in range from 32 to 63 */
LL_EXTI_DisableIT_32_63(EXTI_InitStruct->Line_32_63);
LL_EXTI_DisableEvent_32_63(EXTI_InitStruct->Line_32_63);
}
return status;
}
/**
* @brief Set each @ref LL_EXTI_InitTypeDef field to default value.
* @param EXTI_InitStruct Pointer to a @ref LL_EXTI_InitTypeDef structure.
* @retval None
*/
void LL_EXTI_StructInit(LL_EXTI_InitTypeDef *EXTI_InitStruct)
{
EXTI_InitStruct->Line_0_31 = LL_EXTI_LINE_NONE;
EXTI_InitStruct->Line_32_63 = LL_EXTI_LINE_NONE;
EXTI_InitStruct->LineCommand = DISABLE;
EXTI_InitStruct->Mode = LL_EXTI_MODE_IT;
EXTI_InitStruct->Trigger = LL_EXTI_TRIGGER_FALLING;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (EXTI) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

View File

@ -1,307 +0,0 @@
/**
******************************************************************************
* @file stm32l4xx_ll_spi.c
* @author MCD Application Team
* @brief SPI LL module driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; 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****/

File diff suppressed because it is too large Load Diff

View File

@ -1,319 +0,0 @@
#include <stdint.h>
#include "usbd_ccid.h"
#include "usbd_ctlreq.h"
#include "usbd_conf.h"
#include "usbd_core.h"
#include "log.h"
static uint8_t USBD_CCID_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
static uint8_t USBD_CCID_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx);
static uint8_t USBD_CCID_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
static uint8_t USBD_CCID_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum);
static uint8_t USBD_CCID_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum);
static uint8_t USBD_CCID_EP0_RxReady (USBD_HandleTypeDef *pdev);
USBD_ClassTypeDef USBD_CCID =
{
USBD_CCID_Init,
USBD_CCID_DeInit,
USBD_CCID_Setup,
NULL, /* EP0_TxSent, */
USBD_CCID_EP0_RxReady,
USBD_CCID_DataIn,
USBD_CCID_DataOut,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static uint8_t ccidmsg_buf[CCID_DATA_PACKET_SIZE];
static uint8_t USBD_CCID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
uint8_t ret = 0U;
USBD_CCID_HandleTypeDef *hcdc;
//Y
USBD_LL_OpenEP(pdev, CCID_IN_EP, USBD_EP_TYPE_BULK,
CCID_DATA_PACKET_SIZE);
USBD_LL_OpenEP(pdev, CCID_OUT_EP, USBD_EP_TYPE_BULK,
CCID_DATA_PACKET_SIZE);
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 1U;
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 1U;
USBD_LL_OpenEP(pdev, CCID_CMD_EP, USBD_EP_TYPE_INTR, CCID_DATA_PACKET_SIZE);
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 1U;
// dump_pma_header("ccid.c");
static USBD_CCID_HandleTypeDef mem;
pdev->pClassData = &mem;
hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
// init transfer states
hcdc->TxState = 0U;
hcdc->RxState = 0U;
USBD_LL_PrepareReceive(&Solo_USBD_Device, CCID_OUT_EP, ccidmsg_buf,
CCID_DATA_PACKET_SIZE);
return ret;
}
static uint8_t USBD_CCID_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
uint8_t ret = 0U;
//N
USBD_LL_CloseEP(pdev, CCID_IN_EP);
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 0U;
USBD_LL_CloseEP(pdev, CCID_OUT_EP);
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 0U;
USBD_LL_CloseEP(pdev, CCID_CMD_EP);
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 0U;
/* DeInit physical Interface components */
if(pdev->pClassData != NULL)
{
pdev->pClassData = NULL;
}
return ret;
}
/**
* @brief USBD_CDC_Setup
* Handle the CDC specific requests
* @param pdev: instance
* @param req: usb requests
* @retval status
*/
static uint8_t USBD_CCID_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
uint8_t ifalt = 0U;
uint16_t status_info = 0U;
uint8_t ret = USBD_OK;
//N
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
if (req->wLength)
{
if (req->bmRequest & 0x80U)
{
USBD_CtlSendData (pdev, (uint8_t *)(void *)hcdc->data, req->wLength);
}
else
{
hcdc->CmdOpCode = req->bRequest;
hcdc->CmdLength = (uint8_t)req->wLength;
USBD_CtlPrepareRx (pdev, (uint8_t *)(void *)hcdc->data, req->wLength);
}
}
else
{
}
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
USBD_CtlSendData (pdev, (uint8_t *)(void *)&status_info, 2U);
}
else
{
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_GET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
USBD_CtlSendData (pdev, &ifalt, 1U);
}
else
{
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_SET_INTERFACE:
if (pdev->dev_state != USBD_STATE_CONFIGURED)
{
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_GET_DESCRIPTOR:
break;
default:
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
break;
}
break;
default:
USBD_CtlError (pdev, req);
ret = USBD_FAIL;
break;
}
return ret;
}
/**
* @brief USBD_CDC_DataIn
* Data sent on non-control IN endpoint
* @param pdev: device instance
* @param epnum: endpoint number
* @retval status
*/
static uint8_t USBD_CCID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USBD_OK;
}
static uint8_t USBD_CCID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*)pdev->pClassData;
hcdc->TxState = 0U;
return USBD_OK;
}
uint8_t USBD_CCID_TransmitPacket(uint8_t * msg, int len)
{
/* Update the packet total length */
Solo_USBD_Device.ep_in[CCID_IN_EP & 0xFU].total_length = len;
while (PCD_GET_EP_TX_STATUS(USB, CCID_IN_EP & 0x0f) == USB_EP_TX_VALID)
;
/* Transmit next packet */
USBD_LL_Transmit(&Solo_USBD_Device, CCID_IN_EP, msg,
len);
printf1(TAG_CCID,"<< ");
dump_hex1(TAG_CCID, msg, len);
return USBD_OK;
}
void ccid_send_status(CCID_HEADER * c, uint8_t status)
{
uint8_t msg[CCID_HEADER_SIZE];
memset(msg,0,sizeof(msg));
msg[0] = CCID_SLOT_STATUS_RES;
msg[6] = c->seq;
msg[7] = status;
USBD_CCID_TransmitPacket(msg, sizeof(msg));
}
void ccid_send_data_block(CCID_HEADER * c, uint8_t status)
{
uint8_t msg[CCID_HEADER_SIZE];
memset(msg,0,sizeof(msg));
msg[0] = CCID_DATA_BLOCK_RES;
msg[6] = c->seq;
msg[7] = status;
USBD_CCID_TransmitPacket(msg, sizeof(msg));
}
void handle_ccid(uint8_t * msg, int len)
{
CCID_HEADER * h = (CCID_HEADER *) msg;
switch(h->type)
{
case CCID_SLOT_STATUS:
ccid_send_status(h, CCID_STATUS_ON);
break;
case CCID_POWER_ON:
ccid_send_data_block(h, CCID_STATUS_ON);
break;
case CCID_POWER_OFF:
ccid_send_status(h, CCID_STATUS_OFF);
break;
default:
ccid_send_status(h, CCID_STATUS_ON);
break;
}
}
/**
* @brief USBD_CDC_DataOut
* Data received on non-control Out endpoint
* @param pdev: device instance
* @param epnum: endpoint number
* @retval status
*/
uint8_t usb_ccid_recieve_callback(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
/* Get the received data length */
hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
printf1(TAG_CCID, ">> ");
dump_hex1(TAG_CCID, ccidmsg_buf, hcdc->RxLength);
handle_ccid(ccidmsg_buf, hcdc->RxLength);
USBD_LL_PrepareReceive(&Solo_USBD_Device, CCID_OUT_EP, ccidmsg_buf,
CCID_DATA_PACKET_SIZE);
return USBD_OK;
}
/**
* @brief USBD_CDC_EP0_RxReady
* Handle EP0 Rx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_CCID_EP0_RxReady (USBD_HandleTypeDef *pdev)
{
return USBD_OK;
}

View File

@ -1,58 +0,0 @@
#ifndef _USBD_H_
#define _USBD_H_
#include "usbd_ioreq.h"
#define CCID_HEADER_SIZE 10
typedef struct
{
uint8_t type;
uint32_t len;
uint8_t slot;
uint8_t seq;
uint8_t rsvd;
uint16_t param;
} __attribute__((packed)) CCID_HEADER;
#define CCID_IN_EP 0x86U /* EP1 for data IN */
#define CCID_OUT_EP 0x04U /* EP1 for data OUT */
#define CCID_CMD_EP 0x85U /* EP2 for CDC commands */
#define CCID_DATA_PACKET_SIZE 64
#define CCID_SET_PARAMS 0x61
#define CCID_POWER_ON 0x62
#define CCID_POWER_OFF 0x63
#define CCID_SLOT_STATUS 0x65
#define CCID_SECURE 0x69
#define CCID_GET_PARAMS 0x6C
#define CCID_RESET_PARAMS 0x6D
#define CCID_XFR_BLOCK 0x6F
#define CCID_STATUS_ON 0x00
#define CCID_STATUS_OFF 0x02
#define CCID_DATA_BLOCK_RES 0x80
#define CCID_SLOT_STATUS_RES 0x81
#define CCID_PARAMS_RES 0x82
extern USBD_ClassTypeDef USBD_CCID;
typedef struct
{
uint32_t data[CCID_DATA_PACKET_SIZE / 4U];
uint8_t CmdOpCode;
uint8_t CmdLength;
uint8_t *RxBuffer;
uint8_t *TxBuffer;
uint32_t RxLength;
uint32_t TxLength;
__IO uint32_t TxState;
__IO uint32_t RxState;
}
USBD_CCID_HandleTypeDef;
uint8_t usb_ccid_recieve_callback(USBD_HandleTypeDef *pdev, uint8_t epnum);
#endif

View File

@ -195,9 +195,302 @@ USBD_ClassTypeDef USBD_CDC =
NULL, NULL,
NULL, NULL,
NULL, NULL,
// USBD_CDC_GetHSCfgDesc,
// USBD_CDC_GetFSCfgDesc,
// USBD_CDC_GetOtherSpeedCfgDesc,
// USBD_CDC_GetDeviceQualifierDescriptor,
}; };
/* USB CDC device Configuration Descriptor */
__ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
{
/*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
0x00,
0x02, /* bNumInterfaces: 2 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0xC0, /* bmAttributes: self powered */
0x32, /* MaxPower 0 mA */
/*---------------------------------------------------------------------------*/
/*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: One endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Header Functional Descriptor*/
0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/*Call Management Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
0x01, /* bDataInterface: 1 */
/*ACM Functional Descriptor*/
0x04, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x02, /* bmCapabilities */
/*Union Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */
0x00, /* bMasterInterface: Communication class interface */
0x01, /* bSlaveInterface0: Data Class Interface */
/*Endpoint 2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_CMD_EP, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_CMD_PACKET_SIZE),
CDC_HS_BINTERVAL, /* bInterval: */
/*---------------------------------------------------------------------------*/
/*Data class interface descriptor*/
0x09, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
0x01, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints: Two endpoints used */
0x0A, /* bInterfaceClass: CDC */
0x00, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface: */
/*Endpoint OUT Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_OUT_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_IN_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),
0x00 /* bInterval: ignore for Bulk transfer */
} ;
/* USB CDC device Configuration Descriptor */
__ALIGN_BEGIN uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
{
/*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
0x00,
0x02, /* bNumInterfaces: 2 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0xC0, /* bmAttributes: self powered */
0x32, /* MaxPower 0 mA */
/*---------------------------------------------------------------------------*/
/*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: One endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Header Functional Descriptor*/
0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/*Call Management Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
0x01, /* bDataInterface: 1 */
/*ACM Functional Descriptor*/
0x04, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x02, /* bmCapabilities */
/*Union Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */
0x00, /* bMasterInterface: Communication class interface */
0x01, /* bSlaveInterface0: Data Class Interface */
/*Endpoint 2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_CMD_EP, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_CMD_PACKET_SIZE),
CDC_FS_BINTERVAL, /* bInterval: */
/*---------------------------------------------------------------------------*/
/*Data class interface descriptor*/
0x09, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
0x01, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints: Two endpoints used */
0x0A, /* bInterfaceClass: CDC */
0x00, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface: */
/*Endpoint OUT Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_OUT_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_IN_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
0x00 /* bInterval: ignore for Bulk transfer */
} ;
__ALIGN_BEGIN uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuation Descriptor size */
USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION,
USB_CDC_CONFIG_DESC_SIZ,
0x00,
0x02, /* bNumInterfaces: 2 interfaces */
0x01, /* bConfigurationValue: */
0x04, /* iConfiguration: */
0xC0, /* bmAttributes: */
0x32, /* MaxPower 100 mA */
/*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: One endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Header Functional Descriptor*/
0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/*Call Management Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
0x01, /* bDataInterface: 1 */
/*ACM Functional Descriptor*/
0x04, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x02, /* bmCapabilities */
/*Union Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */
0x00, /* bMasterInterface: Communication class interface */
0x01, /* bSlaveInterface0: Data Class Interface */
/*Endpoint 2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT , /* bDescriptorType: Endpoint */
CDC_CMD_EP, /* bEndpointAddress */
0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_CMD_PACKET_SIZE),
CDC_FS_BINTERVAL, /* bInterval: */
/*---------------------------------------------------------------------------*/
/*Data class interface descriptor*/
0x09, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
0x01, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints: Two endpoints used */
0x0A, /* bInterfaceClass: CDC */
0x00, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface: */
/*Endpoint OUT Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_OUT_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
0x40, /* wMaxPacketSize: */
0x00,
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_IN_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */
0x40, /* wMaxPacketSize: */
0x00,
0x00 /* bInterval */
};
/**
* @}
*/
/** @defgroup USBD_CDC_Private_Functions
* @{
*/
/** /**
* @brief USBD_CDC_Init * @brief USBD_CDC_Init
@ -489,7 +782,45 @@ static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
return USBD_OK; return USBD_OK;
} }
/**
* @brief USBD_CDC_GetFSCfgDesc
* Return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
/*static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_CfgFSDesc);
return USBD_CDC_CfgFSDesc;
}
*/
/**
* @brief USBD_CDC_GetHSCfgDesc
* Return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
/*static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_CfgHSDesc);
return USBD_CDC_CfgHSDesc;
}
*/
/**
* @brief USBD_CDC_GetCfgDesc
* Return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
/*static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_OtherSpeedCfgDesc);
return USBD_CDC_OtherSpeedCfgDesc;
}
*/
/** /**
* @brief DeviceQualifierDescriptor * @brief DeviceQualifierDescriptor
* return Device Qualifier descriptor * return Device Qualifier descriptor
@ -608,10 +939,22 @@ uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
/* Suspend or Resume USB Out process */ /* Suspend or Resume USB Out process */
if(pdev->pClassData != NULL) if(pdev->pClassData != NULL)
{ {
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
/* Prepare Out endpoint to receive next packet */
USBD_LL_PrepareReceive(pdev,
CDC_OUT_EP,
hcdc->RxBuffer,
CDC_DATA_HS_OUT_PACKET_SIZE);
}
else
{
/* Prepare Out endpoint to receive next packet */
USBD_LL_PrepareReceive(pdev, USBD_LL_PrepareReceive(pdev,
CDC_OUT_EP, CDC_OUT_EP,
hcdc->RxBuffer, hcdc->RxBuffer,
CDC_DATA_FS_OUT_PACKET_SIZE); CDC_DATA_FS_OUT_PACKET_SIZE);
}
return USBD_OK; return USBD_OK;
} }
else else

View File

@ -2,9 +2,7 @@
#include "usbd_desc.h" #include "usbd_desc.h"
#include "usbd_hid.h" #include "usbd_hid.h"
#include "usbd_cdc.h" #include "usbd_cdc.h"
#include "usbd_ccid.h"
#include "usbd_ctlreq.h" #include "usbd_ctlreq.h"
#include "app.h"
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx); static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
@ -28,265 +26,151 @@ static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length);
static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length); static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
#ifdef ENABLE_CCID #define NUM_INTERFACES 2
#define CCID_SIZE 84
#define CCID_NUM_INTERFACE 1 #if NUM_INTERFACES>1
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90)
#else #else
#define CCID_NUM_INTERFACE 0 #define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (41)
#define CCID_SIZE 0
#endif #endif
#if DEBUG_LEVEL > 0 #define HID_INTF_NUM 0
#define CDC_SIZE (49 + 8 + 9 + 4) #define CDC_INTF_NUM 1
#define CDC_NUM_INTERFACE 2
#else
#define CDC_SIZE 0
#define CDC_NUM_INTERFACE 0
#endif
#define HID_SIZE 41
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (HID_SIZE + CDC_SIZE + CCID_SIZE)
#define NUM_INTERFACES (1 + CDC_NUM_INTERFACE + CCID_NUM_INTERFACE)
#define NUM_CLASSES 3
#define HID_INTF_NUM 0
#define CDC_MASTER_INTF_NUM 1
#define CDC_SLAVE_INTF_NUM 2
#define CCID_INTF_NUM 3
__ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END = __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END =
{ {
/*Configuration Descriptor*/ /*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */ 0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
COMPOSITE_CDC_HID_DESCRIPTOR_SIZE, /* wTotalLength:no of returned bytes */ COMPOSITE_CDC_HID_DESCRIPTOR_SIZE, /* wTotalLength:no of returned bytes */
0x00, 0x00,
NUM_INTERFACES, /* bNumInterfaces */ NUM_INTERFACES, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */ 0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0x80, /* bmAttributes: self powered */ 0x80, /* bmAttributes: self powered */
0x32, /* MaxPower 100 mA */ 0x32, /* MaxPower 100 mA */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* */ /* */
/* HID */ /* HID */
/* */ /* */
/************** Descriptor of Joystick Mouse interface ****************/ /************** Descriptor of Joystick Mouse interface ****************/
0x09, /*bLength: Interface Descriptor size*/ 0x09, /*bLength: Interface Descriptor size*/
USB_DESC_TYPE_INTERFACE, /*bDescriptorType: Interface descriptor type*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
HID_INTF_NUM, /*bInterfaceNumber: Number of Interface*/ HID_INTF_NUM, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/ 0x00, /*bAlternateSetting: Alternate setting*/
0x02, /*bNumEndpoints*/ 0x02, /*bNumEndpoints*/
0x03, /*bInterfaceClass: HID*/ 0x03, /*bInterfaceClass: HID*/
0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
2, /*iInterface: Index of string descriptor*/ 2, /*iInterface: Index of string descriptor*/
/******************** Descriptor of Joystick Mouse HID ********************/ /******************** Descriptor of Joystick Mouse HID ********************/
0x09, /*bLength: HID Descriptor size*/ 0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bcdHID: HID Class Spec release number*/ 0x11, /*bcdHID: HID Class Spec release number*/
0x01, 0x01,
0x00, /*bCountryCode: Hardware target country*/ 0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/ 0x22, /*bDescriptorType*/
HID_FIDO_REPORT_DESC_SIZE, /*wItemLength: Total length of Report descriptor*/ HID_FIDO_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
0, 0,
/******************** Descriptor of Mouse endpoint ********************/ /******************** Descriptor of Mouse endpoint ********************/
0x07, /*bLength: Endpoint Descriptor size*/ 0x07, /*bLength: Endpoint Descriptor size*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/ 0x03, /*bmAttributes: Interrupt endpoint*/
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */ HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
0x00, 0x00,
HID_BINTERVAL, /*bInterval: Polling Interval */ HID_BINTERVAL, /*bInterval: Polling Interval */
0x07, /*bLength: Endpoint Descriptor size*/ 0x07, /*bLength: Endpoint Descriptor size*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/ 0x03, /*bmAttributes: Interrupt endpoint*/
HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */ HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */
0x00, 0x00,
HID_BINTERVAL, /*bInterval: Polling Interval */ HID_BINTERVAL, /*bInterval: Polling Interval */
#if DEBUG_LEVEL > 0
/* */
/* CDC */
/* */
// This "IAD" is needed for Windows since it ignores the standard Union Functional Descriptor
0x08, // bLength
0x0B, // IAD type
CDC_MASTER_INTF_NUM, // First interface
CDC_SLAVE_INTF_NUM, // Next interface
0x02, // bInterfaceClass of the first interface
0x02, // bInterfaceSubClass of the first interface
0x00, // bInterfaceProtocol of the first interface
0x00, // Interface string index
/*Interface Descriptor */ #if NUM_INTERFACES>1
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
/* Interface descriptor type */
/*!*/ CDC_MASTER_INTF_NUM, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints: 1 endpoint used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x00, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Header Functional Descriptor*/ /* */
0x05, /* bLength: Endpoint Descriptor size */ /* CDC */
0x24, /* bDescriptorType: CS_INTERFACE */ /* */
0x00, /* bDescriptorSubtype: Header Func Desc */
0x10, /* bcdCDC: spec release number */
0x01,
/*Call Management Functional Descriptor*/
0x05, /* bFunctionLength */
0x24, /* bDescriptorType: CS_INTERFACE */
0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x00, /* bmCapabilities: D0+D1 */
/*!*/ CDC_SLAVE_INTF_NUM, /* bDataInterface: 0 */
/*ACM Functional Descriptor*/ /*Interface Descriptor */
0x04, /* bFunctionLength */ 0x09, /* bLength: Interface Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
0x02, /* bDescriptorSubtype: Abstract Control Management desc */ /* Interface descriptor type */
0x02, /* bmCapabilities */ /*!*/ CDC_INTF_NUM, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x03, /* bNumEndpoints: 3 endpoints used */
0x02, /* bInterfaceClass: Communication Interface Class */
0x02, /* bInterfaceSubClass: Abstract Control Model */
0x01, /* bInterfaceProtocol: Common AT commands */
0x00, /* iInterface: */
/*Union Functional Descriptor*/ /*Header Functional Descriptor*/
0x05, /* bFunctionLength */ 0x05, /* bLength: Endpoint Descriptor size */
0x24, /* bDescriptorType: CS_INTERFACE */ 0x24, /* bDescriptorType: CS_INTERFACE */
0x06, /* bDescriptorSubtype: Union func desc */ 0x00, /* bDescriptorSubtype: Header Func Desc */
/*!*/ CDC_MASTER_INTF_NUM, /* bMasterInterface: Communication class interface */ 0x10, /* bcdCDC: spec release number */
/*!*/ CDC_SLAVE_INTF_NUM, /* bSlaveInterface0: Data Class Interface */ 0x01,
/* Control Endpoint Descriptor*/ /*Call Management Functional Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */ 0x05, /* bFunctionLength */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ 0x24, /* bDescriptorType: CS_INTERFACE */
CDC_CMD_EP, /* bEndpointAddress */ 0x01, /* bDescriptorSubtype: Call Management Func Desc */
0x03, /* bmAttributes: Interrupt */ 0x00, /* bmCapabilities: D0+D1 */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */ /*!*/ CDC_INTF_NUM, /* bDataInterface: 0 */
HIBYTE(CDC_CMD_PACKET_SIZE),
0x10, /* bInterval: */
/* Interface descriptor */ /*ACM Functional Descriptor*/
0x09, /* bLength */ 0x04, /* bFunctionLength */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType */ 0x24, /* bDescriptorType: CS_INTERFACE */
CDC_SLAVE_INTF_NUM, /* bInterfaceNumber */ 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
0x00, /* bAlternateSetting */ 0x02, /* bmCapabilities */
0x02, /* bNumEndpoints */
0x0A, /* bInterfaceClass: Communication class data */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00,
/*Endpoint OUT Descriptor*/ /*Union Functional Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */ 0x05, /* bFunctionLength */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ 0x24, /* bDescriptorType: CS_INTERFACE */
CDC_OUT_EP, /* bEndpointAddress */ 0x06, /* bDescriptorSubtype: Union func desc */
0x02, /* bmAttributes: Bulk */ /*!*/ CDC_INTF_NUM, /* bMasterInterface: Communication class interface */
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ /*!*/ CDC_INTF_NUM, /* bSlaveInterface0: Data Class Interface */
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN Descriptor*/ /*Endpoint 2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */ 0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CDC_IN_EP, /* bEndpointAddress */ CDC_CMD_EP, /* bEndpointAddress */
0x02, /* bmAttributes: Bulk */ 0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), HIBYTE(CDC_CMD_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */ 0x10, /* bInterval: */
4, /* Descriptor size */ /*Endpoint OUT Descriptor*/
3, /* Descriptor type */ 0x07, /* bLength: Endpoint Descriptor size */
0x09, USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
0x04, CDC_OUT_EP, /* bEndpointAddress */
#endif 0x02, /* bmAttributes: Bulk */
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
0x00, /* bInterval: ignore for Bulk transfer */
#ifdef ENABLE_CCID /*Endpoint IN Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
/* CCID Interface Descriptor */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
9, /* bLength: Interface Descriptor size */ CDC_IN_EP, /* bEndpointAddress */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ 0x02, /* bmAttributes: Bulk */
CCID_INTF_NUM, /* bInterfaceNumber: CCID Interface */ LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
0, /* Alternate setting for this interface */ HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
3, /* bNumEndpoints: Bulk-IN, Bulk-OUT, Intr-IN */ 0x00, /* bInterval: ignore for Bulk transfer */
0x0B, /* CCID class */
0x00, /* CCID subclass */
0x00, /* CCID protocol */
0, /* string index for interface */
/* ICC Descriptor */
54, /* bLength: */
0x21, /* bDescriptorType: USBDESCR_ICC */
0x10, 0x01, /* bcdCCID: revision 1.1 (of CCID) */
0, /* bMaxSlotIndex: */
1, /* bVoltageSupport: 5V-only */
0x02, 0, 0, 0, /* dwProtocols: T=1 */
0xa0, 0x0f, 0, 0, /* dwDefaultClock: 4000 */
0xa0, 0x0f, 0, 0, /* dwMaximumClock: 4000 */
0, /* bNumClockSupported: 0x00 */
0x80, 0x25, 0, 0, /* dwDataRate: 9600 */
0x80, 0x25, 0, 0, /* dwMaxDataRate: 9600 */
0, /* bNumDataRateSupported: 0x00 */
0xfe, 0, 0, 0, /* dwMaxIFSD: 254 */
0, 0, 0, 0, /* dwSynchProtocols: 0 */
0, 0, 0, 0, /* dwMechanical: 0 */
0x7a, 0x04, 0x02, 0x00, /* dwFeatures:
* Short and extended APDU level: 0x40000 ----
* Short APDU level : 0x20000 *
* (ICCD?) : 0x00800 ----
* Automatic IFSD : 0x00400 *
* NAD value other than 0x00 : 0x00200
* Can set ICC in clock stop : 0x00100
* Automatic PPS CUR : 0x00080
* Automatic PPS PROP : 0x00040 *
* Auto baud rate change : 0x00020 *
* Auto clock change : 0x00010 *
* Auto voltage selection : 0x00008 *
* Auto activaction of ICC : 0x00004
* Automatic conf. based on ATR : 0x00002 *
*/
0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 271 */
0xff, /* bClassGetResponse: 0xff */
0x00, /* bClassEnvelope: 0 */
0, 0, /* wLCDLayout: 0 */
0, /* bPinSupport: No PIN pad */
1, /* bMaxCCIDBusySlots: 1 */
/*Endpoint IN1 Descriptor*/
7, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CCID_IN_EP, /* bEndpointAddress: (IN1) */
0x02, /* bmAttributes: Bulk */
CCID_DATA_PACKET_SIZE, 0x00, /* wMaxPacketSize: */
0x00, /* bInterval */
/*Endpoint OUT1 Descriptor*/
7, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CCID_OUT_EP, /* bEndpointAddress: (OUT1) */
0x02, /* bmAttributes: Bulk */
CCID_DATA_PACKET_SIZE, 0x00, /* wMaxPacketSize: */
0x00, /* bInterval */
/*Endpoint IN2 Descriptor*/
7, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
CCID_CMD_EP, /* bEndpointAddress: (IN2) */
0x03, /* bmAttributes: Interrupt */
CCID_DATA_PACKET_SIZE, 0x00, /* wMaxPacketSize: 4 */
0xFF, /* bInterval (255ms) */
#endif #endif
}; };
USBD_ClassTypeDef USBD_Composite = USBD_ClassTypeDef USBD_Composite =
{ {
USBD_Composite_Init, USBD_Composite_Init,
@ -305,57 +189,32 @@ USBD_ClassTypeDef USBD_Composite =
USBD_Composite_GetDeviceQualifierDescriptor, USBD_Composite_GetDeviceQualifierDescriptor,
}; };
static USBD_ClassTypeDef * USBD_Classes[MAX_CLASSES]; static USBD_ClassTypeDef *USBD_Classes[MAX_CLASSES];
int in_endpoint_to_class[MAX_ENDPOINTS]; int in_endpoint_to_class[MAX_ENDPOINTS];
int out_endpoint_to_class[MAX_ENDPOINTS]; int out_endpoint_to_class[MAX_ENDPOINTS];
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *ccid_class, USBD_ClassTypeDef *cdc_class) { void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1) {
memset(USBD_Classes, 0 , sizeof(USBD_Classes)); USBD_Classes[0] = class0;
USBD_Classes[0] = hid_class; USBD_Classes[1] = class1;
#ifdef ENABLE_CCID
USBD_Classes[1] = ccid_class;
#endif
#if DEBUG_LEVEL > 0
USBD_Classes[2] = cdc_class;
#endif
}
static USBD_ClassTypeDef * getClass(uint8_t index)
{
switch(index)
{
case HID_INTF_NUM:
return USBD_Classes[0];
#ifdef ENABLE_CCID
case CCID_INTF_NUM:
return USBD_Classes[1];
#endif
#if DEBUG_LEVEL > 0
case CDC_MASTER_INTF_NUM:
case CDC_SLAVE_INTF_NUM:
return USBD_Classes[2];
#endif
}
return NULL;
} }
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
int i; int i;
for(i = 0; i < NUM_CLASSES; i++) { for(i = 0; i < NUM_INTERFACES; i++) {
if (USBD_Classes[i] != NULL && USBD_Classes[i]->Init(pdev, cfgidx) != USBD_OK) { if (USBD_Classes[i]->Init(pdev, cfgidx) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
} }
//N
return USBD_OK; return USBD_OK;
} }
static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
int i; int i;
for(i = 0; i < NUM_CLASSES; i++) { for(i = 0; i < NUM_INTERFACES; i++) {
if (USBD_Classes[i] != NULL && USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) { if (USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
} }
@ -365,13 +224,10 @@ static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) {
int i; int i;
USBD_ClassTypeDef * device_class;
device_class = getClass(req->wIndex);
switch (req->bmRequest & USB_REQ_TYPE_MASK) { switch (req->bmRequest & USB_REQ_TYPE_MASK) {
case USB_REQ_TYPE_CLASS : case USB_REQ_TYPE_CLASS :
if (device_class != NULL) if (req->wIndex < NUM_INTERFACES)
return device_class->Setup(pdev, req); return USBD_Classes[req->wIndex]->Setup(pdev, req);
else else
return USBD_FAIL; return USBD_FAIL;
@ -380,8 +236,8 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
switch (req->bRequest) { switch (req->bRequest) {
case USB_REQ_GET_DESCRIPTOR : case USB_REQ_GET_DESCRIPTOR :
for(i = 0; i < NUM_CLASSES; i++) { for(i = 0; i < NUM_INTERFACES; i++) {
if (USBD_Classes[i] != NULL && USBD_Classes[i]->Setup(pdev, req) != USBD_OK) { if (USBD_Classes[i]->Setup(pdev, req) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
} }
@ -390,8 +246,8 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
case USB_REQ_GET_INTERFACE : case USB_REQ_GET_INTERFACE :
case USB_REQ_SET_INTERFACE : case USB_REQ_SET_INTERFACE :
if (device_class != NULL) if (req->wIndex < NUM_INTERFACES)
return device_class->Setup(pdev, req); return USBD_Classes[req->wIndex]->Setup(pdev, req);
else else
return USBD_FAIL; return USBD_FAIL;
} }
@ -404,8 +260,6 @@ static uint8_t USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) {
i = in_endpoint_to_class[epnum]; i = in_endpoint_to_class[epnum];
if (USBD_Classes[i] == NULL) return USBD_FAIL;
return USBD_Classes[i]->DataIn(pdev, epnum); return USBD_Classes[i]->DataIn(pdev, epnum);
} }
@ -414,16 +268,14 @@ static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
i = out_endpoint_to_class[epnum]; i = out_endpoint_to_class[epnum];
if (USBD_Classes[i] == NULL) return USBD_FAIL;
return USBD_Classes[i]->DataOut(pdev, epnum); return USBD_Classes[i]->DataOut(pdev, epnum);
} }
static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) { static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) {
int i; int i;
for(i = 0; i < NUM_CLASSES; i++) { for(i = 0; i < NUM_INTERFACES; i++) {
if (USBD_Classes[i] != NULL && USBD_Classes[i]->EP0_RxReady != NULL) { if (USBD_Classes[i]->EP0_RxReady != NULL) {
if (USBD_Classes[i]->EP0_RxReady(pdev) != USBD_OK) { if (USBD_Classes[i]->EP0_RxReady(pdev) != USBD_OK) {
return USBD_FAIL; return USBD_FAIL;
} }
@ -433,19 +285,16 @@ static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) {
} }
static uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length) { static uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length) {
//Y
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE; *length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
return COMPOSITE_CDC_HID_DESCRIPTOR; return COMPOSITE_CDC_HID_DESCRIPTOR;
} }
static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length) { static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length) {
//N
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE; *length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
return COMPOSITE_CDC_HID_DESCRIPTOR; return COMPOSITE_CDC_HID_DESCRIPTOR;
} }
static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length) { static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length) {
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE; *length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
return COMPOSITE_CDC_HID_DESCRIPTOR; return COMPOSITE_CDC_HID_DESCRIPTOR;
} }
@ -466,7 +315,6 @@ __ALIGN_BEGIN static uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUAL
}; };
uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length) { uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length) {
//N *length = sizeof (USBD_Composite_DeviceQualifierDesc);
*length = sizeof (USBD_Composite_DeviceQualifierDesc); return USBD_Composite_DeviceQualifierDesc;
return USBD_Composite_DeviceQualifierDesc;
} }

View File

@ -17,7 +17,7 @@ extern int in_endpoint_to_class[MAX_ENDPOINTS];
extern int out_endpoint_to_class[MAX_ENDPOINTS]; extern int out_endpoint_to_class[MAX_ENDPOINTS];
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1, USBD_ClassTypeDef *class2); void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -50,9 +50,6 @@
#include "stm32l4xx_hal.h" #include "stm32l4xx_hal.h"
#include "usbd_core.h" #include "usbd_core.h"
#include "usbd_hid.h" #include "usbd_hid.h"
#include "usbd_cdc.h"
#include "usbd_ccid.h"
#include "log.h"
void SystemClock_Config(void); void SystemClock_Config(void);
@ -120,14 +117,9 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
switch(epnum) switch(epnum)
{ {
case HID_EPOUT_ADDR: case HID_ENDPOINT:
usb_hid_recieve_callback(epnum); usb_hid_recieve_callback(epnum);
break; break;
#ifdef ENABLE_CCID
case CCID_OUT_EP:
usb_ccid_recieve_callback((USBD_HandleTypeDef*)hpcd->pData, epnum);
break;
#endif
} }
} }
@ -226,6 +218,7 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
{ {
USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData); USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
} }
/** /**
* @brief Initializes the low level portion of the device driver. * @brief Initializes the low level portion of the device driver.
* @param pdev: Device handle * @param pdev: Device handle
@ -259,20 +252,14 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
// HID // HID
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR , PCD_SNG_BUF, 0x98); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x98);
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR , PCD_SNG_BUF, 0xd8); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xd8);
// CCID
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_OUT_EP , PCD_SNG_BUF, 0xd8 + 64); // data OUT
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_IN_EP , PCD_SNG_BUF, 0xd8 + 64*2); // data IN
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_CMD_EP , PCD_SNG_BUF, 0xd8 + 64*3); // commands
// CDC / uart // CDC / uart
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_CMD_EP , PCD_SNG_BUF, 0xd8 + 64*4); // commands HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x02 , PCD_SNG_BUF, 0xd8 + 64); // data OUT
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, 0xd8 + 64*5); // data OUT HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0xd8 + 64*2); // data IN
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, 0xd8 + 64*6); // data IN HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x83 , PCD_SNG_BUF, 0xd8 + 64*3); // commands
// dump_pma_header("usbd_conf");
return USBD_OK; return USBD_OK;
} }
@ -323,7 +310,6 @@ USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,
uint8_t ep_type, uint8_t ep_type,
uint16_t ep_mps) uint16_t ep_mps)
{ {
// printf1(TAG_RED,"LL_Open. ep: %x, %x\r\n", ep_addr, ep_type);
HAL_PCD_EP_Open((PCD_HandleTypeDef*) pdev->pData, HAL_PCD_EP_Open((PCD_HandleTypeDef*) pdev->pData,
ep_addr, ep_addr,
ep_mps, ep_mps,

View File

@ -821,16 +821,12 @@ void USBD_CtlError( USBD_HandleTypeDef *pdev ,
* @param len : descriptor length * @param len : descriptor length
* @retval None * @retval None
*/ */
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t unicode_size, uint16_t *len) void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
{ {
uint8_t idx = 0U; uint8_t idx = 0U;
if (desc != NULL) if (desc != NULL)
{ {
if ((idx + 4) >= unicode_size)
{
return;
}
*len = (uint16_t)USBD_GetLen(desc) * 2U + 2U; *len = (uint16_t)USBD_GetLen(desc) * 2U + 2U;
unicode[idx++] = *(uint8_t *)(void *)len; unicode[idx++] = *(uint8_t *)(void *)len;
unicode[idx++] = USB_DESC_TYPE_STRING; unicode[idx++] = USB_DESC_TYPE_STRING;

View File

@ -108,7 +108,7 @@ void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata);
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t unicode_size, uint16_t *len); void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len);
/** /**
* @} * @}
*/ */

View File

@ -108,7 +108,7 @@ const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC]=
HIBYTE(USBD_LANGID_STRING), HIBYTE(USBD_LANGID_STRING),
}; };
uint8_t USBD_StrDesc[48]; uint8_t USBD_StrDesc[32];
/** /**
* @brief Returns the device descriptor. * @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) uint8_t *USBD_HID_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ {
USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, sizeof(USBD_StrDesc), length); USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
return USBD_StrDesc; 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) uint8_t *USBD_HID_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ {
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, sizeof(USBD_StrDesc), length); USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc; 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, sizeof(USBD_StrDesc), length); USBD_GetString((uint8_t *)uuid_str, USBD_StrDesc, length);
return USBD_StrDesc; return USBD_StrDesc;
} }

View File

@ -342,7 +342,6 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
uint8_t *pbuf = NULL; uint8_t *pbuf = NULL;
uint16_t status_info = 0U; uint16_t status_info = 0U;
USBD_StatusTypeDef ret = USBD_OK; USBD_StatusTypeDef ret = USBD_OK;
req->wLength = req->wLength & 0x7f;
switch (req->bmRequest & USB_REQ_TYPE_MASK) switch (req->bmRequest & USB_REQ_TYPE_MASK)
{ {
@ -387,7 +386,6 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
break; break;
case USB_REQ_GET_DESCRIPTOR: case USB_REQ_GET_DESCRIPTOR:
req->wLength = req->wLength & 0x7f;
if(req->wValue >> 8 == HID_REPORT_DESC) if(req->wValue >> 8 == HID_REPORT_DESC)
{ {
len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength); len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength);

View File

@ -1,74 +1,201 @@
/* Copyright 2019 SoloKeys Developers */ /*
/* */ *****************************************************************************
/* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */ **
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* End of RAM */ /* Highest address of the user mode stack */
_estack = 0x2000c000; _estack = 0x2000c000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_MIN_STACK_SIZE = 0x400; _Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY MEMORY
{ {
flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 20K
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
.isr_vector : /* The startup code goes first into FLASH */
{ .isr_vector :
. = ALIGN(8); {
KEEP(*(.isr_vector)) . = ALIGN(8);
. = ALIGN(8); KEEP(*(.isr_vector)) /* Startup code */
} >flash . = ALIGN(8);
} >FLASH
.text : /* The program code and other data goes into FLASH */
{ .text :
. = ALIGN(8); {
*(.text*) . = ALIGN(8);
*(.rodata*) *(.text) /* .text sections (code) */
KEEP(*(.init)) *(.text*) /* .text* sections (code) */
KEEP(*(.finit)) *(.glue_7) /* glue arm to thumb code */
. = ALIGN(8); *(.glue_7t) /* glue thumb to arm code */
_etext = .; *(.eh_frame)
} >flash
_sidata = LOADADDR(.data); KEEP (*(.init))
KEEP (*(.fini))
.data : . = ALIGN(8);
{ _etext = .; /* define a global symbols at end of code */
. = ALIGN(8); } >FLASH
_sdata = .;
*(.data*)
. = ALIGN(8);
_edata = .;
} >ram AT> flash
.bss : /* Constant data goes into FLASH */
{ .rodata :
. = ALIGN(4); {
_sbss = .; . = ALIGN(8);
__bss_start__ = _sbss; *(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.bss*) *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(COMMON) . = ALIGN(8);
. = ALIGN(4); } >FLASH
_ebss = .;
__bss_end__ = _ebss;
} > ram
._stack : .ARM.extab :
{ {
. = ALIGN(8); . = ALIGN(8);
end = .; *(.ARM.extab* .gnu.linkonce.armextab.*)
_end = .; . = ALIGN(8);
. = . + _MIN_STACK_SIZE; } >FLASH
. = ALIGN(8); .ARM : {
} > ram . = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,74 +1,201 @@
/* Copyright 2019 SoloKeys Developers */ /*
/* */ *****************************************************************************
/* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */ **
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* End of RAM */ /* Highest address of the user mode stack */
_estack = 0x2000c000; _estack = 0x2000c000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_MIN_STACK_SIZE = 0x400; _Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY MEMORY
{ {
flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
.isr_vector : /* The startup code goes first into FLASH */
{ .isr_vector :
. = ALIGN(8); {
KEEP(*(.isr_vector)) . = ALIGN(8);
. = ALIGN(8); KEEP(*(.isr_vector)) /* Startup code */
} >flash . = ALIGN(8);
} >FLASH
.text : /* The program code and other data goes into FLASH */
{ .text :
. = ALIGN(8); {
*(.text*) . = ALIGN(8);
*(.rodata*) *(.text) /* .text sections (code) */
KEEP(*(.init)) *(.text*) /* .text* sections (code) */
KEEP(*(.finit)) *(.glue_7) /* glue arm to thumb code */
. = ALIGN(8); *(.glue_7t) /* glue thumb to arm code */
_etext = .; *(.eh_frame)
} >flash
_sidata = LOADADDR(.data); KEEP (*(.init))
KEEP (*(.fini))
.data : . = ALIGN(8);
{ _etext = .; /* define a global symbols at end of code */
. = ALIGN(8); } >FLASH
_sdata = .;
*(.data*)
. = ALIGN(8);
_edata = .;
} >ram AT> flash
.bss : /* Constant data goes into FLASH */
{ .rodata :
. = ALIGN(4); {
_sbss = .; . = ALIGN(8);
__bss_start__ = _sbss; *(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.bss*) *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(COMMON) . = ALIGN(8);
. = ALIGN(4); } >FLASH
_ebss = .;
__bss_end__ = _ebss;
} > ram
._stack : .ARM.extab :
{ {
. = ALIGN(8); . = ALIGN(8);
end = .; *(.ARM.extab* .gnu.linkonce.armextab.*)
_end = .; . = ALIGN(8);
. = . + _MIN_STACK_SIZE; } >FLASH
. = ALIGN(8); .ARM : {
} > ram . = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,80 +1,202 @@
/* Copyright 2019 SoloKeys Developers */ /*
/* */ *****************************************************************************
/* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */ **
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* End of RAM */ /* Highest address of the user mode stack */
_estack = 0x2000c000; _estack = 0x2000c000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_MIN_STACK_SIZE = 0x400; _Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/*
Memory layout of device:
20 KB 198KB-8 38 KB
| bootloader | application | secrets/data |
*/
/* Specify the memory areas */
MEMORY MEMORY
{ {
flash (rx) : ORIGIN = 0x08005000, LENGTH = 198K - 8 /* First 20 KB is bootloader */
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K FLASH (rx) : ORIGIN = 0x08005000, LENGTH = 198K-8 /* Leave out 38 Kb at end for data */
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
.isr_vector : /* The startup code goes first into FLASH */
{ .isr_vector :
. = ALIGN(8); {
KEEP(*(.isr_vector)) . = ALIGN(8);
. = ALIGN(8); KEEP(*(.isr_vector)) /* Startup code */
} >flash . = ALIGN(8);
} >FLASH
.text : /* The program code and other data goes into FLASH */
{ .text :
. = ALIGN(8); {
*(.text*) . = ALIGN(8);
*(.rodata*) *(.text) /* .text sections (code) */
KEEP(*(.init)) *(.text*) /* .text* sections (code) */
KEEP(*(.finit)) *(.glue_7) /* glue arm to thumb code */
. = ALIGN(8); *(.glue_7t) /* glue thumb to arm code */
_etext = .; *(.eh_frame)
} >flash
_sidata = LOADADDR(.data); KEEP (*(.init))
KEEP (*(.fini))
.data : . = ALIGN(8);
{ _etext = .; /* define a global symbols at end of code */
. = ALIGN(8); } >FLASH
_sdata = .;
*(.data*)
. = ALIGN(8);
_edata = .;
} >ram AT> flash
.bss : /* Constant data goes into FLASH */
{ .rodata :
. = ALIGN(4); {
_sbss = .; . = ALIGN(8);
__bss_start__ = _sbss; *(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.bss*) *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(COMMON) . = ALIGN(8);
. = ALIGN(4); } >FLASH
_ebss = .;
__bss_end__ = _ebss;
} > ram
._stack : .ARM.extab :
{ {
. = ALIGN(8); . = ALIGN(8);
end = .; *(.ARM.extab* .gnu.linkonce.armextab.*)
_end = .; . = ALIGN(8);
. = . + _MIN_STACK_SIZE; } >FLASH
. = ALIGN(8); .ARM : {
} > ram . = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,74 +1,203 @@
/* Copyright 2019 SoloKeys Developers */ /*
/* */ *****************************************************************************
/* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or */ **
/* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or */
/* http://opensource.org/licenses/MIT>, at your option. This file may not be */
/* copied, modified, or distributed except according to those terms. */
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
/* End of RAM */ /* Highest address of the user mode stack */
_estack = 0x2000c000; _estack = 0x2000c000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_MIN_STACK_SIZE = 0x400; _Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY MEMORY
{ {
flash (rx) : ORIGIN = 0x08008000, LENGTH = 186K - 8 /* First 32 KB is bootloader */
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K /*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 238K-8 [> Leave out 38 Kb at end for data <]*/
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 186K-8 /* Leave out 38 Kb at end for data */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
} }
/* Define output sections */
SECTIONS SECTIONS
{ {
.isr_vector : /* The startup code goes first into FLASH */
{ .isr_vector :
. = ALIGN(8); {
KEEP(*(.isr_vector)) . = ALIGN(8);
. = ALIGN(8); KEEP(*(.isr_vector)) /* Startup code */
} >flash . = ALIGN(8);
} >FLASH
.text : /* The program code and other data goes into FLASH */
{ .text :
. = ALIGN(8); {
*(.text*) . = ALIGN(8);
*(.rodata*) *(.text) /* .text sections (code) */
KEEP(*(.init)) *(.text*) /* .text* sections (code) */
KEEP(*(.finit)) *(.glue_7) /* glue arm to thumb code */
. = ALIGN(8); *(.glue_7t) /* glue thumb to arm code */
_etext = .; *(.eh_frame)
} >flash
_sidata = LOADADDR(.data); KEEP (*(.init))
KEEP (*(.fini))
.data : . = ALIGN(8);
{ _etext = .; /* define a global symbols at end of code */
. = ALIGN(8); } >FLASH
_sdata = .;
*(.data*)
. = ALIGN(8);
_edata = .;
} >ram AT> flash
.bss : /* Constant data goes into FLASH */
{ .rodata :
. = ALIGN(4); {
_sbss = .; . = ALIGN(8);
__bss_start__ = _sbss; *(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.bss*) *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(COMMON) . = ALIGN(8);
. = ALIGN(4); } >FLASH
_ebss = .;
__bss_end__ = _ebss;
} > ram
._stack : .ARM.extab :
{ {
. = ALIGN(8); . = ALIGN(8);
end = .; *(.ARM.extab* .gnu.linkonce.armextab.*)
_end = .; . = ALIGN(8);
. = . + _MIN_STACK_SIZE; } >FLASH
. = ALIGN(8); .ARM : {
} > ram . = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_sisram2 = LOADADDR(.sram2);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.sram2 :
{
. = ALIGN(8);
_ssram2 = .; /* create a global symbol at sram2 start */
*(.sram2)
*(.sram2*)
. = ALIGN(8);
_esram2 = .; /* create a global symbol at sram2 end */
} >SRAM2 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
} }

View File

@ -1,373 +0,0 @@
#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
}
int 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);
uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE);
if (productType == 0x14)
{
return 1;
}
return 0;
}
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);
}
}

View File

@ -1,162 +0,0 @@
// 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)
int 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

View File

@ -12,13 +12,9 @@
#define DEBUG_UART USART1 #define DEBUG_UART USART1
#ifndef DEBUG_LEVEL #ifndef DEBUG_LEVEL
// Enable the CDC ACM USB interface & debug logs (DEBUG_LEVEL > 0)
#define DEBUG_LEVEL 0 #define DEBUG_LEVEL 0
#endif #endif
// Enable the CCID USB interface
// #define ENABLE_CCID
#define NON_BLOCK_PRINTING 0 #define NON_BLOCK_PRINTING 0
@ -27,7 +23,6 @@
//#define USING_DEV_BOARD //#define USING_DEV_BOARD
#define ENABLE_U2F_EXTENSIONS #define ENABLE_U2F_EXTENSIONS
// #define ENABLE_WALLET
#define ENABLE_U2F #define ENABLE_U2F
@ -35,7 +30,6 @@
// #define DISABLE_CTAPHID_WINK // #define DISABLE_CTAPHID_WINK
// #define DISABLE_CTAPHID_CBOR // #define DISABLE_CTAPHID_CBOR
// #define ENABLE_SERIAL_PRINTING
#if defined(SOLO_HACKER) #if defined(SOLO_HACKER)
#define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION #define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION
@ -44,7 +38,7 @@
#endif #endif
void printing_init(); void printing_init();
void hw_init(int lf); void hw_init(void);
//#define TEST //#define TEST
//#define TEST_POWER //#define TEST_POWER
@ -69,12 +63,6 @@ void hw_init(int lf);
#define SOLO_BUTTON_PORT GPIOA #define SOLO_BUTTON_PORT GPIOA
#define SOLO_BUTTON_PIN LL_GPIO_PIN_0 #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_WITH_DELAY 0
#define SKIP_BUTTON_CHECK_FAST 0 #define SKIP_BUTTON_CHECK_FAST 0

View File

@ -24,9 +24,6 @@
#include "aes.h" #include "aes.h"
#include "ctap.h" #include "ctap.h"
#include "device.h" #include "device.h"
// stuff for SHA512
#include "sha2.h"
#include "blockwise.h"
#include APP_CONFIG #include APP_CONFIG
#include "log.h" #include "log.h"
#include "memory_layout.h" #include "memory_layout.h"
@ -51,7 +48,6 @@ typedef enum
static SHA256_CTX sha256_ctx; static SHA256_CTX sha256_ctx;
static cf_sha512_context sha512_ctx;
static const struct uECC_Curve_t * _es256_curve = NULL; static const struct uECC_Curve_t * _es256_curve = NULL;
static const uint8_t * _signing_key = NULL; static const uint8_t * _signing_key = NULL;
static int _key_len = 0; static int _key_len = 0;
@ -66,9 +62,6 @@ void crypto_sha256_init()
sha256_init(&sha256_ctx); sha256_init(&sha256_ctx);
} }
void crypto_sha512_init() {
cf_sha512_init(&sha512_ctx);
}
void crypto_load_master_secret(uint8_t * key) void crypto_load_master_secret(uint8_t * key)
{ {
@ -93,10 +86,6 @@ void crypto_sha256_update(uint8_t * data, size_t len)
sha256_update(&sha256_ctx, data, 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() void crypto_sha256_update_secret()
{ {
sha256_update(&sha256_ctx, master_secret, 32); sha256_update(&sha256_ctx, master_secret, 32);
@ -107,11 +96,6 @@ void crypto_sha256_final(uint8_t * hash)
sha256_final(&sha256_ctx, 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) void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
{ {
uint8_t buf[64]; uint8_t buf[64];
@ -157,11 +141,6 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
key = master_secret; key = master_secret;
klen = sizeof(master_secret)/2; klen = sizeof(master_secret)/2;
} }
else if (key == CRYPTO_TRANSPORT_KEY2)
{
key = transport_secret;
klen = 32;
}
if(klen > 64) if(klen > 64)
@ -282,11 +261,6 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(x,pubkey,32); memmove(x,pubkey,32);
memmove(y,pubkey+32,32); memmove(y,pubkey+32,32);
} }
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
uECC_compute_public_key(privkey, pubkey, _es256_curve);
}
void crypto_load_external_key(uint8_t * key, int len) void crypto_load_external_key(uint8_t * key, int len)
{ {

View File

@ -10,7 +10,6 @@
#include "stm32l4xx_ll_gpio.h" #include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_tim.h" #include "stm32l4xx_ll_tim.h"
#include "stm32l4xx_ll_usart.h" #include "stm32l4xx_ll_usart.h"
#include "stm32l4xx_ll_pwr.h"
#include "usbd_hid.h" #include "usbd_hid.h"
#include APP_CONFIG #include APP_CONFIG
@ -27,74 +26,16 @@
#include "memory_layout.h" #include "memory_layout.h"
#include "stm32l4xx_ll_iwdg.h" #include "stm32l4xx_ll_iwdg.h"
#include "usbd_cdc_if.h" #include "usbd_cdc_if.h"
#include "nfc.h"
#include "init.h"
#include "sense.h"
#define LOW_FREQUENCY 1
#define HIGH_FREQUENCY 0
void wait_for_usb_tether(); void wait_for_usb_tether();
uint32_t __90_ms = 0; uint32_t __90_ms = 0;
uint32_t __last_button_press_time = 0;
uint32_t __last_button_bounce_time = 0;
uint32_t __device_status = 0; uint32_t __device_status = 0;
uint32_t __last_update = 0; uint32_t __last_update = 0;
extern PCD_HandleTypeDef hpcd; extern PCD_HandleTypeDef hpcd;
static int _NFC_status = 0;
static bool isLowFreq = 0;
static bool _RequestComeFromNFC = false;
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN)) #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
static int is_physical_button_pressed()
{
return (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN));
}
static int is_touch_button_pressed()
{
int is_pressed = (tsc_read_button(0) || tsc_read_button(1));
#ifndef IS_BOOTLOADER
if (is_pressed)
{
// delay for debounce, and longer than polling timer period.
delay(95);
return (tsc_read_button(0) || tsc_read_button(1));
}
#endif
return is_pressed;
}
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
static void edge_detect_touch_button()
{
static uint8_t last_touch = 0;
uint8_t current_touch = 0;
if (is_touch_button_pressed == IS_BUTTON_PRESSED)
{
current_touch = (tsc_read_button(0) || tsc_read_button(1));
// 1 sample per 25 ms
if ((millis() - __last_button_bounce_time) > 25)
{
// Detect "touch / rising edge"
if (!last_touch && current_touch)
{
__last_button_press_time = millis();
}
__last_button_bounce_time = millis();
last_touch = current_touch;
}
}
}
void request_from_nfc(bool request_active) {
_RequestComeFromNFC = request_active;
}
// Timer6 overflow handler. happens every ~90ms. // Timer6 overflow handler. happens every ~90ms.
void TIM6_DAC_IRQHandler() void TIM6_DAC_IRQHandler()
@ -102,38 +43,13 @@ void TIM6_DAC_IRQHandler()
// timer is only 16 bits, so roll it over here // timer is only 16 bits, so roll it over here
TIM6->SR = 0; TIM6->SR = 0;
__90_ms += 1; __90_ms += 1;
if ((millis() - __last_update) > 90) if ((millis() - __last_update) > 8)
{ {
if (__device_status != CTAPHID_STATUS_IDLE) if (__device_status != CTAPHID_STATUS_IDLE)
{ {
ctaphid_update_status(__device_status); ctaphid_update_status(__device_status);
} }
} }
edge_detect_touch_button();
#ifndef IS_BOOTLOADER
// NFC sending WTX if needs
if (device_is_nfc() == NFC_IS_ACTIVE)
{
WTX_timer_exec();
}
#endif
}
// Interrupt on rising edge of button (button released)
void EXTI0_IRQHandler(void)
{
EXTI->PR1 = EXTI->PR1;
if (is_physical_button_pressed == IS_BUTTON_PRESSED)
{
// Only allow 1 press per 25 ms.
if ((millis() - __last_button_bounce_time) > 25)
{
__last_button_press_time = millis();
}
__last_button_bounce_time = millis();
}
} }
// Global USB interrupt handler // Global USB interrupt handler
@ -175,60 +91,32 @@ void device_reboot()
{ {
NVIC_SystemReset(); NVIC_SystemReset();
} }
void device_init()
void device_init_button()
{ {
if (tsc_sensor_exists()) hw_init();
{ LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT);
tsc_init(); LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP);
IS_BUTTON_PRESSED = is_touch_button_pressed;
}
else
{
IS_BUTTON_PRESSED = is_physical_button_pressed;
}
}
void device_init(int argc, char *argv[])
{
hw_init(LOW_FREQUENCY);
if (! tsc_sensor_exists())
{
_NFC_status = nfc_init();
}
if (_NFC_status == NFC_IS_ACTIVE)
{
printf1(TAG_NFC, "Have NFC\r\n");
isLowFreq = 1;
IS_BUTTON_PRESSED = is_physical_button_pressed;
}
else
{
printf1(TAG_NFC, "Have NO NFC\r\n");
hw_init(HIGH_FREQUENCY);
isLowFreq = 0;
device_init_button();
}
usbhid_init();
ctaphid_init();
ctap_init();
#ifndef IS_BOOTLOADER
#if BOOT_TO_DFU #if BOOT_TO_DFU
flash_option_bytes_init(1); flash_option_bytes_init(1);
#else #else
flash_option_bytes_init(0); flash_option_bytes_init(0);
#endif
#endif #endif
printf1(TAG_GEN,"hello solo\r\n");
} }
int device_is_nfc() void usb_init(void);
void usbhid_init()
{ {
return _NFC_status; usb_init();
#if DEBUG_LEVEL>1
wait_for_usb_tether();
#endif
} }
void wait_for_usb_tether() void wait_for_usb_tether()
@ -242,26 +130,6 @@ 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) int usbhid_recv(uint8_t * msg)
{ {
if (fifo_hidmsg_size()) if (fifo_hidmsg_size())
@ -498,7 +366,6 @@ uint32_t ctap_atomic_count(int sel)
} }
void device_manage() void device_manage()
{ {
#if NON_BLOCK_PRINTING #if NON_BLOCK_PRINTING
@ -519,10 +386,6 @@ void device_manage()
} }
} }
#endif #endif
#ifndef IS_BOOTLOADER
if(device_is_nfc())
nfc_loop();
#endif
} }
static int handle_packets() static int handle_packets()
@ -544,49 +407,9 @@ static int handle_packets()
return 0; return 0;
} }
static int wait_for_button_activate(uint32_t wait) int ctap_user_presence_test()
{ {
int ret; int ret;
uint32_t start = millis();
do
{
if ((start + wait) < millis())
{
return 0;
}
delay(1);
ret = handle_packets();
if (ret)
return ret;
} while (!IS_BUTTON_PRESSED());
return 0;
}
static int wait_for_button_release(uint32_t wait)
{
int ret;
uint32_t start = millis();
do
{
if ((start + wait) < millis())
{
return 0;
}
delay(1);
ret = handle_packets();
if (ret)
return ret;
} while (IS_BUTTON_PRESSED());
return 0;
}
int ctap_user_presence_test(uint32_t up_delay)
{
int ret;
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
{
return 1;
}
#if SKIP_BUTTON_CHECK_WITH_DELAY #if SKIP_BUTTON_CHECK_WITH_DELAY
int i=500; int i=500;
while(i--) while(i--)
@ -599,41 +422,49 @@ int ctap_user_presence_test(uint32_t up_delay)
#elif SKIP_BUTTON_CHECK_FAST #elif SKIP_BUTTON_CHECK_FAST
delay(2); delay(2);
ret = handle_packets(); ret = handle_packets();
if (ret) if (ret) return ret;
return ret;
goto done; goto done;
#endif #endif
uint32_t t1 = millis();
// If button was pressed within last [2] seconds, succeed.
if (__last_button_press_time && (millis() - __last_button_press_time < 2000))
{
goto done;
}
// Set LED status and wait.
led_rgb(0xff3520); led_rgb(0xff3520);
// Block and wait for some time. while (IS_BUTTON_PRESSED())
ret = wait_for_button_activate(up_delay); {
if (ret) return ret; if (t1 + 5000 < millis())
ret = wait_for_button_release(up_delay);
if (ret) return ret;
// If button was pressed within last [2] seconds, succeed.
if (__last_button_press_time && (millis() - __last_button_press_time < 2000))
{ {
goto done; printf1(TAG_GEN,"Button not pressed\n");
goto fail;
} }
ret = handle_packets();
if (ret) return ret;
}
t1 = millis();
do
{
if (t1 + 5000 < millis())
{
goto fail;
}
delay(1);
ret = handle_packets();
if (ret) return ret;
}
while (! IS_BUTTON_PRESSED());
led_rgb(0x001040);
delay(50);
return 0; #if SKIP_BUTTON_CHECK_WITH_DELAY || SKIP_BUTTON_CHECK_FAST
done: done:
ret = wait_for_button_release(up_delay); #endif
__last_button_press_time = 0; return 1;
return 1;
fail:
return 0;
} }
int ctap_generate_rng(uint8_t * dst, size_t num) int ctap_generate_rng(uint8_t * dst, size_t num)
@ -712,7 +543,7 @@ void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey)); memmove(tmppage + (sizeof(CTAP_residentKey) * index) % PAGE_SIZE, rk, sizeof(CTAP_residentKey));
flash_erase_page(page); flash_erase_page(page);
flash_write(flash_addr(page), tmppage, PAGE_SIZE); flash_write(flash_addr(page), tmppage, ((sizeof(CTAP_residentKey) * (index + 1)) % PAGE_SIZE) );
} }
else else
{ {

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
/*
* 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

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
#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();
int 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) )
extern uint8_t p14443_block_offset(uint8_t pcb);
#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

View File

@ -24,33 +24,19 @@ void _putchar(char c)
} }
int _write (int fd, const void *buf, unsigned long int len)
int _write (int fd, const void *buf, long int len)
{ {
uint8_t * data = (uint8_t *) buf; uint8_t * data = (uint8_t *) buf;
#if DEBUG_LEVEL>0
// 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 // Send out USB serial
CDC_Transmit_FS(data, len); CDC_Transmit_FS(data, len);
// if (res == USBD_OK)
// logbuflen = 0;
#endif
#ifdef ENABLE_SERIAL_PRINTING
// Send out UART serial // Send out UART serial
while(len--) while(len--)
{ {
_putchar(*data++); _putchar(*data++);
} }
#endif
return 0; return 0;
} }
#endif #endif

View File

@ -17,7 +17,7 @@ int __errno = 0;
void rng_get_bytes(uint8_t * dst, size_t sz) void rng_get_bytes(uint8_t * dst, size_t sz)
{ {
uint8_t r[4]; uint8_t r[8];
unsigned int i,j; unsigned int i,j;
for (i = 0; i < sz; i += 4) for (i = 0; i < sz; i += 4)
{ {
@ -33,7 +33,7 @@ void rng_get_bytes(uint8_t * dst, size_t sz)
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{ {
if ((i + j) >= sz) if ((i + j) > sz)
{ {
return; return;
} }

View File

@ -0,0 +1,183 @@
/*
*****************************************************************************
**
** File : LinkerScript.ld
**
** Abstract : Linker script for STM32L432KCUx Device with
** 256KByte FLASH, 64KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
** (c)Copyright Ac6.
** You may use this file as-is or modify it according to the needs of your
** project. Distribution of this file (unmodified or modified) is not
** permitted. Ac6 permit registered System Workbench for MCU users the
** rights to distribute the assembled, compiled & linked contents of this
** file as part of an application binary file, provided that it is built
** using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20010000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(8);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(8);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(8);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(8);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(8);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(8);
} >FLASH
.ARM.extab :
{
. = ALIGN(8);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(8);
} >FLASH
.ARM : {
. = ALIGN(8);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(8);
} >FLASH
.preinit_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(8);
} >FLASH
.init_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(8);
} >FLASH
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

View File

@ -1,136 +0,0 @@
#include "sense.h"
#include "device.h"
#include "log.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_hal_tsc.h"
#define ELECTRODE_0 TSC_GROUP2_IO1
#define ELECTRODE_1 TSC_GROUP2_IO2
void tsc_init()
{
LL_GPIO_InitTypeDef GPIO_InitStruct;
// Enable TSC clock
RCC->AHB1ENR |= (1<<16);
/** TSC GPIO Configuration
PA4 ------> Channel 1
PA5 ------> Channel 2
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_4;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_9;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/** TSC GPIO Configuration
PA6 ------> sampling cap
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// Channel IOs
uint32_t channel_ios = TSC_GROUP2_IO1 | TSC_GROUP2_IO2;
// enable
TSC->CR = TSC_CR_TSCE;
TSC->CR |= (TSC_CTPH_8CYCLES |
TSC_CTPL_10CYCLES |
(uint32_t)(1 << TSC_CR_SSD_Pos) |
TSC_SS_PRESC_DIV1 |
TSC_PG_PRESC_DIV16 |
TSC_MCV_16383 |
TSC_SYNC_POLARITY_FALLING |
TSC_ACQ_MODE_NORMAL);
// Spread spectrum
if (0)
{
TSC->CR |= TSC_CR_SSE;
}
// Schmitt trigger and hysteresis
TSC->IOHCR = (uint32_t)(~(channel_ios | 0 | TSC_GROUP2_IO3));
// Sampling IOs
TSC->IOSCR = TSC_GROUP2_IO3;
// Groups
uint32_t grps = 0x02;
TSC->IOGCSR = grps;
TSC->IER &= (uint32_t)(~(TSC_IT_EOA | TSC_IT_MCE));
TSC->ICR = (TSC_FLAG_EOA | TSC_FLAG_MCE);
}
void tsc_set_electrode(uint32_t channel_ids)
{
TSC->IOCCR = (channel_ids);
}
void tsc_start_acq()
{
TSC->CR &= ~(TSC_CR_START);
TSC->ICR = TSC_FLAG_EOA | TSC_FLAG_MCE;
// Set IO output to output push-pull low
TSC->CR &= (~TSC_CR_IODEF);
TSC->CR |= TSC_CR_START;
}
void tsc_wait_on_acq()
{
while ( ! (TSC->ISR & TSC_FLAG_EOA) )
;
if ( TSC->ISR & TSC_FLAG_MCE )
{
printf1(TAG_ERR,"Max count reached\r\n");
}
}
uint32_t tsc_read(uint32_t indx)
{
return TSC->IOGXCR[indx];
}
uint32_t tsc_read_button(uint32_t index)
{
switch(index)
{
case 0:
tsc_set_electrode(ELECTRODE_0);
break;
case 1:
tsc_set_electrode(ELECTRODE_1);
break;
}
tsc_start_acq();
tsc_wait_on_acq();
return tsc_read(1) < 45;
}
int tsc_sensor_exists()
{
static uint8_t does = 0;
if (does) return 1;
LL_GPIO_SetPinMode(GPIOB, (1 << 1), LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinPull(GPIOB, (1 << 1), LL_GPIO_PULL_UP);
// Short delay before reading pin
asm("nop"); asm("nop"); asm("nop"); asm("nop");
does = (LL_GPIO_ReadInputPort(GPIOB) & (1 << 1)) == 0;
LL_GPIO_SetPinPull(GPIOB, 1, LL_GPIO_PULL_NO);
return does;
}

View File

@ -1,14 +0,0 @@
#ifndef _SENSE_H_
#define _SENSE_H_
#include <stdint.h>
void tsc_init();
int tsc_sensor_exists();
// Read button0 or button1
// Returns 1 if pressed, 0 if not.
uint32_t tsc_read_button(uint32_t index);
#endif

View File

@ -7,7 +7,7 @@
* - Set the initial SP * - Set the initial SP
* - Set the initial PC == Reset_Handler, * - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address, * - Set the vector table entries with the exceptions ISR address,
* - Configure the clock system * - Configure the clock system
* - Branches to main in the C library (which eventually * - Branches to main in the C library (which eventually
* calls main()). * calls main()).
* After Reset the Cortex-M4 processor is in Thread mode, * After Reset the Cortex-M4 processor is in Thread mode,
@ -79,8 +79,6 @@ Reset_Handler:
ldr sp, =_estack /* Atollic update: set stack pointer */ ldr sp, =_estack /* Atollic update: set stack pointer */
/* Copy the data segment initializers from flash to SRAM */ /* Copy the data segment initializers from flash to SRAM */
/* Call the clock system intitialization function.*/
bl SystemInit
movs r1, #0 movs r1, #0
b LoopCopyDataInit b LoopCopyDataInit
@ -108,7 +106,8 @@ LoopFillZerobss:
cmp r2, r3 cmp r2, r3
bcc FillZerobss bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */ /* Call static constructors */
bl __libc_init_array bl __libc_init_array
/* Call the application's entry point.*/ /* Call the application's entry point.*/
@ -116,7 +115,7 @@ LoopFillZerobss:
LoopForever: LoopForever:
b LoopForever b LoopForever
.size Reset_Handler, .-Reset_Handler .size Reset_Handler, .-Reset_Handler
/** /**
@ -415,49 +414,49 @@ g_pfnVectors:
.weak COMP_IRQHandler .weak COMP_IRQHandler
.thumb_set COMP_IRQHandler,Default_Handler .thumb_set COMP_IRQHandler,Default_Handler
.weak LPTIM1_IRQHandler .weak LPTIM1_IRQHandler
.thumb_set LPTIM1_IRQHandler,Default_Handler .thumb_set LPTIM1_IRQHandler,Default_Handler
.weak LPTIM2_IRQHandler .weak LPTIM2_IRQHandler
.thumb_set LPTIM2_IRQHandler,Default_Handler .thumb_set LPTIM2_IRQHandler,Default_Handler
.weak USB_IRQHandler .weak USB_IRQHandler
.thumb_set USB_IRQHandler,Default_Handler .thumb_set USB_IRQHandler,Default_Handler
.weak DMA2_Channel6_IRQHandler .weak DMA2_Channel6_IRQHandler
.thumb_set DMA2_Channel6_IRQHandler,Default_Handler .thumb_set DMA2_Channel6_IRQHandler,Default_Handler
.weak DMA2_Channel7_IRQHandler .weak DMA2_Channel7_IRQHandler
.thumb_set DMA2_Channel7_IRQHandler,Default_Handler .thumb_set DMA2_Channel7_IRQHandler,Default_Handler
.weak LPUART1_IRQHandler .weak LPUART1_IRQHandler
.thumb_set LPUART1_IRQHandler,Default_Handler .thumb_set LPUART1_IRQHandler,Default_Handler
.weak QUADSPI_IRQHandler .weak QUADSPI_IRQHandler
.thumb_set QUADSPI_IRQHandler,Default_Handler .thumb_set QUADSPI_IRQHandler,Default_Handler
.weak I2C3_EV_IRQHandler .weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler .thumb_set I2C3_EV_IRQHandler,Default_Handler
.weak I2C3_ER_IRQHandler .weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler .thumb_set I2C3_ER_IRQHandler,Default_Handler
.weak SAI1_IRQHandler .weak SAI1_IRQHandler
.thumb_set SAI1_IRQHandler,Default_Handler .thumb_set SAI1_IRQHandler,Default_Handler
.weak SWPMI1_IRQHandler .weak SWPMI1_IRQHandler
.thumb_set SWPMI1_IRQHandler,Default_Handler .thumb_set SWPMI1_IRQHandler,Default_Handler
.weak TSC_IRQHandler .weak TSC_IRQHandler
.thumb_set TSC_IRQHandler,Default_Handler .thumb_set TSC_IRQHandler,Default_Handler
.weak RNG_IRQHandler .weak RNG_IRQHandler
.thumb_set RNG_IRQHandler,Default_Handler .thumb_set RNG_IRQHandler,Default_Handler
.weak FPU_IRQHandler .weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler .thumb_set FPU_IRQHandler,Default_Handler
.weak CRS_IRQHandler .weak CRS_IRQHandler
.thumb_set CRS_IRQHandler,Default_Handler .thumb_set CRS_IRQHandler,Default_Handler
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -106,8 +106,6 @@
*/ */
#include "stm32l4xx.h" #include "stm32l4xx.h"
#include "device.h"
#include "init.h"
#if !defined (HSE_VALUE) #if !defined (HSE_VALUE)
#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
@ -221,9 +219,6 @@ void SystemInit(void)
/* Disable all interrupts */ /* Disable all interrupts */
RCC->CIER = 0x00000000U; RCC->CIER = 0x00000000U;
// TODO this is causing boot issues for old bootloader
device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
} }
/** /**

Some files were not shown because too many files have changed in this diff Show More