Compare commits

..

6 Commits

Author SHA1 Message Date
a7cda74741 Update solo-extras.md 2019-08-16 14:03:41 +08:00
a8baba422f add info for rng use 2019-08-16 14:03:07 +08:00
abd2eca3ca run through fixes 2019-08-16 13:53:28 +08:00
038c594e37 dont remove solo.hex bootloader.hex 2019-08-16 13:52:17 +08:00
f09900a391 initial draft 2019-08-16 11:59:54 +08:00
bd822dd95f add secure build that uses default attestation key 2019-08-16 10:29:24 +08:00
41 changed files with 723 additions and 1243 deletions

View File

@ -168,25 +168,6 @@
"infra", "infra",
"tool" "tool"
] ]
},
{
"login": "kimusan",
"name": "Kim Schulz",
"avatar_url": "https://avatars1.githubusercontent.com/u/1150049?v=4",
"profile": "http://www.schulz.dk",
"contributions": [
"business",
"ideas"
]
},
{
"login": "oplik0",
"name": "Jakub",
"avatar_url": "https://avatars2.githubusercontent.com/u/25460763?v=4",
"profile": "https://github.com/oplik0",
"contributions": [
"bug"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

View File

@ -1,19 +1,25 @@
**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)
[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors)
[<img src="https://miro.medium.com/max/1400/1*PnzCPLqq_5nt1gjgSEY2LQ.png" width="600">](https://solokeys.com/somu) [![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)
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)
[![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)
# 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.
<img src="https://static.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, but it is easily portable. 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.
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.
@ -36,7 +42,7 @@ Solo for Hacker is a special version of Solo that let you customize its firmware
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. 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.
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
@ -134,8 +140,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<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="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="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://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>
<td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td>
</tr> </tr>
</table> </table>
@ -164,19 +168,3 @@ You may use Solo documentation under the terms of the CC-BY-SA 4.0 license
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-19-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 +1 @@
2.5.2 2.4.2

View File

@ -115,7 +115,7 @@ If the checks succeed, you are ready to program the device attestation key and c
### Programming an attestation key and certificate ### Programming an attestation key and certificate
Convert the DER format of the device attestation certificate to "C" bytes using our utility script. You may first need to 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`). first install prerequisite python modules (pip install -r tools/requirements.txt).
``` ```
python tools/gencert/cbytes.py device_cert.der python tools/gencert/cbytes.py device_cert.der
@ -123,7 +123,7 @@ 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. 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. 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. Print your attestation key in a hex string format.
@ -131,11 +131,11 @@ Print your attestation key in a hex string format.
python tools/print_x_y.py device_key.pem python tools/print_x_y.py device_key.pem
``` ```
Merge the `bootloader.hex`, `solo.hex`, and attestion key into one firmware file. Merge the bootloader.hex, solo.hex, and attestion key into one firmware file.
``` ```
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex 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 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). with Solo in DFU mode](/solo/programming#procedure).

View File

@ -85,13 +85,14 @@ brew install arm-none-eabi-gcc
### Install flashing software ### Install flashing software
ST provides a CLI flashing tool - `STM32_Programmer_CLI`. It can be downloaded directly from the vendor's site: 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. 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),
2. Unzip contents of the archive. go to bottom page and from STM32CubeProg row select Download button.
3. Run \*Linux setup 2\. Unzip contents of the archive.
4. In installation directory go to `./bin` - there the `./STM32_Programmer_CLI` is located 3\. Run \*Linux setup
5. Add symlink to the STM32 CLI binary to `.local/bin`. Make sure the latter it is in `$PATH`. 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 MacOS X and installed the STM32CubeProg, you need to add the following to your path: If you're on OsX and installed the STM32CubeProg, you need to add the following to your path:
```bash ```bash
# ~/.bash_profile # ~/.bash_profile

View File

@ -3,16 +3,16 @@
## Random number generation ## Random number generation
Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism
that leverages natural phenomenon to generate random numbers, which can be better than a traditional 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. 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). 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 solo key rng raw > random.bin
``` ```
Or you can seed the state of the RNG on your kernel (`/dev/random`). Or you can seed the state of the RNG on your kernel (/dev/random).
``` ```
solo key rng feedkernel solo key rng feedkernel

View File

@ -1,21 +1,20 @@
# Summary # Summary
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. 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. (Under Fedora, your key may work without such a rule.)
For some users, things will work automatically: 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, for instance the following rule should cover normal access (it has to be on one line):
- 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 SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", MODE="0660", GROUP="plugdev"
- 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>. Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>. ```
sudo udevadm control --reload-rules && sudo udevadm trigger
```
If you still need to setup a rule, a simple way to do it is: A simple way to setup both the udev rule and the udevadm reload is:
``` ```
git clone git@github.com:solokeys/solo.git git clone git@github.com:solokeys/solo.git
@ -23,11 +22,9 @@ cd solo/udev
make setup make setup
``` ```
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. We are working on getting user access to Solo keys enabled automatically in common Linux distributions: <https://github.com/solokeys/solo/issues/144>.
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
```
# How do udev rules work and why are they needed # How do udev rules work and why are they needed

View File

@ -9,11 +9,11 @@
#include "apdu.h" #include "apdu.h"
uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu) int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
{ {
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data; EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any apdu->cla = hapdu->cla;
apdu->ins = hapdu->ins; apdu->ins = hapdu->ins;
apdu->p1 = hapdu->p1; apdu->p1 = hapdu->p1;
apdu->p2 = hapdu->p2; apdu->p2 = hapdu->p2;
@ -62,11 +62,6 @@ uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
if (len >= 7 && b0 == 0) if (len >= 7 && b0 == 0)
{ {
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
if (len - 7 < extlen)
{
return SW_WRONG_LENGTH;
}
// case 2E (Le) - extended // case 2E (Le) - extended
if (len == 7) if (len == 7)
@ -108,18 +103,9 @@ uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
apdu->le = 0x10000; apdu->le = 0x10000;
} }
} }
else
{
if ((len > 5) && (len - 5 < hapdu->lc[0]))
{
return SW_WRONG_LENGTH;
}
}
if (!apdu->case_type) if (!apdu->case_type)
{ return 1;
return SW_COND_USE_NOT_SATISFIED;
}
if (apdu->lc) if (apdu->lc)
{ {

View File

@ -36,26 +36,20 @@ typedef struct
uint8_t case_type; uint8_t case_type;
} __attribute__((packed)) APDU_STRUCT; } __attribute__((packed)) APDU_STRUCT;
extern uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu); extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
#define APDU_FIDO_U2F_REGISTER 0x01 #define APDU_FIDO_U2F_REGISTER 0x01
#define APDU_FIDO_U2F_AUTHENTICATE 0x02 #define APDU_FIDO_U2F_AUTHENTICATE 0x02
#define APDU_FIDO_U2F_VERSION 0x03 #define APDU_FIDO_U2F_VERSION 0x03
#define APDU_FIDO_NFCCTAP_MSG 0x10 #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_SELECT 0xA4
#define APDU_INS_READ_BINARY 0xB0 #define APDU_INS_READ_BINARY 0xB0
#define APDU_GET_RESPONSE 0xC0
#define SW_SUCCESS 0x9000 #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_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_WRONG_LENGTH 0x6700
#define SW_COND_USE_NOT_SATISFIED 0x6985 #define SW_COND_USE_NOT_SATISFIED 0x6985
#define SW_FILE_NOT_FOUND 0x6a82 #define SW_FILE_NOT_FOUND 0x6a82
#define SW_INCORRECT_P1P2 0x6a86
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid #define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
#define SW_CLA_INVALID 0x6e00 #define SW_CLA_INVALID 0x6e00
#define SW_INTERNAL_EXCEPTION 0x6f00 #define SW_INTERNAL_EXCEPTION 0x6f00

View File

@ -262,11 +262,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

@ -26,7 +26,6 @@ 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();

View File

