Compare commits
77 Commits
nfc_fido2_
...
2.5.3
Author | SHA1 | Date | |
---|---|---|---|
8c256298ae | |||
01b928c0ec | |||
018a4d394c | |||
7a75fba6d3 | |||
c61f15a090 | |||
f072561899 | |||
6652feb4a2 | |||
fc7ea68d4a | |||
cb116efcc9 | |||
80b9df3e04 | |||
194ef5edcf | |||
006117bb6b | |||
75c75fa897 | |||
2969d09ffa | |||
b871e10d08 | |||
18d39a7047 | |||
a9bbdee35b | |||
321bbe3691 | |||
1ce191343f | |||
9041e5903c | |||
689d471688 | |||
8b9e44c3ed | |||
83dd92d9ba | |||
8bf1921263 | |||
3ba9b671fc | |||
69c34f9ca9 | |||
3b4c154fd1 | |||
ccd9a04146 | |||
bde4c09c21 | |||
5d3914bc5e | |||
abe306a649 | |||
41ceb78f6c | |||
8e192f2363 | |||
affc256ca2 | |||
b3ac739a35 | |||
3b53537077 | |||
3fad9a7a7d | |||
8973608f59 | |||
8af6505f6d | |||
d39d7978fd | |||
c972a13034 | |||
a95e62e2ea | |||
c79b7abfb6 | |||
dfb124dc8b | |||
972760eb78 | |||
0d621d13f9 | |||
32f920e372 | |||
a5aff478dd | |||
728acc1671 | |||
62b4418dac | |||
8059a9765f | |||
b743d5fac5 | |||
dccfb0d1b3 | |||
a72f0ede05 | |||
adcbd3aeb8 | |||
d931954a13 | |||
b706cc30b0 | |||
57fe39704b | |||
4b6619b705 | |||
a5877f518f | |||
5a0cc0d02c | |||
b452e3dfe4 | |||
7f82233d17 | |||
8e3753e711 | |||
816ca21f08 | |||
6c60a37e8a | |||
ee351421cb | |||
bac576f3a0 | |||
6e637299e5 | |||
43b3e93854 | |||
5a448d636c | |||
7be0553377 | |||
a51417bf61 | |||
ba581db49c | |||
3a5cd786dc | |||
4fad28ea47 | |||
0ff9870612 |
@ -168,6 +168,25 @@
|
|||||||
"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,
|
||||||
|
@ -134,6 +134,8 @@ 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>
|
||||||
|
|
||||||
@ -167,7 +169,7 @@ You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solok
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
||||||
[](#contributors)
|
[](#contributors)
|
||||||
[](https://travis-ci.com/solokeys/solo)
|
[](https://travis-ci.com/solokeys/solo)
|
||||||
[](https://discourse.solokeys.com)
|
[](https://discourse.solokeys.com)
|
||||||
[](https://keybase.io/team/solokeys.public)
|
[](https://keybase.io/team/solokeys.public)
|
||||||
|
@ -1 +1 @@
|
|||||||
2.4.3
|
2.5.2
|
||||||
|
@ -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).
|
||||||
|
@ -85,14 +85,13 @@ 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),
|
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.
|
||||||
go to bottom page and from STM32CubeProg row select Download button.
|
2. Unzip contents of the archive.
|
||||||
2\. Unzip contents of the archive.
|
3. Run \*Linux setup
|
||||||
3\. Run \*Linux setup
|
4. In installation directory go to `./bin` - there the `./STM32_Programmer_CLI` is located
|
||||||
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`.
|
||||||
5\. Add symlink to the STM32 CLI binary to .local/bin. Make sure the latter it is in $PATH.
|
|
||||||
|
|
||||||
If you're on OsX and installed the STM32CubeProg, you need to add the following to your path:
|
If you're on MacOS X and installed the STM32CubeProg, you need to add the following to your path:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ~/.bash_profile
|
# ~/.bash_profile
|
||||||
|
@ -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 is can be better than a traditional
|
that leverages natural phenomenon to generate random numbers, which 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
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
# 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. (Under Fedora, your key may work without such a rule.)
|
On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed.
|
||||||
|
|
||||||
Create 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):
|
For some users, things will work automatically:
|
||||||
|
|
||||||
```
|
- Fedora seems to use a ["universal" udev rule for FIDO devices](https://github.com/amluto/u2f-hidraw-policy)
|
||||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", MODE="0660", GROUP="plugdev"
|
- Our udev rule made it into [libu2f-host](https://github.com/Yubico/libu2f-host/) v1.1.10
|
||||||
```
|
- Arch Linux [has this package](https://www.archlinux.org/packages/community/x86_64/libu2f-host/)
|
||||||
|
- [Debian sid](https://packages.debian.org/sid/libu2f-udev) and [Ubuntu Eon](https://packages.ubuntu.com/eoan/libu2f-udev) can use the `libu2f-udev` package
|
||||||
|
- Debian Buster and Ubuntu Disco still distribute v1.1.10, so need the manual rule
|
||||||
|
- FreeBSD has support in [u2f-devd](https://github.com/solokeys/solo/issues/144#issuecomment-500216020)
|
||||||
|
|
||||||
Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
|
There is hope that `udev` itself will adopt the Fedora approach (which is to check for HID usage page `F1D0`, and avoids manually whitelisting each U2F/FIDO2 key): <https://github.com/systemd/systemd/issues/11996>.
|
||||||
|
|
||||||
```
|
Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>.
|
||||||
sudo udevadm control --reload-rules && sudo udevadm trigger
|
|
||||||
```
|
|
||||||
|
|
||||||
A simple way to setup both the udev rule and the udevadm reload is:
|
If you still need to setup a rule, a simple way to do it is:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone git@github.com:solokeys/solo.git
|
git clone git@github.com:solokeys/solo.git
|
||||||
@ -22,9 +23,11 @@ cd solo/udev
|
|||||||
make setup
|
make setup
|
||||||
```
|
```
|
||||||
|
|
||||||
We are working on getting user access to Solo keys enabled automatically in common Linux distributions: <https://github.com/solokeys/solo/issues/144>.
|
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.
|
||||||
|
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
|
||||||
|
|
||||||
|
20
fido2/apdu.c
20
fido2/apdu.c
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
|
|
||||||
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
uint16_t 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;
|
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any
|
||||||
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,6 +62,11 @@ int 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)
|
||||||
@ -103,9 +108,18 @@ int 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)
|
||||||
{
|
{
|
||||||
|
@ -36,20 +36,26 @@ typedef struct
|
|||||||
uint8_t case_type;
|
uint8_t case_type;
|
||||||
} __attribute__((packed)) APDU_STRUCT;
|
} __attribute__((packed)) APDU_STRUCT;
|
||||||
|
|
||||||
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
|
extern uint16_t 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
|
||||||
|
@ -262,6 +262,11 @@ 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;
|
||||||
|
@ -26,6 +26,7 @@ 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();
|
||||||
|
172
fido2/ctap.c
172
fido2/ctap.c
@ -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,7 +256,9 @@ 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);
|
||||||
@ -435,7 +437,23 @@ 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);
|
||||||
return ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
int ret = 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)
|
||||||
@ -468,19 +486,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)
|
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
authData->head.flags = (0 << 0); // User presence disabled
|
||||||
}
|
}
|
||||||
else if (but < 0) // Cancel
|
else
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
check_retr(but);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
@ -664,7 +682,16 @@ 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:
|
||||||
make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
crypto_sha256_init();
|
||||||
|
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:
|
||||||
@ -705,10 +732,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
if (MC.pinAuthEmpty)
|
if (MC.pinAuthEmpty)
|
||||||
{
|
{
|
||||||
if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
check_retr( 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)
|
||||||
@ -731,7 +755,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MC.up)
|
if (MC.up == 1 || MC.up == 0)
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_INVALID_OPTION;
|
return CTAP2_ERR_INVALID_OPTION;
|
||||||
}
|
}
|
||||||
@ -1141,10 +1165,7 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
|
|
||||||
if (GA.pinAuthEmpty)
|
if (GA.pinAuthEmpty)
|
||||||
{
|
{
|
||||||
if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
check_retr( 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)
|
||||||
@ -1227,8 +1248,9 @@ 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);
|
||||||
@ -1286,11 +1308,13 @@ 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())
|
||||||
@ -1303,6 +1327,7 @@ 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();
|
||||||
@ -1325,6 +1350,7 @@ 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
|
||||||
@ -1334,7 +1360,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;
|
||||||
@ -1350,6 +1376,8 @@ 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())
|
||||||
@ -1362,7 +1390,14 @@ 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();
|
||||||
@ -1378,6 +1413,7 @@ 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;
|
||||||
@ -1397,12 +1433,16 @@ 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];
|
||||||
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
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)
|
||||||
{
|
{
|
||||||
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, PIN_CODE_HASH, 16);
|
printf2(TAG_ERR,"authentic-pin-hash: "); dump_hex1(TAG_ERR, STATE.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);
|
||||||
@ -1479,6 +1519,11 @@ 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);
|
||||||
|
|
||||||
@ -1649,14 +1694,11 @@ 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");
|
||||||
if (ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
status = 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");
|
||||||
@ -1678,7 +1720,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\n");
|
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@ -1708,8 +1750,18 @@ 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()
|
||||||
@ -1742,14 +1794,12 @@ 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
|
||||||
@ -1767,10 +1817,7 @@ void ctap_init()
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_is_nfc() != NFC_IS_ACTIVE)
|
ctap_reset_key_agreement();
|
||||||
{
|
|
||||||
ctap_reset_key_agreement();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BRIDGE_TO_WALLET
|
#ifdef BRIDGE_TO_WALLET
|
||||||
wallet_init();
|
wallet_init();
|
||||||
@ -1784,34 +1831,38 @@ 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.
|
||||||
return memcmp(pin, STATE.pin_code, len) == 0;
|
* Globals: STATE
|
||||||
}
|
* @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(STATE.pin_code, len);
|
crypto_sha256_update(pin, len);
|
||||||
crypto_sha256_final(PIN_CODE_HASH);
|
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.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\n", STATE.pin_code);
|
printf1(TAG_CTAP, "New pin set: %s [%d]\n", pin, len);
|
||||||
|
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()
|
||||||
@ -1828,9 +1879,7 @@ uint8_t ctap_decrement_pin_attempts()
|
|||||||
|
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
|
lock_device_permanently();
|
||||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
|
||||||
printf1(TAG_CP, "Device locked!\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1969,7 +2018,7 @@ int8_t ctap_load_key(uint8_t index, uint8_t * key)
|
|||||||
|
|
||||||
static void ctap_reset_key_agreement()
|
static void ctap_reset_key_agreement()
|
||||||
{
|
{
|
||||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
ctap_generate_rng(KEY_AGREEMENT_PRIV, sizeof(KEY_AGREEMENT_PRIV));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctap_reset()
|
void ctap_reset()
|
||||||
@ -1986,8 +2035,17 @@ 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);
|
||||||
|
}
|
||||||
|
@ -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 5000
|
#define CTAP2_UP_DELAY_MS 29000
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -359,5 +359,6 @@ 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
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#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
|
||||||
|
@ -715,6 +715,7 @@ 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);
|
||||||
|
|
||||||
@ -1010,6 +1011,7 @@ 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);
|
||||||
|
150
fido2/ctaphid.c
150
fido2/ctaphid.c
@ -16,6 +16,7 @@
|
|||||||
#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
|
||||||
@ -729,155 +730,22 @@ 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:
|
||||||
* Expects CBOR-serialized data of the form
|
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
|
||||||
* {"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_PROBE;
|
wb.cmd = CTAPHID_GETVERSION;
|
||||||
|
wb.bcnt = 3;
|
||||||
// prepare parsing (or halt)
|
ctap_buffer[0] = SOLO_VERSION_MAJ;
|
||||||
int ret;
|
ctap_buffer[1] = SOLO_VERSION_MIN;
|
||||||
CborParser parser;
|
ctap_buffer[2] = SOLO_VERSION_PATCH;
|
||||||
CborValue it, map;
|
ctaphid_write(&wb, &ctap_buffer, 3);
|
||||||
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);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#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)
|
||||||
|
|
||||||
|
91
fido2/data_migration.c
Normal file
91
fido2/data_migration.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// 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));
|
||||||
|
}
|
15
fido2/data_migration.h
Normal file
15
fido2/data_migration.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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
|
@ -30,6 +30,7 @@ void main_loop_delay();
|
|||||||
|
|
||||||
void heartbeat();
|
void heartbeat();
|
||||||
|
|
||||||
|
void device_reboot();
|
||||||
|
|
||||||
void authenticator_read_state(AuthenticatorState * );
|
void authenticator_read_state(AuthenticatorState * );
|
||||||
|
|
||||||
@ -52,7 +53,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 1 for user is present, 0 user not present, -1 if cancel is requested.
|
// Return 2 for disabled, 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
|
||||||
@ -105,7 +106,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 request_from_nfc(bool request_active);
|
void device_disable_up(bool request_active);
|
||||||
|
|
||||||
void device_init_button();
|
void device_init_button();
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -50,6 +50,7 @@ struct logtag tagtable[] = {
|
|||||||
{TAG_EXT,"[1;37mEXT[0m"},
|
{TAG_EXT,"[1;37mEXT[0m"},
|
||||||
{TAG_NFC,"[1;38mNFC[0m"},
|
{TAG_NFC,"[1;38mNFC[0m"},
|
||||||
{TAG_NFC_APDU, "NAPDU"},
|
{TAG_NFC_APDU, "NAPDU"},
|
||||||
|
{TAG_CCID, "CCID"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ 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)
|
||||||
|
@ -46,6 +46,7 @@ int main(int argc, char *argv[])
|
|||||||
TAG_GREEN|
|
TAG_GREEN|
|
||||||
TAG_RED|
|
TAG_RED|
|
||||||
TAG_EXT|
|
TAG_EXT|
|
||||||
|
TAG_CCID|
|
||||||
TAG_ERR
|
TAG_ERR
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
#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
|
||||||
@ -19,20 +22,40 @@
|
|||||||
#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[NEW_PIN_ENC_MIN_SIZE];
|
uint8_t PIN_CODE_HASH[32];
|
||||||
int pin_code_length;
|
uint8_t PIN_SALT[PIN_SALT_LEN];
|
||||||
|
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];
|
||||||
} AuthenticatorState;
|
uint8_t data_version;
|
||||||
|
} AuthenticatorState_0x01;
|
||||||
|
|
||||||
|
typedef AuthenticatorState_0x01 AuthenticatorState;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -118,9 +118,9 @@ void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONS
|
|||||||
if (!header)
|
if (!header)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
request_from_nfc(true); // disable presence test
|
device_disable_up(true); // disable presence test
|
||||||
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
||||||
request_from_nfc(false); // enable presence test
|
device_disable_up(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)
|
||||||
|
21
pc/device.c
21
pc/device.c
@ -26,6 +26,7 @@
|
|||||||
#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];
|
||||||
@ -43,7 +44,11 @@ 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()
|
||||||
{
|
{
|
||||||
@ -295,6 +300,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,3 +637,13 @@ 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ 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
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ 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)
|
||||||
|
319
targets/stm32l432/lib/usbd/usbd_ccid.c
Normal file
319
targets/stm32l432/lib/usbd/usbd_ccid.c
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
#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;
|
||||||
|
}
|
58
targets/stm32l432/lib/usbd/usbd_ccid.h
Normal file
58
targets/stm32l432/lib/usbd/usbd_ccid.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#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
|
@ -195,302 +195,9 @@ 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
|
||||||
@ -782,45 +489,7 @@ 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
|
||||||
@ -939,22 +608,10 @@ 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
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
#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);
|
||||||
|
|
||||||
@ -26,18 +28,33 @@ 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);
|
||||||
|
|
||||||
#define NUM_CLASSES 2
|
#ifdef ENABLE_CCID
|
||||||
#define NUM_INTERFACES 3
|
#define CCID_SIZE 84
|
||||||
|
#define CCID_NUM_INTERFACE 1
|
||||||
#if NUM_INTERFACES>1
|
|
||||||
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90 + 8+9 + 4)
|
|
||||||
#else
|
#else
|
||||||
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (41)
|
#define CCID_NUM_INTERFACE 0
|
||||||
|
#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*/
|
||||||
@ -94,7 +111,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 NUM_INTERFACES > 1
|
#if DEBUG_LEVEL > 0
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
/* CDC */
|
/* CDC */
|
||||||
@ -191,6 +208,83 @@ __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 =
|
||||||
@ -211,15 +305,21 @@ 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 *cdc_class) {
|
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *ccid_class, USBD_ClassTypeDef *cdc_class) {
|
||||||
|
memset(USBD_Classes, 0 , sizeof(USBD_Classes));
|
||||||
USBD_Classes[0] = hid_class;
|
USBD_Classes[0] = hid_class;
|
||||||
USBD_Classes[1] = cdc_class;
|
#ifdef ENABLE_CCID
|
||||||
|
USBD_Classes[1] = ccid_class;
|
||||||
|
#endif
|
||||||
|
#if DEBUG_LEVEL > 0
|
||||||
|
USBD_Classes[2] = cdc_class;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static USBD_ClassTypeDef * getClass(uint8_t index)
|
static USBD_ClassTypeDef * getClass(uint8_t index)
|
||||||
@ -228,9 +328,15 @@ 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[1];
|
return USBD_Classes[2];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -238,18 +344,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]->Init(pdev, cfgidx) != USBD_OK) {
|
if (USBD_Classes[i] != NULL && 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]->DeInit(pdev, cfgidx) != USBD_OK) {
|
if (USBD_Classes[i] != NULL && USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) {
|
||||||
return USBD_FAIL;
|
return USBD_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +381,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]->Setup(pdev, req) != USBD_OK) {
|
if (USBD_Classes[i] != NULL && USBD_Classes[i]->Setup(pdev, req) != USBD_OK) {
|
||||||
return USBD_FAIL;
|
return USBD_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,6 +404,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,6 +414,8 @@ 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -313,7 +423,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]->EP0_RxReady != NULL) {
|
if (USBD_Classes[i] != NULL && 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;
|
||||||
}
|
}
|
||||||
@ -323,16 +433,19 @@ 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;
|
||||||
}
|
}
|
||||||
@ -353,6 +466,7 @@ __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) {
|
||||||
*length = sizeof (USBD_Composite_DeviceQualifierDesc);
|
//N
|
||||||
return USBD_Composite_DeviceQualifierDesc;
|
*length = sizeof (USBD_Composite_DeviceQualifierDesc);
|
||||||
|
return USBD_Composite_DeviceQualifierDesc;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1, USBD_ClassTypeDef *class2);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,9 @@
|
|||||||
#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);
|
||||||
|
|
||||||
@ -117,9 +120,14 @@ 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_ENDPOINT:
|
case HID_EPOUT_ADDR:
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +226,6 @@ 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
|
||||||
@ -252,14 +259,20 @@ 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 , 0x01 , PCD_SNG_BUF, 0x98);
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR , PCD_SNG_BUF, 0x98);
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xd8);
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR , 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 , 0x02 , PCD_SNG_BUF, 0xd8 + 64); // data OUT
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_CMD_EP , PCD_SNG_BUF, 0xd8 + 64*4); // commands
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0xd8 + 64*2); // data IN
|
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 , 0x83 , PCD_SNG_BUF, 0xd8 + 64*3); // commands
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, 0xd8 + 64*6); // data IN
|
||||||
|
|
||||||
|
// dump_pma_header("usbd_conf");
|
||||||
|
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
@ -310,6 +323,7 @@ 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,
|
||||||
|
@ -12,9 +12,13 @@
|
|||||||
#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
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,6 +282,11 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -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 _RequestComeFromNFC = false;
|
static bool _up_disabled = 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,13 +55,45 @@ static int is_physical_button_pressed()
|
|||||||
|
|
||||||
static int is_touch_button_pressed()
|
static int is_touch_button_pressed()
|
||||||
{
|
{
|
||||||
return tsc_read_button(0) || tsc_read_button(1);
|
int is_pressed = (tsc_read_button(0) || tsc_read_button(1));
|
||||||
|
#ifndef IS_BOOTLOADER
|
||||||
|
if (is_pressed)
|
||||||
|
{
|
||||||
|
// delay for debounce, and longer than polling timer period.
|
||||||
|
delay(95);
|
||||||
|
return (tsc_read_button(0) || tsc_read_button(1));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return is_pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
|
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
|
||||||
|
|
||||||
void request_from_nfc(bool request_active) {
|
static void edge_detect_touch_button()
|
||||||
_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.
|
||||||
@ -78,19 +110,7 @@ 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
|
||||||
@ -142,7 +162,6 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,11 +582,17 @@ 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--)
|
||||||
|
@ -28,6 +28,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_composite.h"
|
#include "usbd_composite.h"
|
||||||
#include "usbd_cdc_if.h"
|
#include "usbd_cdc_if.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -705,26 +706,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
|
||||||
#if DEBUG_LEVEL > 0
|
USBD_Composite_Set_Classes(&USBD_HID, &USBD_CCID, &USBD_CDC);
|
||||||
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[CDC_IN_EP & 0x7F] = 1;
|
in_endpoint_to_class[CCID_IN_EP & 0x7F] = 1;
|
||||||
out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 1;
|
out_endpoint_to_class[CCID_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);
|
||||||
// USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
|
#if DEBUG_LEVEL > 0
|
||||||
//
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,23 @@
|
|||||||
|
|
||||||
#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
|
||||||
@ -186,7 +203,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] = 0;
|
res[1] = current_cid;
|
||||||
res[2] = 0;
|
res[2] = 0;
|
||||||
|
|
||||||
uint8_t block_offset = p14443_block_offset(req0);
|
uint8_t block_offset = p14443_block_offset(req0);
|
||||||
@ -213,7 +230,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(uint8_t req0, uint8_t * data, int len)
|
void nfc_write_response_chaining_plain(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);
|
||||||
@ -223,6 +240,8 @@ void nfc_write_response_chaining(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);
|
||||||
@ -232,7 +251,7 @@ void nfc_write_response_chaining(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] = 0;
|
res[1] = current_cid;
|
||||||
res[2] = 0;
|
res[2] = 0;
|
||||||
memcpy(&res[block_offset], &data[sendlen], vlen);
|
memcpy(&res[block_offset], &data[sendlen], vlen);
|
||||||
|
|
||||||
@ -263,6 +282,20 @@ void nfc_write_response_chaining(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)
|
||||||
@ -284,6 +317,38 @@ void nfc_write_response_chaining(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
|
||||||
@ -429,7 +494,9 @@ 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);
|
||||||
if (ack)
|
buf[1] = current_cid;
|
||||||
|
// 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);
|
||||||
@ -483,37 +550,70 @@ int select_applet(uint8_t * aid, int len)
|
|||||||
return APP_NOTHING;
|
return APP_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_process_iblock(uint8_t * buf, int len)
|
void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
||||||
{
|
{
|
||||||
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(buf[0], SW_CLA_INVALID);
|
nfc_write_response(buf0, 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)
|
||||||
// {
|
// {
|
||||||
@ -529,49 +629,49 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
|||||||
// }
|
// }
|
||||||
// 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(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
nfc_write_response_ex(buf0, (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(buf[0], SW_SUCCESS);
|
nfc_write_response(buf0, SW_SUCCESS);
|
||||||
printf1(TAG_NFC, "SELECTED %d\r\n", selected);
|
printf1(TAG_NFC, "SELECTED %d\r\n", selected);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
nfc_write_response(buf0, 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(buf[0], SW_INS_INVALID);
|
nfc_write_response(buf0, SW_INS_INVALID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
||||||
|
|
||||||
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp);
|
||||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
||||||
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(buf[0], SW_INS_INVALID);
|
nfc_write_response(buf0, 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(buf[0], SW_WRONG_LENGTH);
|
nfc_write_response(buf0, SW_WRONG_LENGTH);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,61 +682,61 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
|||||||
// 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(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
u2f_request_nfc(apduptr, 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(buf[0], ctap_resp.data, ctap_resp.length);
|
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
||||||
|
|
||||||
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(buf[0], SW_INS_INVALID);
|
nfc_write_response(buf0, 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(buf[0], SW_WRONG_LENGTH);
|
nfc_write_response(buf0, SW_WRONG_LENGTH);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp();
|
timestamp();
|
||||||
// WTX_on(WTX_TIME_DEFAULT);
|
// WTX_on(WTX_TIME_DEFAULT);
|
||||||
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
u2f_request_nfc(apduptr, 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(buf[0], ctap_resp.data, ctap_resp.length);
|
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
||||||
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(buf[0], SW_INS_INVALID);
|
nfc_write_response(buf0, 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);
|
||||||
request_from_nfc(true);
|
device_disable_up(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);
|
||||||
request_from_nfc(false);
|
device_disable_up(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);
|
||||||
|
|
||||||
@ -652,44 +752,107 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
|||||||
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(buf[0], ctap_resp.data, ctap_resp.length);
|
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
||||||
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(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS);
|
nfc_write_response_ex(buf0, (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(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS);
|
nfc_write_response_ex(buf0, NDEF_SAMPLE, reslen, SW_SUCCESS);
|
||||||
ams_wait_for_tx(10);
|
ams_wait_for_tx(10);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
nfc_write_response(buf0, 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(buf[0], SW_INS_INVALID);
|
nfc_write_response(buf0, 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;
|
||||||
|
|
||||||
@ -719,9 +882,11 @@ 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\r\n", ibuflen, len);
|
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d offs=%d\r\n", ibuflen, len, block_offset);
|
||||||
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));
|
||||||
@ -754,21 +919,24 @@ 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\r\n", ibuflen, len);
|
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,"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 {
|
||||||
nfc_process_iblock(buf, len);
|
memcpy(ibuf, buf, len); // because buf only 32b
|
||||||
|
nfc_process_iblock(ibuf, len);
|
||||||
}
|
}
|
||||||
clear_ibuf();
|
clear_ibuf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IS_RBLOCK(buf[0]))
|
else if (IS_RBLOCK(buf[0]))
|
||||||
{
|
{
|
||||||
rblock_acknowledge(buf[0], false);
|
if (p14443_have_cid(buf[0]))
|
||||||
|
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]))
|
||||||
@ -777,7 +945,10 @@ 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");
|
||||||
nfc_write_frame(buf, 1);
|
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||||
|
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();
|
||||||
|
@ -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 0x80
|
#define NFC_CMD_RBLOCK 0xa0
|
||||||
#define NFC_CMD_RBLOCK_ACK 0x20
|
#define NFC_CMD_RBLOCK_ACK 0x10
|
||||||
#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
|
#define IS_RBLOCK(x) ( (((x) & 0xe0) == 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) )
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user