@ -25,11 +25,11 @@
#include "extensions.h" #include "extensions.h"
#include "device.h" #include "device.h"
#include "data_migration.h"
uint8_t PIN_TOKEN[PIN_TOKEN_SIZE]; uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
uint8_t KEY_AGREEMENT_PUB[64]; uint8_t KEY_AGREEMENT_PUB[64];
static uint8_t KEY_AGREEMENT_PRIV[32]; static uint8_t KEY_AGREEMENT_PRIV[32];
static uint8_t PIN_CODE_HASH[32];
static int8_t PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS; static int8_t PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
AuthenticatorState STATE; AuthenticatorState STATE;
@ -256,9 +256,7 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input,
switch(algtype) switch(algtype)
{ {
case COSE_ALG_ES256: case COSE_ALG_ES256:
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
crypto_ecc256_derive_public_key(hmac_input, len, x, y); crypto_ecc256_derive_public_key(hmac_input, len, x, y);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
break; break;
default: default:
printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype); printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype);
@ -437,23 +435,7 @@ static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred)
static int ctap2_user_presence_test() static int ctap2_user_presence_test()
{ {
device_set_status(CTAPHID_STATUS_UPNEEDED); device_set_status(CTAPHID_STATUS_UPNEEDED);
int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS); return ctap_user_presence_test(CTAP2_UP_DELAY_MS);
if ( ret > 1 )
{
return CTAP2_ERR_PROCESSING;
}
else if ( ret > 0 )
{
return CTAP1_ERR_SUCCESS;
}
else if (ret < 0)
{
return CTAP2_ERR_KEEPALIVE_CANCEL;
}
else
{
return CTAP2_ERR_ACTION_TIMEOUT;
}
} }
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo) static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo)
@ -486,19 +468,19 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
int but; int but;
but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS); but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
if (CTAP2_ERR_PROCESSING == but)
if (!but)
{ {
authData->head.flags = (0 << 0); // User presence disabled return CTAP2_ERR_OPERATION_DENIED;
} }
else else if (but < 0) // Cancel
{ {
check_retr(but); return CTAP2_ERR_KEEPALIVE_CANCEL;
authData->head.flags = (1 << 0); // User presence
} }
device_set_status(CTAPHID_STATUS_PROCESSING); device_set_status(CTAPHID_STATUS_PROCESSING);
authData->head.flags = (but << 0);
authData->head.flags |= (ctap_is_pin_set() << 2); authData->head.flags |= (ctap_is_pin_set() << 2);
@ -682,16 +664,7 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d
switch(desc->type) switch(desc->type)
{ {
case PUB_KEY_CRED_PUB_KEY: case PUB_KEY_CRED_PUB_KEY:
crypto_sha256_init(); make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
crypto_sha256_update(rp->id, rp->size);
crypto_sha256_final(rpIdHash);
printf1(TAG_RED,"rpId: %s\r\n", rp->id); dump_hex1(TAG_RED,rp->id, rp->size);
if (memcmp(desc->credential.id.rpIdHash, rpIdHash, 32) != 0)
{
return 0;
}
make_auth_tag(rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0); return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
break; break;
case PUB_KEY_CRED_CTAP1: case PUB_KEY_CRED_CTAP1:
@ -732,7 +705,10 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
} }
if (MC.pinAuthEmpty) if (MC.pinAuthEmpty)
{ {
check_retr( ctap2_user_presence_test(CTAP2_UP_DELAY_MS) ); if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
{
return CTAP2_ERR_OPERATION_DENIED;
}
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET; return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
} }
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask) if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
@ -755,7 +731,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
} }
} }
if (MC.up == 1 || MC.up == 0) if (MC.up)
{ {
return CTAP2_ERR_INVALID_OPTION; return CTAP2_ERR_INVALID_OPTION;
} }
@ -1165,7 +1141,10 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
if (GA.pinAuthEmpty) if (GA.pinAuthEmpty)
{ {
check_retr( ctap2_user_presence_test(CTAP2_UP_DELAY_MS) ); if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
{
return CTAP2_ERR_OPERATION_DENIED;
}
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET; return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
} }
if (GA.pinAuthPresent) if (GA.pinAuthPresent)
@ -1248,9 +1227,8 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
else else
#endif #endif
{ {
device_disable_up(GA.up == 0);
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL); ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
device_disable_up(false);
check_retr(ret); check_retr(ret);
((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2); ((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2);
@ -1308,13 +1286,11 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
uint8_t hmac[32]; uint8_t hmac[32];
int ret; int ret;
// Validate incoming data packet len
if (len < 64) if (len < 64)
{ {
return CTAP1_ERR_OTHER; return CTAP1_ERR_OTHER;
} }
// Validate device's state
if (ctap_is_pin_set()) // Check first, prevent SCA if (ctap_is_pin_set()) // Check first, prevent SCA
{ {
if (ctap_device_locked()) if (ctap_device_locked())
@ -1327,7 +1303,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
} }
} }
// calculate shared_secret
crypto_ecc256_shared_secret(platform_pubkey, KEY_AGREEMENT_PRIV, shared_secret); crypto_ecc256_shared_secret(platform_pubkey, KEY_AGREEMENT_PRIV, shared_secret);
crypto_sha256_init(); crypto_sha256_init();
@ -1350,7 +1325,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
return CTAP2_ERR_PIN_AUTH_INVALID; return CTAP2_ERR_PIN_AUTH_INVALID;
} }
// decrypt new PIN with shared secret
crypto_aes256_init(shared_secret, NULL); crypto_aes256_init(shared_secret, NULL);
while((len & 0xf) != 0) // round up to nearest AES block size multiple while((len & 0xf) != 0) // round up to nearest AES block size multiple
@ -1360,7 +1334,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
crypto_aes256_decrypt(pinEnc, len); crypto_aes256_decrypt(pinEnc, len);
// validate new PIN (length)
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1); ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
ret = NEW_PIN_ENC_MIN_SIZE - ret; ret = NEW_PIN_ENC_MIN_SIZE - ret;
@ -1376,8 +1350,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
dump_hex1(TAG_CP, pinEnc, ret); dump_hex1(TAG_CP, pinEnc, ret);
} }
// validate device's state, decrypt and compare pinHashEnc (user provided current PIN hash) with stored PIN_CODE_HASH
if (ctap_is_pin_set()) if (ctap_is_pin_set())
{ {
if (ctap_device_locked()) if (ctap_device_locked())
@ -1390,14 +1362,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
} }
crypto_aes256_reset_iv(NULL); crypto_aes256_reset_iv(NULL);
crypto_aes256_decrypt(pinHashEnc, 16); crypto_aes256_decrypt(pinHashEnc, 16);
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
uint8_t pinHashEncSalted[32];
crypto_sha256_init();
crypto_sha256_update(pinHashEnc, 16);
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
crypto_sha256_final(pinHashEncSalted);
if (memcmp(pinHashEncSalted, STATE.PIN_CODE_HASH, 16) != 0)
{ {
ctap_reset_key_agreement(); ctap_reset_key_agreement();
ctap_decrement_pin_attempts(); ctap_decrement_pin_attempts();
@ -1413,7 +1378,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
} }
} }
// set new PIN (update and store PIN_CODE_HASH)
ctap_update_pin(pinEnc, ret); ctap_update_pin(pinEnc, ret);
return 0; return 0;
@ -1433,16 +1397,12 @@ uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubke
crypto_aes256_decrypt(pinHashEnc, 16); crypto_aes256_decrypt(pinHashEnc, 16);
uint8_t pinHashEncSalted[32];
crypto_sha256_init(); if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
crypto_sha256_update(pinHashEnc, 16);
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
crypto_sha256_final(pinHashEncSalted);
if (memcmp(pinHashEncSalted, STATE.PIN_CODE_HASH, 16) != 0)
{ {
printf2(TAG_ERR,"Pin does not match!\n"); printf2(TAG_ERR,"Pin does not match!\n");
printf2(TAG_ERR,"platform-pin-hash: "); dump_hex1(TAG_ERR, pinHashEnc, 16); printf2(TAG_ERR,"platform-pin-hash: "); dump_hex1(TAG_ERR, pinHashEnc, 16);
printf2(TAG_ERR,"authentic-pin-hash: "); dump_hex1(TAG_ERR, STATE.PIN_CODE_HASH, 16); printf2(TAG_ERR,"authentic-pin-hash: "); dump_hex1(TAG_ERR, PIN_CODE_HASH, 16);
printf2(TAG_ERR,"shared-secret: "); dump_hex1(TAG_ERR, shared_secret, 32); printf2(TAG_ERR,"shared-secret: "); dump_hex1(TAG_ERR, shared_secret, 32);
printf2(TAG_ERR,"platform-pubkey: "); dump_hex1(TAG_ERR, platform_pubkey, 64); printf2(TAG_ERR,"platform-pubkey: "); dump_hex1(TAG_ERR, platform_pubkey, 64);
printf2(TAG_ERR,"device-pubkey: "); dump_hex1(TAG_ERR, KEY_AGREEMENT_PUB, 64); printf2(TAG_ERR,"device-pubkey: "); dump_hex1(TAG_ERR, KEY_AGREEMENT_PUB, 64);
@ -1519,11 +1479,6 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
ret = cbor_encode_int(&map, RESP_keyAgreement); ret = cbor_encode_int(&map, RESP_keyAgreement);
check_ret(ret); check_ret(ret);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
crypto_ecc256_compute_public_key(KEY_AGREEMENT_PRIV, KEY_AGREEMENT_PUB);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
ret = ctap_add_cose_key(&map, KEY_AGREEMENT_PUB, KEY_AGREEMENT_PUB+32, PUB_KEY_CRED_PUB_KEY, COSE_ALG_ECDH_ES_HKDF_256); ret = ctap_add_cose_key(&map, KEY_AGREEMENT_PUB, KEY_AGREEMENT_PUB+32, PUB_KEY_CRED_PUB_KEY, COSE_ALG_ECDH_ES_HKDF_256);
check_retr(ret); check_retr(ret);
@ -1694,11 +1649,14 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
break; break;
case CTAP_RESET: case CTAP_RESET:
printf1(TAG_CTAP,"CTAP_RESET\n"); printf1(TAG_CTAP,"CTAP_RESET\n");
status = ctap2_user_presence_test(CTAP2_UP_DELAY_MS); if (ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
if (status == CTAP1_ERR_SUCCESS)
{ {
ctap_reset(); ctap_reset();
} }
else
{
status = CTAP2_ERR_OPERATION_DENIED;
}
break; break;
case GET_NEXT_ASSERTION: case GET_NEXT_ASSERTION:
printf1(TAG_CTAP,"CTAP_NEXT_ASSERTION\n"); printf1(TAG_CTAP,"CTAP_NEXT_ASSERTION\n");
@ -1720,7 +1678,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
break; break;
default: default:
status = CTAP1_ERR_INVALID_COMMAND; status = CTAP1_ERR_INVALID_COMMAND;
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd); printf2(TAG_ERR,"error, invalid cmd\n");
} }
done: done:
@ -1750,18 +1708,8 @@ static void ctap_state_init()
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS; STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
STATE.is_pin_set = 0; STATE.is_pin_set = 0;
STATE.rk_stored = 0; STATE.rk_stored = 0;
STATE.data_version = STATE_VERSION;
ctap_reset_rk(); ctap_reset_rk();
if (ctap_generate_rng(STATE.PIN_SALT, sizeof(STATE.PIN_SALT)) != 1) {
printf2(TAG_ERR, "Error, rng failed\n");
exit(1);
}
printf1(TAG_STOR, "Generated PIN SALT: ");
dump_hex1(TAG_STOR, STATE.PIN_SALT, sizeof STATE.PIN_SALT);
} }
void ctap_init() void ctap_init()
@ -1794,12 +1742,14 @@ void ctap_init()
} }
} }
do_migration_if_required(&STATE);
crypto_load_master_secret(STATE.key_space); crypto_load_master_secret(STATE.key_space);
if (ctap_is_pin_set()) if (ctap_is_pin_set())
{ {
printf1(TAG_STOR,"pin code: \"%s\"\n", STATE.pin_code);
crypto_sha256_init();
crypto_sha256_update(STATE.pin_code, STATE.pin_code_length);
crypto_sha256_final(PIN_CODE_HASH);
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries); printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
} }
else else
@ -1817,7 +1767,10 @@ void ctap_init()
exit(1); exit(1);
} }
ctap_reset_key_agreement(); if (device_is_nfc() != NFC_IS_ACTIVE)
{
ctap_reset_key_agreement();
}
#ifdef BRIDGE_TO_WALLET #ifdef BRIDGE_TO_WALLET
wallet_init(); wallet_init();
@ -1831,38 +1784,34 @@ uint8_t ctap_is_pin_set()
return STATE.is_pin_set == 1; return STATE.is_pin_set == 1;
} }
/** uint8_t ctap_pin_matches(uint8_t * pin, int len)
* Set new PIN, by updating PIN hash. Save state. {
* Globals: STATE return memcmp(pin, STATE.pin_code, len) == 0;
* @param pin new PIN (raw) }
* @param len pin array length
*/
void ctap_update_pin(uint8_t * pin, int len) void ctap_update_pin(uint8_t * pin, int len)
{ {
if (len >= NEW_PIN_ENC_MIN_SIZE || len < 4) if (len > NEW_PIN_ENC_MIN_SIZE || len < 4)
{ {
printf2(TAG_ERR, "Update pin fail length\n"); printf2(TAG_ERR, "Update pin fail length\n");
exit(1); exit(1);
} }
memset(STATE.pin_code, 0, NEW_PIN_ENC_MIN_SIZE);
memmove(STATE.pin_code, pin, len);
STATE.pin_code_length = len;
STATE.pin_code[NEW_PIN_ENC_MIN_SIZE - 1] = 0;
crypto_sha256_init(); crypto_sha256_init();
crypto_sha256_update(pin, len); crypto_sha256_update(STATE.pin_code, len);
uint8_t intermediateHash[32]; crypto_sha256_final(PIN_CODE_HASH);
crypto_sha256_final(intermediateHash);
crypto_sha256_init();
crypto_sha256_update(intermediateHash, 16);
memset(intermediateHash, 0, sizeof(intermediateHash));
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
crypto_sha256_final(STATE.PIN_CODE_HASH);
STATE.is_pin_set = 1; STATE.is_pin_set = 1;
authenticator_write_state(&STATE, 1); authenticator_write_state(&STATE, 1);
authenticator_write_state(&STATE, 0); authenticator_write_state(&STATE, 0);
printf1(TAG_CTAP, "New pin set: %s [%d]\n", pin, len); printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
dump_hex1(TAG_ERR, STATE.PIN_CODE_HASH, sizeof(STATE.PIN_CODE_HASH));
} }
uint8_t ctap_decrement_pin_attempts() uint8_t ctap_decrement_pin_attempts()
@ -1879,7 +1828,9 @@ uint8_t ctap_decrement_pin_attempts()
if (ctap_device_locked()) if (ctap_device_locked())
{ {
lock_device_permanently(); memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
printf1(TAG_CP, "Device locked!\n");
} }
} }
else else
@ -2018,7 +1969,7 @@ int8_t ctap_load_key(uint8_t index, uint8_t * key)
static void ctap_reset_key_agreement() static void ctap_reset_key_agreement()
{ {
ctap_generate_rng(KEY_AGREEMENT_PRIV, sizeof(KEY_AGREEMENT_PRIV)); crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
} }
void ctap_reset() void ctap_reset()
@ -2035,17 +1986,8 @@ void ctap_reset()
} }
ctap_reset_state(); ctap_reset_state();
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
ctap_reset_key_agreement(); ctap_reset_key_agreement();
crypto_load_master_secret(STATE.key_space); crypto_load_master_secret(STATE.key_space);
} }
void lock_device_permanently() {
memset(PIN_TOKEN, 0, sizeof(PIN_TOKEN));
memset(STATE.PIN_CODE_HASH, 0, sizeof(STATE.PIN_CODE_HASH));
printf1(TAG_CP, "Device locked!\n");
authenticator_write_state(&STATE, 0);
authenticator_write_state(&STATE, 1);
}

View File

@ -131,7 +131,7 @@
#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 #define CTAP2_UP_DELAY_MS 5000
typedef struct typedef struct
{ {
@ -359,6 +359,5 @@ uint16_t ctap_key_len(uint8_t index);
extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE]; extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
extern uint8_t KEY_AGREEMENT_PUB[64]; extern uint8_t KEY_AGREEMENT_PUB[64];
void lock_device_permanently();
#endif #endif

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

@ -715,7 +715,6 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
CborValue it,map; CborValue it,map;
memset(MC, 0, sizeof(CTAP_makeCredential)); memset(MC, 0, sizeof(CTAP_makeCredential));
MC->up = 0xff;
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it); ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_retr(ret); check_retr(ret);
@ -1011,7 +1010,6 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
memset(GA, 0, sizeof(CTAP_getAssertion)); memset(GA, 0, sizeof(CTAP_getAssertion));
GA->creds = getAssertionState.creds; // Save stack memory GA->creds = getAssertionState.creds; // Save stack memory
GA->up = 0xff;
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it); ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret); check_ret(ret);

View File

@ -16,7 +16,6 @@
#include "util.h" #include "util.h"
#include "log.h" #include "log.h"
#include "extensions.h" #include "extensions.h"
#include "version.h"
// move custom SHA512 command out, // move custom SHA512 command out,
// and the following headers too // and the following headers too
@ -730,22 +729,155 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
is_busy = 0; is_busy = 0;
break; break;
#endif #endif
#if defined(SOLO_HACKER) && (DEBUG_LEVEL > 0) && (!IS_BOOTLOADER == 1)
case CTAPHID_PROBE:
case CTAPHID_GETVERSION: /*
printf1(TAG_HID,"CTAPHID_GETVERSION\n"); * 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); ctap_response_init(&ctap_resp);
// initialise write buffer
ctaphid_write_buffer_init(&wb); ctaphid_write_buffer_init(&wb);
wb.cid = cid; wb.cid = cid;
wb.cmd = CTAPHID_GETVERSION; wb.cmd = CTAPHID_PROBE;
wb.bcnt = 3;
ctap_buffer[0] = SOLO_VERSION_MAJ; // prepare parsing (or halt)
ctap_buffer[1] = SOLO_VERSION_MIN; int ret;
ctap_buffer[2] = SOLO_VERSION_PATCH; CborParser parser;
ctaphid_write(&wb, &ctap_buffer, 3); 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); ctaphid_write(&wb, NULL, 0);
is_busy = 0; is_busy = 0;
break; break;
/*
case CTAPHID_SHA256:
// some random logging
printf1(TAG_HID,"CTAPHID_SHA256\n");
// initialise CTAP response object
ctap_response_init(&ctap_resp);
// initialise write buffer
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_SHA256;
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
// calculate hash
crypto_sha256_init();
crypto_sha256_update(ctap_buffer, buffer_len());
crypto_sha256_final(ctap_buffer);
// copy to output
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
case CTAPHID_SHA512:
// some random logging
printf1(TAG_HID,"CTAPHID_SHA512\n");
// initialise CTAP response object
ctap_response_init(&ctap_resp);
// initialise write buffer
ctaphid_write_buffer_init(&wb);
wb.cid = cid;
wb.cmd = CTAPHID_SHA512;
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
// calculate hash
crypto_sha512_init();
crypto_sha512_update(ctap_buffer, buffer_len());
crypto_sha512_final(ctap_buffer);
// copy to output
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
ctaphid_write(&wb, NULL, 0);
is_busy = 0;
break;
*/
#endif
default: 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());
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND); ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);

View File

@ -28,7 +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)
#define CTAPHID_GETVERSION (TYPE_INIT | 0x61)
// reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0 // reserved for debug, not implemented except for HACKER and DEBUG_LEVEl > 0
#define CTAPHID_PROBE (TYPE_INIT | 0x70) #define CTAPHID_PROBE (TYPE_INIT | 0x70)

View File

@ -1,91 +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.
#include "data_migration.h"
#include "log.h"
#include "device.h"
#include "crypto.h"
// TODO move from macro to function/assert for better readability?
#define check(x) assert(state_prev_0xff->x == state_tmp_ptr->x);
#define check_buf(x) assert(memcmp(state_prev_0xff->x, state_tmp_ptr->x, sizeof(state_tmp_ptr->x)) == 0);
bool migrate_from_FF_to_01(AuthenticatorState_0xFF* state_prev_0xff, AuthenticatorState_0x01* state_tmp_ptr){
// Calculate PIN hash, and replace PIN raw storage with it; add version to structure
// other ingredients do not change
if (state_tmp_ptr->data_version != 0xFF)
return false;
static_assert(sizeof(AuthenticatorState_0xFF) <= sizeof(AuthenticatorState_0x01), "New state structure is smaller, than current one, which is not handled");
if (ctap_generate_rng(state_tmp_ptr->PIN_SALT, sizeof(state_tmp_ptr->PIN_SALT)) != 1) {
printf2(TAG_ERR, "Error, rng failed\n");
return false;
}
if (state_prev_0xff->is_pin_set){
crypto_sha256_init();
crypto_sha256_update(state_prev_0xff->pin_code, state_prev_0xff->pin_code_length);
uint8_t intermediateHash[32];
crypto_sha256_final(intermediateHash);
crypto_sha256_init();
crypto_sha256_update(intermediateHash, 16);
memset(intermediateHash, 0, sizeof(intermediateHash));
crypto_sha256_update(state_tmp_ptr->PIN_SALT, sizeof(state_tmp_ptr->PIN_SALT));
crypto_sha256_final(state_tmp_ptr->PIN_CODE_HASH);
}
assert(state_tmp_ptr->_reserved == state_prev_0xff->pin_code_length);
state_tmp_ptr->_reserved = 0xFF;
state_tmp_ptr->data_version = 1;
check(is_initialized);
check(is_pin_set);
check(remaining_tries);
check(rk_stored);
check_buf(key_lens);
check_buf(key_space);
assert(state_tmp_ptr->data_version != 0xFF);
return true;
}
void save_migrated_state(AuthenticatorState *state_tmp_ptr) {
memmove(&STATE, state_tmp_ptr, sizeof(AuthenticatorState));
authenticator_write_state(state_tmp_ptr, 0);
authenticator_write_state(state_tmp_ptr, 1);
}
void do_migration_if_required(AuthenticatorState* state_current){
// Currently handles only state structures with the same size, or bigger
// FIXME rework to raw buffers with fixed size to allow state structure size decrease
if(!state_current->is_initialized)
return;
AuthenticatorState state_tmp;
AuthenticatorState state_previous;
authenticator_read_state(&state_previous);
authenticator_read_state(&state_tmp);
if(state_current->data_version == 0xFF){
printf2(TAG_ERR, "Running migration\n");
bool success = migrate_from_FF_to_01((AuthenticatorState_0xFF *) &state_previous, &state_tmp);
if (!success){
printf2(TAG_ERR, "Failed migration from 0xFF to 1\n");
// FIXME discuss migration failure behavior
goto return_cleanup;
}
dump_hex1(TAG_ERR, (void*)&state_tmp, sizeof(state_tmp));
dump_hex1(TAG_ERR, (void*)&state_previous, sizeof(state_previous));
save_migrated_state(&state_tmp);
}
assert(state_current->data_version == STATE_VERSION);
return_cleanup:
memset(&state_tmp, 0, sizeof(AuthenticatorState));
memset(&state_previous, 0, sizeof(AuthenticatorState));
}

View File

@ -1,15 +0,0 @@
// Copyright 2019 SoloKeys Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
#ifndef FIDO2_PR_DATA_MIGRATION_H
#define FIDO2_PR_DATA_MIGRATION_H
#include "storage.h"
void do_migration_if_required(AuthenticatorState* state_current);
#endif //FIDO2_PR_DATA_MIGRATION_H

View File

@ -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 * );
@ -53,7 +52,7 @@ void device_set_status(uint32_t status);
int device_is_button_pressed(); int device_is_button_pressed();
// Test for user presence // Test for user presence
// Return 2 for disabled, 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); int ctap_user_presence_test(uint32_t delay);
// Generate @num bytes of random numbers to @dest // Generate @num bytes of random numbers to @dest
@ -106,7 +105,7 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param);
#define NFC_IS_AVAILABLE 2 #define NFC_IS_AVAILABLE 2
int device_is_nfc(); int device_is_nfc();
void device_disable_up(bool request_active); void request_from_nfc(bool request_active);
void device_init_button(); void device_init_button();

View File

@ -95,7 +95,7 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
if (ret != 0) if (ret != 0)
return ret; return ret;
// printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code); printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code);
break; break;
case CP_cmdChangePin: case CP_cmdChangePin:

View File

@ -50,7 +50,6 @@ struct logtag tagtable[] = {
{TAG_EXT,"EXT"}, {TAG_EXT,"EXT"},
{TAG_NFC,"NFC"}, {TAG_NFC,"NFC"},
{TAG_NFC_APDU, "NAPDU"}, {TAG_NFC_APDU, "NAPDU"},
{TAG_CCID, "CCID"},
}; };

View File

@ -44,7 +44,6 @@ typedef enum
TAG_EXT = (1 << 18), TAG_EXT = (1 << 18),
TAG_NFC = (1 << 19), TAG_NFC = (1 << 19),
TAG_NFC_APDU = (1 << 20), TAG_NFC_APDU = (1 << 20),
TAG_CCID = (1 << 21),
TAG_NO_TAG = (1UL << 30), TAG_NO_TAG = (1UL << 30),
TAG_FILENO = (1UL << 31) TAG_FILENO = (1UL << 31)

View File

@ -46,7 +46,6 @@ int main(int argc, char *argv[])
TAG_GREEN| TAG_GREEN|
TAG_RED| TAG_RED|
TAG_EXT| TAG_EXT|
TAG_CCID|
TAG_ERR TAG_ERR
); );

View File

@ -11,9 +11,6 @@
#define KEY_SPACE_BYTES 128 #define KEY_SPACE_BYTES 128
#define MAX_KEYS (1) #define MAX_KEYS (1)
#define PIN_SALT_LEN (32)
#define STATE_VERSION (1)
#define BACKUP_MARKER 0x5A #define BACKUP_MARKER 0x5A
#define INITIALIZED_MARKER 0xA5 #define INITIALIZED_MARKER 0xA5
@ -22,40 +19,20 @@
#define ERR_KEY_SPACE_TAKEN (-2) #define ERR_KEY_SPACE_TAKEN (-2)
#define ERR_KEY_SPACE_EMPTY (-2) #define ERR_KEY_SPACE_EMPTY (-2)
typedef struct
{
// Pin information
uint8_t is_initialized;
uint8_t is_pin_set;
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
int pin_code_length;
int8_t remaining_tries;
uint16_t rk_stored;
uint16_t key_lens[MAX_KEYS];
uint8_t key_space[KEY_SPACE_BYTES];
} AuthenticatorState_0xFF;
typedef struct typedef struct
{ {
// Pin information // Pin information
uint8_t is_initialized; uint8_t is_initialized;
uint8_t is_pin_set; uint8_t is_pin_set;
uint8_t PIN_CODE_HASH[32]; uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
uint8_t PIN_SALT[PIN_SALT_LEN]; int pin_code_length;
int _reserved;
int8_t remaining_tries; int8_t remaining_tries;
uint16_t rk_stored; uint16_t rk_stored;
uint16_t key_lens[MAX_KEYS]; uint16_t key_lens[MAX_KEYS];
uint8_t key_space[KEY_SPACE_BYTES]; uint8_t key_space[KEY_SPACE_BYTES];
uint8_t data_version; } AuthenticatorState;
} AuthenticatorState_0x01;
typedef AuthenticatorState_0x01 AuthenticatorState;
typedef struct typedef struct

View File

@ -118,9 +118,9 @@ void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONS
if (!header) if (!header)
return; return;
device_disable_up(true); // disable presence test request_from_nfc(true); // disable presence test
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp); u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
device_disable_up(false); // enable presence test request_from_nfc(false); // enable presence test
} }
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)

View File

@ -26,7 +26,6 @@
#define RK_NUM 50 #define RK_NUM 50
bool use_udp = true; bool use_udp = true;
static bool _up_disabled = false;
struct ResidentKeyStore { struct ResidentKeyStore {
CTAP_residentKey rks[RK_NUM]; CTAP_residentKey rks[RK_NUM];
@ -44,11 +43,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()
{ {
@ -300,10 +295,6 @@ void ctaphid_write_block(uint8_t * data)
int ctap_user_presence_test(uint32_t d) int ctap_user_presence_test(uint32_t d)
{ {
if (_up_disabled)
{
return 2;
}
return 1; return 1;
} }
@ -637,13 +628,3 @@ int device_is_nfc()
{ {
return 0; return 0;
} }
void device_disable_up(bool disable)
{
_up_disabled = disable;
}
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
{
}

View File

@ -10,7 +10,6 @@ SRC += $(DRIVER_LIBS) $(USB_LIB)
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c SRC += ../../fido2/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/data_migration.c
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
SRC += ../../fido2/extensions/wallet.c SRC += ../../fido2/extensions/wallet.c

View File

@ -10,8 +10,7 @@ DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_
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,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,33 +26,18 @@ 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_CLASSES 2
#define CCID_SIZE 84 #define NUM_INTERFACES 3
#define CCID_NUM_INTERFACE 1
#if NUM_INTERFACES>1
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90 + 8+9 + 4)
#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 CDC_SIZE (49 + 8 + 9 + 4)
#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 HID_INTF_NUM 0
#define CDC_MASTER_INTF_NUM 1 #define CDC_MASTER_INTF_NUM 1
#define CDC_SLAVE_INTF_NUM 2 #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*/
@ -111,7 +94,7 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
0x00, 0x00,
HID_BINTERVAL, /*bInterval: Polling Interval */ HID_BINTERVAL, /*bInterval: Polling Interval */
#if DEBUG_LEVEL > 0 #if NUM_INTERFACES > 1
/* */ /* */
/* CDC */ /* CDC */
@ -208,83 +191,6 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
0x09, 0x09,
0x04, 0x04,
#endif #endif
#ifdef ENABLE_CCID
/* CCID Interface Descriptor */
9, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
CCID_INTF_NUM, /* bInterfaceNumber: CCID Interface */
0, /* Alternate setting for this interface */
3, /* bNumEndpoints: Bulk-IN, Bulk-OUT, Intr-IN */
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
}; };
USBD_ClassTypeDef USBD_Composite = USBD_ClassTypeDef USBD_Composite =
@ -305,21 +211,15 @@ 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 *hid_class, USBD_ClassTypeDef *cdc_class) {
memset(USBD_Classes, 0 , sizeof(USBD_Classes));
USBD_Classes[0] = hid_class; USBD_Classes[0] = hid_class;
#ifdef ENABLE_CCID USBD_Classes[1] = cdc_class;
USBD_Classes[1] = ccid_class;
#endif
#if DEBUG_LEVEL > 0
USBD_Classes[2] = cdc_class;
#endif
} }
static USBD_ClassTypeDef * getClass(uint8_t index) static USBD_ClassTypeDef * getClass(uint8_t index)
@ -328,15 +228,9 @@ static USBD_ClassTypeDef * getClass(uint8_t index)
{ {
case HID_INTF_NUM: case HID_INTF_NUM:
return USBD_Classes[0]; 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_MASTER_INTF_NUM:
case CDC_SLAVE_INTF_NUM: case CDC_SLAVE_INTF_NUM:
return USBD_Classes[2]; return USBD_Classes[1];
#endif
} }
return NULL; return NULL;
} }
@ -344,18 +238,18 @@ static USBD_ClassTypeDef * getClass(uint8_t index)
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_CLASSES; 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_CLASSES; 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;
} }
} }
@ -381,7 +275,7 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
case USB_REQ_GET_DESCRIPTOR : case USB_REQ_GET_DESCRIPTOR :
for(i = 0; i < NUM_CLASSES; i++) { for(i = 0; i < NUM_CLASSES; 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;
} }
} }
@ -404,8 +298,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,8 +306,6 @@ 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);
} }
@ -423,7 +313,7 @@ static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t 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_CLASSES; 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 +323,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 +353,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

@ -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

View File

@ -282,11 +282,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

@ -45,7 +45,7 @@ uint32_t __last_update = 0;
extern PCD_HandleTypeDef hpcd; extern PCD_HandleTypeDef hpcd;
static int _NFC_status = 0; static int _NFC_status = 0;
static bool isLowFreq = 0; static bool isLowFreq = 0;
static bool _up_disabled = false; 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() static int is_physical_button_pressed()
@ -55,45 +55,13 @@ static int is_physical_button_pressed()
static int is_touch_button_pressed() static int is_touch_button_pressed()
{ {
int is_pressed = (tsc_read_button(0) || tsc_read_button(1)); return 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; int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
static void edge_detect_touch_button() void request_from_nfc(bool request_active) {
{ _RequestComeFromNFC = request_active;
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 device_disable_up(bool disable) {
_up_disabled = disable;
} }
// Timer6 overflow handler. happens every ~90ms. // Timer6 overflow handler. happens every ~90ms.
@ -110,7 +78,19 @@ void TIM6_DAC_IRQHandler()
} }
} }
edge_detect_touch_button();
if (is_touch_button_pressed == IS_BUTTON_PRESSED)
{
if (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();
}
}
#ifndef IS_BOOTLOADER #ifndef IS_BOOTLOADER
// NFC sending WTX if needs // NFC sending WTX if needs
@ -162,6 +142,7 @@ void device_set_status(uint32_t status)
int device_is_button_pressed() int device_is_button_pressed()
{ {
return IS_BUTTON_PRESSED(); return IS_BUTTON_PRESSED();
} }
@ -582,17 +563,11 @@ static int wait_for_button_release(uint32_t wait)
int ctap_user_presence_test(uint32_t up_delay) int ctap_user_presence_test(uint32_t up_delay)
{ {
int ret; int ret;
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
if (device_is_nfc() == NFC_IS_ACTIVE)
{ {
return 1; return 1;
} }
if (_up_disabled)
{
return 2;
}
#if SKIP_BUTTON_CHECK_WITH_DELAY #if SKIP_BUTTON_CHECK_WITH_DELAY
int i=500; int i=500;
while(i--) while(i--)

View File

@ -28,7 +28,6 @@
#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_composite.h" #include "usbd_composite.h"
#include "usbd_cdc_if.h" #include "usbd_cdc_if.h"
#include "device.h" #include "device.h"
@ -706,26 +705,26 @@ void init_usb()
// Enable USB Clock // Enable USB Clock
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN); SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN);
#ifndef IS_BOOTLOADER
USBD_Composite_Set_Classes(&USBD_HID, &USBD_CCID, &USBD_CDC); #if DEBUG_LEVEL > 0
USBD_Composite_Set_Classes(&USBD_HID, &USBD_CDC);
in_endpoint_to_class[HID_EPIN_ADDR & 0x7F] = 0; in_endpoint_to_class[HID_EPIN_ADDR & 0x7F] = 0;
out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0; out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0;
in_endpoint_to_class[CCID_IN_EP & 0x7F] = 1; in_endpoint_to_class[CDC_IN_EP & 0x7F] = 1;
out_endpoint_to_class[CCID_OUT_EP & 0x7F] = 1; out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 1;
in_endpoint_to_class[CDC_IN_EP & 0x7F] = 2;
out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 2;
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0); USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
USBD_RegisterClass(&Solo_USBD_Device, &USBD_Composite); USBD_RegisterClass(&Solo_USBD_Device, &USBD_Composite);
#if DEBUG_LEVEL > 0 // USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
//
// USBD_RegisterClass(&Solo_USBD_Device, &USBD_CDC);
USBD_CDC_RegisterInterface(&Solo_USBD_Device, &USBD_Interface_fops_FS); USBD_CDC_RegisterInterface(&Solo_USBD_Device, &USBD_Interface_fops_FS);
#endif
#else #else
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0); USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID); USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
#endif #endif
USBD_Start(&Solo_USBD_Device); USBD_Start(&Solo_USBD_Device);
} }

View File

@ -14,23 +14,6 @@
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN)) #define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
// chain buffer for 61XX responses
static uint8_t chain_buffer[2048] = {0};
static size_t chain_buffer_len = 0;
static bool chain_buffer_tx = false;
static uint8_t current_cid = 0;
// forward declarations
void rblock_acknowledge(uint8_t req0, bool ack);
uint8_t p14443_have_cid(uint8_t pcb) {
// CID
if (pcb & 0x08)
return true;
else
return false;
}
uint8_t p14443_block_offset(uint8_t pcb) { uint8_t p14443_block_offset(uint8_t pcb) {
uint8_t offset = 1; uint8_t offset = 1;
// NAD following // NAD following
@ -203,7 +186,7 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r
return false; return false;
res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f); res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f);
res[1] = current_cid; res[1] = 0;
res[2] = 0; res[2] = 0;
uint8_t block_offset = p14443_block_offset(req0); uint8_t block_offset = p14443_block_offset(req0);
@ -213,14 +196,7 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r
res[len + block_offset + 0] = resp >> 8; res[len + block_offset + 0] = resp >> 8;
res[len + block_offset + 1] = resp & 0xff; res[len + block_offset + 1] = resp & 0xff;
nfc_write_frame(res, block_offset + len + 2); nfc_write_frame(res, block_offset + len + 2);
if (!ams_wait_for_tx(1))
{
printf1(TAG_NFC, "TX resp timeout. len: %d \r\n", len);
return false;
}
return true; return true;
} }
@ -230,7 +206,7 @@ bool nfc_write_response(uint8_t req0, uint16_t resp)
return nfc_write_response_ex(req0, NULL, 0, resp); return nfc_write_response_ex(req0, NULL, 0, resp);
} }
void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len) void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
{ {
uint8_t res[32 + 2]; uint8_t res[32 + 2];
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f); uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f);
@ -240,8 +216,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
{ {
uint8_t res[32] = {0}; uint8_t res[32] = {0};
res[0] = iBlock; res[0] = iBlock;
res[1] = current_cid;
res[2] = 0;
if (len && data) if (len && data)
memcpy(&res[block_offset], data, len); memcpy(&res[block_offset], data, len);
nfc_write_frame(res, len + block_offset); nfc_write_frame(res, len + block_offset);
@ -251,7 +225,7 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
// transmit I block // transmit I block
int vlen = MIN(32 - block_offset, len - sendlen); int vlen = MIN(32 - block_offset, len - sendlen);
res[0] = iBlock; res[0] = iBlock;
res[1] = current_cid; res[1] = 0;
res[2] = 0; res[2] = 0;
memcpy(&res[block_offset], &data[sendlen], vlen); memcpy(&res[block_offset], &data[sendlen], vlen);
@ -282,20 +256,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
printf1(TAG_NFC, "R block RX timeout %d/%d.\r\n",sendlen,len); printf1(TAG_NFC, "R block RX timeout %d/%d.\r\n",sendlen,len);
break; break;
} }
if (!IS_RBLOCK(recbuf[0]))
{
printf1(TAG_NFC, "R block RX error. Not a R block(0x%02x) %d/%d.\r\n", recbuf[0], sendlen, len);
break;
}
// NAK check
if (recbuf[0] & NFC_CMD_RBLOCK_ACK)
{
rblock_acknowledge(recbuf[0], true);
printf1(TAG_NFC, "R block RX error. NAK received. %d/%d.\r\n", recbuf[0], sendlen, len);
break;
}
uint8_t rblock_offset = p14443_block_offset(recbuf[0]); uint8_t rblock_offset = p14443_block_offset(recbuf[0]);
if (reclen != rblock_offset) if (reclen != rblock_offset)
@ -317,38 +277,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
} }
} }
void append_get_response(uint8_t *data, size_t rest_len)
{
data[0] = 0x61;
data[1] = 0x00;
if (rest_len <= 0xff)
data[1] = rest_len & 0xff;
}
void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len, bool extapdu)
{
chain_buffer_len = 0;
chain_buffer_tx = true;
// if we dont need to break data to parts that need to exchange via GET RESPONSE command (ISO 7816-4 7.1.3)
if (len <= 255 || extapdu)
{
nfc_write_response_chaining_plain(req0, data, len);
} else {
size_t pcklen = MIN(253, len);
chain_buffer_len = len - pcklen;
printf1(TAG_NFC, "61XX chaining %d/%d.\r\n", pcklen, chain_buffer_len);
memmove(chain_buffer, data, pcklen);
append_get_response(&chain_buffer[pcklen], chain_buffer_len);
nfc_write_response_chaining_plain(req0, chain_buffer, pcklen + 2); // 2 for 61XX
// put the rest data into chain buffer
memmove(chain_buffer, &data[pcklen], chain_buffer_len);
}
}
// WTX on/off: // WTX on/off:
// sends/receives WTX frame to reader every `WTX_time` time in ms // sends/receives WTX frame to reader every `WTX_time` time in ms
// works via timer interrupts // works via timer interrupts
@ -494,9 +422,7 @@ void rblock_acknowledge(uint8_t req0, bool ack)
NFC_STATE.block_num = !NFC_STATE.block_num; NFC_STATE.block_num = !NFC_STATE.block_num;
buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f); buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f);
buf[1] = current_cid; if (ack)
// iso14443-4:2001 page 16. ACK, if bit is set to 0, NAK, if bit is set to 1
if (!ack)
buf[0] |= NFC_CMD_RBLOCK_ACK; buf[0] |= NFC_CMD_RBLOCK_ACK;
nfc_write_frame(buf, block_offset); nfc_write_frame(buf, block_offset);
@ -550,70 +476,37 @@ int select_applet(uint8_t * aid, int len)
return APP_NOTHING; return APP_NOTHING;
} }
void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu) void nfc_process_iblock(uint8_t * buf, int len)
{ {
int selected; int selected;
CTAP_RESPONSE ctap_resp; CTAP_RESPONSE ctap_resp;
int status; int status;
uint16_t reslen; uint16_t reslen;
printf1(TAG_NFC,"Iblock: ");
dump_hex1(TAG_NFC, buf, len);
uint8_t block_offset = p14443_block_offset(buf[0]);
APDU_STRUCT apdu;
if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) {
printf1(TAG_NFC,"apdu decode error\r\n");
nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED);
return;
}
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
// check CLA // check CLA
if (apdu->cla != 0x00 && apdu->cla != 0x80) { if (apdu.cla != 0x00 && apdu.cla != 0x80) {
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu->cla); printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla);
nfc_write_response(buf0, SW_CLA_INVALID); nfc_write_response(buf[0], SW_CLA_INVALID);
return; return;
} }
// TODO this needs to be organized better // TODO this needs to be organized better
switch(apdu->ins) switch(apdu.ins)
{ {
// ISO 7816. 7.1 GET RESPONSE command
case APDU_GET_RESPONSE:
if (apdu->p1 != 0x00 || apdu->p2 != 0x00)
{
nfc_write_response(buf0, SW_INCORRECT_P1P2);
printf1(TAG_NFC, "P1 or P2 error\r\n");
return;
}
// too many bytes needs. 0x00 and 0x100 - any length
if (apdu->le != 0 && apdu->le != 0x100 && apdu->le > chain_buffer_len)
{
uint16_t wlresp = SW_WRONG_LENGTH; // here can be 6700, 6C00, 6FXX. but the most standard way - 67XX or 6700
if (chain_buffer_len <= 0xff)
wlresp += chain_buffer_len & 0xff;
nfc_write_response(buf0, wlresp);
printf1(TAG_NFC, "buffer length less than requesteds\r\n");
return;
}
// create temporary packet
uint8_t pck[255] = {0};
size_t pcklen = 253;
if (apdu->le)
pcklen = apdu->le;
if (pcklen > chain_buffer_len)
pcklen = chain_buffer_len;
printf1(TAG_NFC, "GET RESPONSE. pck len: %d buffer len: %d\r\n", pcklen, chain_buffer_len);
// create packet and add 61XX there if we have another portion(s) of data
memmove(pck, chain_buffer, pcklen);
size_t dlen = 0;
if (chain_buffer_len - pcklen)
{
append_get_response(&pck[pcklen], chain_buffer_len - pcklen);
dlen = 2;
}
// send
nfc_write_response_chaining_plain(buf0, pck, pcklen + dlen); // dlen for 61XX
// shift the buffer
chain_buffer_len -= pcklen;
memmove(chain_buffer, &chain_buffer[pcklen], chain_buffer_len);
break;
case APDU_INS_SELECT: case APDU_INS_SELECT:
// if (apdu->p1 == 0 && apdu->p2 == 0x0c) // if (apdu->p1 == 0 && apdu->p2 == 0x0c)
// { // {
@ -629,49 +522,49 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
// } // }
// else // else
{ {
selected = select_applet(apdu->data, apdu->lc); selected = select_applet(apdu.data, apdu.lc);
if (selected == APP_FIDO) if (selected == APP_FIDO)
{ {
nfc_write_response_ex(buf0, (uint8_t *)"U2F_V2", 6, SW_SUCCESS); nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
printf1(TAG_NFC, "FIDO applet selected.\r\n"); printf1(TAG_NFC, "FIDO applet selected.\r\n");
} }
else if (selected != APP_NOTHING) else if (selected != APP_NOTHING)
{ {
nfc_write_response(buf0, SW_SUCCESS); nfc_write_response(buf[0], SW_SUCCESS);
printf1(TAG_NFC, "SELECTED %d\r\n", selected); printf1(TAG_NFC, "SELECTED %d\r\n", selected);
} }
else else
{ {
nfc_write_response(buf0, SW_FILE_NOT_FOUND); nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu->data, apdu->lc); printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc);
} }
} }
break; break;
case APDU_FIDO_U2F_VERSION: case APDU_FIDO_U2F_VERSION:
if (NFC_STATE.selected_applet != APP_FIDO) { if (NFC_STATE.selected_applet != APP_FIDO) {
nfc_write_response(buf0, SW_INS_INVALID); nfc_write_response(buf[0], SW_INS_INVALID);
break; break;
} }
printf1(TAG_NFC, "U2F GetVersion command.\r\n"); printf1(TAG_NFC, "U2F GetVersion command.\r\n");
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp); u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
break; break;
case APDU_FIDO_U2F_REGISTER: case APDU_FIDO_U2F_REGISTER:
if (NFC_STATE.selected_applet != APP_FIDO) { if (NFC_STATE.selected_applet != APP_FIDO) {
nfc_write_response(buf0, SW_INS_INVALID); nfc_write_response(buf[0], SW_INS_INVALID);
break; break;
} }
printf1(TAG_NFC, "U2F Register command.\r\n"); printf1(TAG_NFC, "U2F Register command.\r\n");
if (apdu->lc != 64) if (apdu.lc != 64)
{ {
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu->lc); printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc);
nfc_write_response(buf0, SW_WRONG_LENGTH); nfc_write_response(buf[0], SW_WRONG_LENGTH);
return; return;
} }
@ -682,61 +575,61 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
// SystemClock_Config_LF32(); // SystemClock_Config_LF32();
// delay(300); // delay(300);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST); if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp); u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE); if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
// if (!WTX_off()) // if (!WTX_off())
// return; // return;
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp()); printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
break; break;
case APDU_FIDO_U2F_AUTHENTICATE: case APDU_FIDO_U2F_AUTHENTICATE:
if (NFC_STATE.selected_applet != APP_FIDO) { if (NFC_STATE.selected_applet != APP_FIDO) {
nfc_write_response(buf0, SW_INS_INVALID); nfc_write_response(buf[0], SW_INS_INVALID);
break; break;
} }
printf1(TAG_NFC, "U2F Authenticate command.\r\n"); printf1(TAG_NFC, "U2F Authenticate command.\r\n");
if (apdu->lc != 64 + 1 + apdu->data[64]) if (apdu.lc != 64 + 1 + apdu.data[64])
{ {
delay(5); delay(5);
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu->lc, apdu->data[64]); printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu.lc, apdu.data[64]);
nfc_write_response(buf0, SW_WRONG_LENGTH); nfc_write_response(buf[0], SW_WRONG_LENGTH);
return; return;
} }
timestamp(); timestamp();
// WTX_on(WTX_TIME_DEFAULT); // WTX_on(WTX_TIME_DEFAULT);
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp); u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
// if (!WTX_off()) // if (!WTX_off())
// return; // return;
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp());
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp); printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp);
break; break;
case APDU_FIDO_NFCCTAP_MSG: case APDU_FIDO_NFCCTAP_MSG:
if (NFC_STATE.selected_applet != APP_FIDO) { if (NFC_STATE.selected_applet != APP_FIDO) {
nfc_write_response(buf0, SW_INS_INVALID); nfc_write_response(buf[0], SW_INS_INVALID);
return; return;
} }
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp()); printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
// WTX_on(WTX_TIME_DEFAULT); WTX_on(WTX_TIME_DEFAULT);
device_disable_up(true); request_from_nfc(true);
ctap_response_init(&ctap_resp); ctap_response_init(&ctap_resp);
status = ctap_request(apdu->data, apdu->lc, &ctap_resp); status = ctap_request(apdu.data, apdu.lc, &ctap_resp);
device_disable_up(false); request_from_nfc(false);
// if (!WTX_off()) if (!WTX_off())
// return; return;
printf1(TAG_NFC, "CTAP resp: 0x%02x len: %d\r\n", status, ctap_resp.length); printf1(TAG_NFC, "CTAP resp: 0x%02x len: %d\r\n", status, ctap_resp.length);
@ -752,107 +645,44 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff; ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff;
printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp());
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp());
break; break;
case APDU_INS_READ_BINARY: case APDU_INS_READ_BINARY:
// response length // response length
reslen = apdu->le & 0xffff; reslen = apdu.le & 0xffff;
switch(NFC_STATE.selected_applet) switch(NFC_STATE.selected_applet)
{ {
case APP_CAPABILITY_CONTAINER: case APP_CAPABILITY_CONTAINER:
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n"); printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
if (reslen == 0 || reslen > sizeof(NFC_CC)) if (reslen == 0 || reslen > sizeof(NFC_CC))
reslen = sizeof(NFC_CC); reslen = sizeof(NFC_CC);
nfc_write_response_ex(buf0, (uint8_t *)&NFC_CC, reslen, SW_SUCCESS); nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS);
ams_wait_for_tx(10); ams_wait_for_tx(10);
break; break;
case APP_NDEF_TAG: case APP_NDEF_TAG:
printf1(TAG_NFC,"APP_NDEF_TAG\r\n"); printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1) if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1)
reslen = sizeof(NDEF_SAMPLE) - 1; reslen = sizeof(NDEF_SAMPLE) - 1;
nfc_write_response_ex(buf0, NDEF_SAMPLE, reslen, SW_SUCCESS); nfc_write_response_ex(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS);
ams_wait_for_tx(10); ams_wait_for_tx(10);
break; break;
default: default:
nfc_write_response(buf0, SW_FILE_NOT_FOUND); nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
printf1(TAG_ERR, "No binary applet selected!\r\n"); printf1(TAG_ERR, "No binary applet selected!\r\n");
return; return;
break; break;
} }
break; break;
case APDU_SOLO_RESET:
if (apdu->lc == 4 && !memcmp(apdu->data, "\x12\x56\xab\xf0", 4)) {
printf1(TAG_NFC, "Reset...\r\n");
nfc_write_response(buf0, SW_SUCCESS);
delay(20);
device_reboot();
while(1);
} else {
printf1(TAG_NFC, "Reset FAIL\r\n");
nfc_write_response(buf0, SW_INS_INVALID);
}
break;
default: default:
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins); printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins);
nfc_write_response(buf0, SW_INS_INVALID); nfc_write_response(buf[0], SW_INS_INVALID);
break; break;
} }
} }
void nfc_process_iblock(uint8_t * buf, int len)
{
uint8_t block_offset = p14443_block_offset(buf[0]);
// clear tx chain buffer if we have some other command than GET RESPONSE
if (chain_buffer_tx && buf[block_offset + 1] != APDU_GET_RESPONSE) {
chain_buffer_len = 0;
chain_buffer_tx = false;
}
APDU_STRUCT apdu;
uint16_t ret = apdu_decode(buf + block_offset, len - block_offset, &apdu);
if (ret != 0) {
printf1(TAG_NFC,"apdu decode error\r\n");
nfc_write_response(buf[0], ret);
return;
}
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
// APDU level chaining. ISO7816-4, 5.1.1. class byte
if (!chain_buffer_tx && buf[block_offset] & 0x10) {
if (chain_buffer_len + len > sizeof(chain_buffer)) {
nfc_write_response(buf[0], SW_WRONG_LENGTH);
return;
}
memmove(&chain_buffer[chain_buffer_len], apdu.data, apdu.lc);
chain_buffer_len += apdu.lc;
nfc_write_response(buf[0], SW_SUCCESS);
printf1(TAG_NFC, "APDU chaining ok. %d/%d\r\n", apdu.lc, chain_buffer_len);
return;
}
// if we have ISO 7816 APDU chain - move there all the data
if (!chain_buffer_tx && chain_buffer_len > 0) {
memmove(&apdu.data[chain_buffer_len], apdu.data, apdu.lc);
memmove(apdu.data, chain_buffer, chain_buffer_len);
apdu.lc += chain_buffer_len; // here apdu struct does not match with memory!
printf1(TAG_NFC, "APDU chaining merge. %d/%d\r\n", chain_buffer_len, apdu.lc);
}
apdu_process(buf[0], &buf[block_offset], &apdu);
printf1(TAG_NFC,"prev.Iblock: ");
dump_hex1(TAG_NFC, buf, len);
}
static uint8_t ibuf[1024]; static uint8_t ibuf[1024];
static int ibuflen = 0; static int ibuflen = 0;
@ -882,11 +712,9 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
else if (IS_IBLOCK(buf[0])) else if (IS_IBLOCK(buf[0]))
{ {
uint8_t block_offset = p14443_block_offset(buf[0]); uint8_t block_offset = p14443_block_offset(buf[0]);
if (p14443_have_cid(buf[0]))
current_cid = buf[1];
if (buf[0] & 0x10) if (buf[0] & 0x10)
{ {
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d offs=%d\r\n", ibuflen, len, block_offset); printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len);
if (ibuflen + len > sizeof(ibuf)) if (ibuflen + len > sizeof(ibuf))
{ {
printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf)); printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf));
@ -919,24 +747,21 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
memmove(ibuf, buf, block_offset); memmove(ibuf, buf, block_offset);
ibuflen += block_offset; ibuflen += block_offset;
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d offset=%d\r\n", ibuflen, len, block_offset); printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len);
printf1(TAG_NFC_APDU,"i> "); printf1(TAG_NFC_APDU,"i> ");
dump_hex1(TAG_NFC_APDU, buf, len); dump_hex1(TAG_NFC_APDU, buf, len);
nfc_process_iblock(ibuf, ibuflen); nfc_process_iblock(ibuf, ibuflen);
} else { } else {
memcpy(ibuf, buf, len); // because buf only 32b nfc_process_iblock(buf, len);
nfc_process_iblock(ibuf, len);
} }
clear_ibuf(); clear_ibuf();
} }
} }
else if (IS_RBLOCK(buf[0])) else if (IS_RBLOCK(buf[0]))
{ {
if (p14443_have_cid(buf[0])) rblock_acknowledge(buf[0], false);
current_cid = buf[1];
rblock_acknowledge(buf[0], true);
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n"); printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
} }
else if (IS_SBLOCK(buf[0])) else if (IS_SBLOCK(buf[0]))
@ -945,10 +770,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
if ((buf[0] & NFC_SBLOCK_DESELECT) == 0) if ((buf[0] & NFC_SBLOCK_DESELECT) == 0)
{ {
printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n"); printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n");
uint8_t block_offset = p14443_block_offset(buf[0]); nfc_write_frame(buf, 1);
if (p14443_have_cid(buf[0]))
current_cid = buf[1];
nfc_write_frame(buf, block_offset);
ams_wait_for_tx(2); ams_wait_for_tx(2);
ams_write_command(AMS_CMD_SLEEP); ams_write_command(AMS_CMD_SLEEP);
nfc_state_init(); nfc_state_init();
@ -1030,7 +852,6 @@ int nfc_loop()
printf1(TAG_NFC, "NFC_CMD_WUPA\r\n"); printf1(TAG_NFC, "NFC_CMD_WUPA\r\n");
break; break;
case NFC_CMD_HLTA: case NFC_CMD_HLTA:
ams_write_command(AMS_CMD_SLEEP);
printf1(TAG_NFC, "HLTA/Halt\r\n"); printf1(TAG_NFC, "HLTA/Halt\r\n");
break; break;
case NFC_CMD_RATS: case NFC_CMD_RATS:

View File

@ -34,9 +34,9 @@ typedef struct
#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS) #define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS)
#define NFC_CMD_IBLOCK 0x00 #define NFC_CMD_IBLOCK 0x00
#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) ) #define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) )
#define NFC_CMD_RBLOCK 0xa0 #define NFC_CMD_RBLOCK 0x80
#define NFC_CMD_RBLOCK_ACK 0x10 #define NFC_CMD_RBLOCK_ACK 0x20
#define IS_RBLOCK(x) ( (((x) & 0xe0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) ) #define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
#define NFC_CMD_SBLOCK 0xc0 #define NFC_CMD_SBLOCK 0xc0
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) ) #define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )