Compare commits
5 Commits
fido2_on_u
...
nfc_fido2_
Author | SHA1 | Date | |
---|---|---|---|
525ff0c5d6 | |||
79d986197b | |||
9045c0ca3e | |||
508f2e1e1c | |||
6dfdf36654 |
@ -168,35 +168,6 @@
|
|||||||
"infra",
|
"infra",
|
||||||
"tool"
|
"tool"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "kimusan",
|
|
||||||
"name": "Kim Schulz",
|
|
||||||
"avatar_url": "https://avatars1.githubusercontent.com/u/1150049?v=4",
|
|
||||||
"profile": "http://www.schulz.dk",
|
|
||||||
"contributions": [
|
|
||||||
"business",
|
|
||||||
"ideas"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "oplik0",
|
|
||||||
"name": "Jakub",
|
|
||||||
"avatar_url": "https://avatars2.githubusercontent.com/u/25460763?v=4",
|
|
||||||
"profile": "https://github.com/oplik0",
|
|
||||||
"contributions": [
|
|
||||||
"bug"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "jolo1581",
|
|
||||||
"name": "Jan A.",
|
|
||||||
"avatar_url": "https://avatars1.githubusercontent.com/u/53423977?v=4",
|
|
||||||
"profile": "https://github.com/jolo1581",
|
|
||||||
"contributions": [
|
|
||||||
"code",
|
|
||||||
"doc"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
2
Makefile
2
Makefile
@ -39,7 +39,7 @@ INCLUDES += -I./crypto/cifra/src
|
|||||||
|
|
||||||
CFLAGS += $(INCLUDES)
|
CFLAGS += $(INCLUDES)
|
||||||
# for crypto/tiny-AES-c
|
# for crypto/tiny-AES-c
|
||||||
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\" -DSOLO_EXPERIMENTAL=1
|
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\"
|
||||||
|
|
||||||
name = main
|
name = main
|
||||||
|
|
||||||
|
@ -134,9 +134,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center"><a href="http://1bitsquared.com"><img src="https://avatars3.githubusercontent.com/u/17334?v=4" width="100px;" alt="Piotr Esden-Tempski"/><br /><sub><b>Piotr Esden-Tempski</b></sub></a><br /><a href="#business-esden" title="Business development">💼</a></td>
|
<td align="center"><a href="http://1bitsquared.com"><img src="https://avatars3.githubusercontent.com/u/17334?v=4" width="100px;" alt="Piotr Esden-Tempski"/><br /><sub><b>Piotr Esden-Tempski</b></sub></a><br /><a href="#business-esden" title="Business development">💼</a></td>
|
||||||
<td align="center"><a href="https://github.com/m3hm00d"><img src="https://avatars1.githubusercontent.com/u/42179593?v=4" width="100px;" alt="f.m3hm00d"/><br /><sub><b>f.m3hm00d</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=m3hm00d" title="Documentation">📖</a></td>
|
<td align="center"><a href="https://github.com/m3hm00d"><img src="https://avatars1.githubusercontent.com/u/42179593?v=4" width="100px;" alt="f.m3hm00d"/><br /><sub><b>f.m3hm00d</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=m3hm00d" title="Documentation">📖</a></td>
|
||||||
<td align="center"><a href="http://blogs.gnome.org/hughsie/"><img src="https://avatars0.githubusercontent.com/u/151380?v=4" width="100px;" alt="Richard Hughes"/><br /><sub><b>Richard Hughes</b></sub></a><br /><a href="#ideas-hughsie" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=hughsie" title="Code">💻</a> <a href="#infra-hughsie" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#tool-hughsie" title="Tools">🔧</a></td>
|
<td align="center"><a href="http://blogs.gnome.org/hughsie/"><img src="https://avatars0.githubusercontent.com/u/151380?v=4" width="100px;" alt="Richard Hughes"/><br /><sub><b>Richard Hughes</b></sub></a><br /><a href="#ideas-hughsie" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=hughsie" title="Code">💻</a> <a href="#infra-hughsie" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#tool-hughsie" title="Tools">🔧</a></td>
|
||||||
<td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center"><a href="https://github.com/jolo1581"><img src="https://avatars1.githubusercontent.com/u/53423977?v=4" width="100px;" alt="Jan A."/><br /><sub><b>Jan A.</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Code">💻</a> <a href="https://github.com/solokeys/solo/commits?author=jolo1581" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -170,7 +167,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.5.3
|
2.4.3
|
||||||
|
@ -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,13 +85,14 @@ brew install arm-none-eabi-gcc
|
|||||||
### Install flashing software
|
### Install flashing software
|
||||||
|
|
||||||
ST provides a CLI flashing tool - `STM32_Programmer_CLI`. It can be downloaded directly from the vendor's site:
|
ST provides a CLI flashing tool - `STM32_Programmer_CLI`. It can be downloaded directly from the vendor's site:
|
||||||
1. Go to [download site URL](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html), go to bottom page and from STM32CubeProg row select Download button.
|
1\. Go to [download site URL](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html),
|
||||||
2. Unzip contents of the archive.
|
go to bottom page and from STM32CubeProg row select Download button.
|
||||||
3. Run \*Linux setup
|
2\. Unzip contents of the archive.
|
||||||
4. In installation directory go to `./bin` - there the `./STM32_Programmer_CLI` is located
|
3\. Run \*Linux setup
|
||||||
5. Add symlink to the STM32 CLI binary to `.local/bin`. Make sure the latter it is in `$PATH`.
|
4\. In installation directory go to ./bin - there the ./STM32_Programmer_CLI is located
|
||||||
|
5\. Add symlink to the STM32 CLI binary to .local/bin. Make sure the latter it is in $PATH.
|
||||||
|
|
||||||
If you're on MacOS X and installed the STM32CubeProg, you need to add the following to your path:
|
If you're on OsX and installed the STM32CubeProg, you need to add the following to your path:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ~/.bash_profile
|
# ~/.bash_profile
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
## Random number generation
|
## Random number generation
|
||||||
|
|
||||||
Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism
|
Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism
|
||||||
that leverages natural phenomenon to generate random numbers, which can be better than a traditional
|
that leverages natural phenomenon to generate random numbers, which is can be better than a traditional
|
||||||
RNG that has state and updates deterministically using cryptographic methods.
|
RNG that has state and updates deterministically using cryptographic methods.
|
||||||
|
|
||||||
You can easily access the TRNG stream on Solo using our python tool [`solo-python`](https://github.com/solokeys/solo-python).
|
You can easily access the TRNG stream on Solo using our python tool [solo-python](https://github.com/solokeys/solo-python).
|
||||||
|
|
||||||
```
|
```
|
||||||
solo key rng raw > random.bin
|
solo key rng raw > random.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Or you can seed the state of the RNG on your kernel (`/dev/random`).
|
Or you can seed the state of the RNG on your kernel (/dev/random).
|
||||||
|
|
||||||
```
|
```
|
||||||
solo key rng feedkernel
|
solo key rng feedkernel
|
||||||
|
@ -1,33 +1,30 @@
|
|||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed.
|
On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed. (Under Fedora, your key may work without such a rule.)
|
||||||
|
|
||||||
For some users, things will work automatically:
|
Create a file like [`70-solokeys-access.rules`](https://github.com/solokeys/solo/blob/master/udev/70-solokeys-access.rules) in your `/etc/udev/rules.d` directory, for instance the following rule should cover normal access (it has to be on one line):
|
||||||
|
|
||||||
- Fedora seems to use a ["universal" udev rule for FIDO devices](https://github.com/amluto/u2f-hidraw-policy)
|
|
||||||
- Our udev rule made it into [libu2f-host](https://github.com/Yubico/libu2f-host/) v1.1.10
|
|
||||||
- Arch Linux [has this package](https://www.archlinux.org/packages/community/x86_64/libu2f-host/)
|
|
||||||
- [Debian sid](https://packages.debian.org/sid/libu2f-udev) and [Ubuntu Eon](https://packages.ubuntu.com/eoan/libu2f-udev) can use the `libu2f-udev` package
|
|
||||||
- Debian Buster and Ubuntu Disco still distribute v1.1.10, so need the manual rule
|
|
||||||
- FreeBSD has support in [u2f-devd](https://github.com/solokeys/solo/issues/144#issuecomment-500216020)
|
|
||||||
|
|
||||||
There is hope that `udev` itself will adopt the Fedora approach (which is to check for HID usage page `F1D0`, and avoids manually whitelisting each U2F/FIDO2 key): <https://github.com/systemd/systemd/issues/11996>.
|
|
||||||
|
|
||||||
Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>.
|
|
||||||
|
|
||||||
If you still need to setup a rule, a simple way to do it is:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/solokeys/solo.git
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", MODE="0660", GROUP="plugdev"
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
A simple way to setup both the udev rule and the udevadm reload is:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@github.com:solokeys/solo.git
|
||||||
cd solo/udev
|
cd solo/udev
|
||||||
make setup
|
make setup
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, manually, create a file like [`70-solokeys-access.rules`](https://github.com/solokeys/solo/blob/master/udev/70-solokeys-access.rules) in your `/etc/udev/rules.d` directory.
|
We are working on getting user access to Solo keys enabled automatically in common Linux distributions: <https://github.com/solokeys/solo/issues/144>.
|
||||||
Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
|
|
||||||
```
|
|
||||||
sudo udevadm control --reload-rules && sudo udevadm trigger
|
|
||||||
```
|
|
||||||
|
|
||||||
# How do udev rules work and why are they needed
|
# How do udev rules work and why are they needed
|
||||||
|
|
||||||
|
20
fido2/apdu.c
20
fido2/apdu.c
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
|
|
||||||
uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
||||||
{
|
{
|
||||||
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
|
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
|
||||||
|
|
||||||
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any
|
apdu->cla = hapdu->cla;
|
||||||
apdu->ins = hapdu->ins;
|
apdu->ins = hapdu->ins;
|
||||||
apdu->p1 = hapdu->p1;
|
apdu->p1 = hapdu->p1;
|
||||||
apdu->p2 = hapdu->p2;
|
apdu->p2 = hapdu->p2;
|
||||||
@ -62,11 +62,6 @@ uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
|||||||
if (len >= 7 && b0 == 0)
|
if (len >= 7 && b0 == 0)
|
||||||
{
|
{
|
||||||
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
|
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
|
||||||
|
|
||||||
if (len - 7 < extlen)
|
|
||||||
{
|
|
||||||
return SW_WRONG_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
// case 2E (Le) - extended
|
// case 2E (Le) - extended
|
||||||
if (len == 7)
|
if (len == 7)
|
||||||
@ -108,18 +103,9 @@ uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
|||||||
apdu->le = 0x10000;
|
apdu->le = 0x10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((len > 5) && (len - 5 < hapdu->lc[0]))
|
|
||||||
{
|
|
||||||
return SW_WRONG_LENGTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!apdu->case_type)
|
if (!apdu->case_type)
|
||||||
{
|
return 1;
|
||||||
return SW_COND_USE_NOT_SATISFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apdu->lc)
|
if (apdu->lc)
|
||||||
{
|
{
|
||||||
|
@ -36,26 +36,20 @@ typedef struct
|
|||||||
uint8_t case_type;
|
uint8_t case_type;
|
||||||
} __attribute__((packed)) APDU_STRUCT;
|
} __attribute__((packed)) APDU_STRUCT;
|
||||||
|
|
||||||
extern uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
|
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
|
||||||
|
|
||||||
#define APDU_FIDO_U2F_REGISTER 0x01
|
#define APDU_FIDO_U2F_REGISTER 0x01
|
||||||
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
|
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
|
||||||
#define APDU_FIDO_U2F_VERSION 0x03
|
#define APDU_FIDO_U2F_VERSION 0x03
|
||||||
#define APDU_FIDO_NFCCTAP_MSG 0x10
|
#define APDU_FIDO_NFCCTAP_MSG 0x10
|
||||||
#define APDU_FIDO_U2F_VENDOR_FIRST 0xc0 // First vendor defined command
|
|
||||||
#define APDU_FIDO_U2F_VENDOR_LAST 0xff // Last vendor defined command
|
|
||||||
#define APDU_SOLO_RESET 0xee
|
|
||||||
|
|
||||||
#define APDU_INS_SELECT 0xA4
|
#define APDU_INS_SELECT 0xA4
|
||||||
#define APDU_INS_READ_BINARY 0xB0
|
#define APDU_INS_READ_BINARY 0xB0
|
||||||
#define APDU_GET_RESPONSE 0xC0
|
|
||||||
|
|
||||||
#define SW_SUCCESS 0x9000
|
#define SW_SUCCESS 0x9000
|
||||||
#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE.
|
#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE.
|
||||||
#define SW_WRONG_LENGTH 0x6700
|
#define SW_WRONG_LENGTH 0x6700
|
||||||
#define SW_COND_USE_NOT_SATISFIED 0x6985
|
#define SW_COND_USE_NOT_SATISFIED 0x6985
|
||||||
#define SW_FILE_NOT_FOUND 0x6a82
|
#define SW_FILE_NOT_FOUND 0x6a82
|
||||||
#define SW_INCORRECT_P1P2 0x6a86
|
|
||||||
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
|
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
|
||||||
#define SW_CLA_INVALID 0x6e00
|
#define SW_CLA_INVALID 0x6e00
|
||||||
#define SW_INTERNAL_EXCEPTION 0x6f00
|
#define SW_INTERNAL_EXCEPTION 0x6f00
|
||||||
|
177
fido2/ctap.c
177
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;
|
||||||
@ -437,23 +437,7 @@ static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred)
|
|||||||
static int ctap2_user_presence_test()
|
static int ctap2_user_presence_test()
|
||||||
{
|
{
|
||||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||||
int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
return ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||||
if ( ret > 1 )
|
|
||||||
{
|
|
||||||
return CTAP2_ERR_PROCESSING;
|
|
||||||
}
|
|
||||||
else if ( ret > 0 )
|
|
||||||
{
|
|
||||||
return CTAP1_ERR_SUCCESS;
|
|
||||||
}
|
|
||||||
else if (ret < 0)
|
|
||||||
{
|
|
||||||
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return CTAP2_ERR_ACTION_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo)
|
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo)
|
||||||
@ -486,19 +470,19 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
int but;
|
int but;
|
||||||
|
|
||||||
but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||||
if (CTAP2_ERR_PROCESSING == but)
|
|
||||||
|
if (!but)
|
||||||
{
|
{
|
||||||
authData->head.flags = (0 << 0); // User presence disabled
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
}
|
}
|
||||||
else
|
else if (but < 0) // Cancel
|
||||||
{
|
{
|
||||||
check_retr(but);
|
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
||||||
authData->head.flags = (1 << 0); // User presence
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
|
|
||||||
|
authData->head.flags = (but << 0);
|
||||||
authData->head.flags |= (ctap_is_pin_set() << 2);
|
authData->head.flags |= (ctap_is_pin_set() << 2);
|
||||||
|
|
||||||
|
|
||||||
@ -682,23 +666,14 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d
|
|||||||
switch(desc->type)
|
switch(desc->type)
|
||||||
{
|
{
|
||||||
case PUB_KEY_CRED_PUB_KEY:
|
case PUB_KEY_CRED_PUB_KEY:
|
||||||
crypto_sha256_init();
|
make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
||||||
crypto_sha256_update(rp->id, rp->size);
|
|
||||||
crypto_sha256_final(rpIdHash);
|
|
||||||
|
|
||||||
printf1(TAG_RED,"rpId: %s\r\n", rp->id); dump_hex1(TAG_RED,rp->id, rp->size);
|
|
||||||
if (memcmp(desc->credential.id.rpIdHash, rpIdHash, 32) != 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
make_auth_tag(rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
|
||||||
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
||||||
break;
|
break;
|
||||||
case PUB_KEY_CRED_CTAP1:
|
case PUB_KEY_CRED_CTAP1:
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
crypto_sha256_update(rp->id, rp->size);
|
crypto_sha256_update(rp->id, rp->size);
|
||||||
crypto_sha256_final(rpIdHash);
|
crypto_sha256_final(rpIdHash);
|
||||||
return u2f_authenticate_credential((struct u2f_key_handle *)&desc->credential.id, U2F_KEY_HANDLE_SIZE,rpIdHash);
|
return u2f_authenticate_credential((struct u2f_key_handle *)&desc->credential.id, rpIdHash);
|
||||||
break;
|
break;
|
||||||
case PUB_KEY_CRED_CUSTOM:
|
case PUB_KEY_CRED_CUSTOM:
|
||||||
return is_extension_request(getAssertionState.customCredId, getAssertionState.customCredIdSize);
|
return is_extension_request(getAssertionState.customCredId, getAssertionState.customCredIdSize);
|
||||||
@ -732,7 +707,10 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
if (MC.pinAuthEmpty)
|
if (MC.pinAuthEmpty)
|
||||||
{
|
{
|
||||||
check_retr( ctap2_user_presence_test(CTAP2_UP_DELAY_MS) );
|
if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||||
}
|
}
|
||||||
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
|
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
|
||||||
@ -755,7 +733,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MC.up == 1 || MC.up == 0)
|
if (MC.up)
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_INVALID_OPTION;
|
return CTAP2_ERR_INVALID_OPTION;
|
||||||
}
|
}
|
||||||
@ -1165,7 +1143,10 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
|
|
||||||
if (GA.pinAuthEmpty)
|
if (GA.pinAuthEmpty)
|
||||||
{
|
{
|
||||||
check_retr( ctap2_user_presence_test(CTAP2_UP_DELAY_MS) );
|
if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||||
}
|
}
|
||||||
if (GA.pinAuthPresent)
|
if (GA.pinAuthPresent)
|
||||||
@ -1248,9 +1229,8 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
device_disable_up(GA.up == 0);
|
|
||||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
|
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
|
||||||
device_disable_up(false);
|
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
|
||||||
((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2);
|
((CTAP_authDataHeader *)auth_data_buf)->flags &= ~(1 << 2);
|
||||||
@ -1308,13 +1288,11 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
uint8_t hmac[32];
|
uint8_t hmac[32];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
// Validate incoming data packet len
|
|
||||||
if (len < 64)
|
if (len < 64)
|
||||||
{
|
{
|
||||||
return CTAP1_ERR_OTHER;
|
return CTAP1_ERR_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate device's state
|
|
||||||
if (ctap_is_pin_set()) // Check first, prevent SCA
|
if (ctap_is_pin_set()) // Check first, prevent SCA
|
||||||
{
|
{
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
@ -1327,7 +1305,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate shared_secret
|
|
||||||
crypto_ecc256_shared_secret(platform_pubkey, KEY_AGREEMENT_PRIV, shared_secret);
|
crypto_ecc256_shared_secret(platform_pubkey, KEY_AGREEMENT_PRIV, shared_secret);
|
||||||
|
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
@ -1350,7 +1327,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
return CTAP2_ERR_PIN_AUTH_INVALID;
|
return CTAP2_ERR_PIN_AUTH_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt new PIN with shared secret
|
|
||||||
crypto_aes256_init(shared_secret, NULL);
|
crypto_aes256_init(shared_secret, NULL);
|
||||||
|
|
||||||
while((len & 0xf) != 0) // round up to nearest AES block size multiple
|
while((len & 0xf) != 0) // round up to nearest AES block size multiple
|
||||||
@ -1360,7 +1336,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
|
|
||||||
crypto_aes256_decrypt(pinEnc, len);
|
crypto_aes256_decrypt(pinEnc, len);
|
||||||
|
|
||||||
// validate new PIN (length)
|
|
||||||
|
|
||||||
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
|
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
|
||||||
ret = NEW_PIN_ENC_MIN_SIZE - ret;
|
ret = NEW_PIN_ENC_MIN_SIZE - ret;
|
||||||
@ -1376,8 +1352,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
dump_hex1(TAG_CP, pinEnc, ret);
|
dump_hex1(TAG_CP, pinEnc, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate device's state, decrypt and compare pinHashEnc (user provided current PIN hash) with stored PIN_CODE_HASH
|
|
||||||
|
|
||||||
if (ctap_is_pin_set())
|
if (ctap_is_pin_set())
|
||||||
{
|
{
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
@ -1390,14 +1364,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
}
|
}
|
||||||
crypto_aes256_reset_iv(NULL);
|
crypto_aes256_reset_iv(NULL);
|
||||||
crypto_aes256_decrypt(pinHashEnc, 16);
|
crypto_aes256_decrypt(pinHashEnc, 16);
|
||||||
|
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
||||||
uint8_t pinHashEncSalted[32];
|
|
||||||
crypto_sha256_init();
|
|
||||||
crypto_sha256_update(pinHashEnc, 16);
|
|
||||||
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
|
|
||||||
crypto_sha256_final(pinHashEncSalted);
|
|
||||||
|
|
||||||
if (memcmp(pinHashEncSalted, STATE.PIN_CODE_HASH, 16) != 0)
|
|
||||||
{
|
{
|
||||||
ctap_reset_key_agreement();
|
ctap_reset_key_agreement();
|
||||||
ctap_decrement_pin_attempts();
|
ctap_decrement_pin_attempts();
|
||||||
@ -1413,7 +1380,6 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set new PIN (update and store PIN_CODE_HASH)
|
|
||||||
ctap_update_pin(pinEnc, ret);
|
ctap_update_pin(pinEnc, ret);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1433,16 +1399,12 @@ uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubke
|
|||||||
|
|
||||||
crypto_aes256_decrypt(pinHashEnc, 16);
|
crypto_aes256_decrypt(pinHashEnc, 16);
|
||||||
|
|
||||||
uint8_t pinHashEncSalted[32];
|
|
||||||
crypto_sha256_init();
|
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
||||||
crypto_sha256_update(pinHashEnc, 16);
|
|
||||||
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
|
|
||||||
crypto_sha256_final(pinHashEncSalted);
|
|
||||||
if (memcmp(pinHashEncSalted, STATE.PIN_CODE_HASH, 16) != 0)
|
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Pin does not match!\n");
|
printf2(TAG_ERR,"Pin does not match!\n");
|
||||||
printf2(TAG_ERR,"platform-pin-hash: "); dump_hex1(TAG_ERR, pinHashEnc, 16);
|
printf2(TAG_ERR,"platform-pin-hash: "); dump_hex1(TAG_ERR, pinHashEnc, 16);
|
||||||
printf2(TAG_ERR,"authentic-pin-hash: "); dump_hex1(TAG_ERR, STATE.PIN_CODE_HASH, 16);
|
printf2(TAG_ERR,"authentic-pin-hash: "); dump_hex1(TAG_ERR, PIN_CODE_HASH, 16);
|
||||||
printf2(TAG_ERR,"shared-secret: "); dump_hex1(TAG_ERR, shared_secret, 32);
|
printf2(TAG_ERR,"shared-secret: "); dump_hex1(TAG_ERR, shared_secret, 32);
|
||||||
printf2(TAG_ERR,"platform-pubkey: "); dump_hex1(TAG_ERR, platform_pubkey, 64);
|
printf2(TAG_ERR,"platform-pubkey: "); dump_hex1(TAG_ERR, platform_pubkey, 64);
|
||||||
printf2(TAG_ERR,"device-pubkey: "); dump_hex1(TAG_ERR, KEY_AGREEMENT_PUB, 64);
|
printf2(TAG_ERR,"device-pubkey: "); dump_hex1(TAG_ERR, KEY_AGREEMENT_PUB, 64);
|
||||||
@ -1694,11 +1656,14 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
break;
|
break;
|
||||||
case CTAP_RESET:
|
case CTAP_RESET:
|
||||||
printf1(TAG_CTAP,"CTAP_RESET\n");
|
printf1(TAG_CTAP,"CTAP_RESET\n");
|
||||||
status = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
if (ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||||
if (status == CTAP1_ERR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
ctap_reset();
|
ctap_reset();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GET_NEXT_ASSERTION:
|
case GET_NEXT_ASSERTION:
|
||||||
printf1(TAG_CTAP,"CTAP_NEXT_ASSERTION\n");
|
printf1(TAG_CTAP,"CTAP_NEXT_ASSERTION\n");
|
||||||
@ -1720,7 +1685,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
status = CTAP1_ERR_INVALID_COMMAND;
|
status = CTAP1_ERR_INVALID_COMMAND;
|
||||||
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd);
|
printf2(TAG_ERR,"error, invalid cmd: %x\n", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@ -1750,39 +1715,12 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Overwrite master secret from external source.
|
|
||||||
* @param keybytes an array of KEY_SPACE_BYTES length.
|
|
||||||
*
|
|
||||||
* This function should only be called from a privilege mode.
|
|
||||||
*/
|
|
||||||
void ctap_load_external_keys(uint8_t * keybytes){
|
|
||||||
memmove(STATE.key_space, keybytes, KEY_SPACE_BYTES);
|
|
||||||
authenticator_write_state(&STATE, 0);
|
|
||||||
authenticator_write_state(&STATE, 1);
|
|
||||||
crypto_load_master_secret(STATE.key_space);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "version.h"
|
|
||||||
void ctap_init()
|
void ctap_init()
|
||||||
{
|
{
|
||||||
printf1(TAG_ERR,"Current firmware version address: %p\r\n", &firmware_version);
|
|
||||||
printf1(TAG_ERR,"Current firmware version: %d.%d.%d.%d (%02x.%02x.%02x.%02x)\r\n",
|
|
||||||
firmware_version.major, firmware_version.minor, firmware_version.patch, firmware_version.reserved,
|
|
||||||
firmware_version.major, firmware_version.minor, firmware_version.patch, firmware_version.reserved
|
|
||||||
);
|
|
||||||
crypto_ecc256_init();
|
crypto_ecc256_init();
|
||||||
|
|
||||||
authenticator_read_state(&STATE);
|
authenticator_read_state(&STATE);
|
||||||
@ -1811,12 +1749,14 @@ void ctap_init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_migration_if_required(&STATE);
|
|
||||||
|
|
||||||
crypto_load_master_secret(STATE.key_space);
|
crypto_load_master_secret(STATE.key_space);
|
||||||
|
|
||||||
if (ctap_is_pin_set())
|
if (ctap_is_pin_set())
|
||||||
{
|
{
|
||||||
|
printf1(TAG_STOR,"pin code: \"%s\"\n", STATE.pin_code);
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(STATE.pin_code, STATE.pin_code_length);
|
||||||
|
crypto_sha256_final(PIN_CODE_HASH);
|
||||||
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
|
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1848,38 +1788,34 @@ uint8_t ctap_is_pin_set()
|
|||||||
return STATE.is_pin_set == 1;
|
return STATE.is_pin_set == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
uint8_t ctap_pin_matches(uint8_t * pin, int len)
|
||||||
* Set new PIN, by updating PIN hash. Save state.
|
{
|
||||||
* Globals: STATE
|
return memcmp(pin, STATE.pin_code, len) == 0;
|
||||||
* @param pin new PIN (raw)
|
}
|
||||||
* @param len pin array length
|
|
||||||
*/
|
|
||||||
void ctap_update_pin(uint8_t * pin, int len)
|
void ctap_update_pin(uint8_t * pin, int len)
|
||||||
{
|
{
|
||||||
if (len >= NEW_PIN_ENC_MIN_SIZE || len < 4)
|
if (len > NEW_PIN_ENC_MIN_SIZE || len < 4)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR, "Update pin fail length\n");
|
printf2(TAG_ERR, "Update pin fail length\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
memset(STATE.pin_code, 0, NEW_PIN_ENC_MIN_SIZE);
|
||||||
|
memmove(STATE.pin_code, pin, len);
|
||||||
|
STATE.pin_code_length = len;
|
||||||
|
STATE.pin_code[NEW_PIN_ENC_MIN_SIZE - 1] = 0;
|
||||||
|
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
crypto_sha256_update(pin, len);
|
crypto_sha256_update(STATE.pin_code, len);
|
||||||
uint8_t intermediateHash[32];
|
crypto_sha256_final(PIN_CODE_HASH);
|
||||||
crypto_sha256_final(intermediateHash);
|
|
||||||
|
|
||||||
crypto_sha256_init();
|
|
||||||
crypto_sha256_update(intermediateHash, 16);
|
|
||||||
memset(intermediateHash, 0, sizeof(intermediateHash));
|
|
||||||
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
|
|
||||||
crypto_sha256_final(STATE.PIN_CODE_HASH);
|
|
||||||
|
|
||||||
STATE.is_pin_set = 1;
|
STATE.is_pin_set = 1;
|
||||||
|
|
||||||
authenticator_write_state(&STATE, 1);
|
authenticator_write_state(&STATE, 1);
|
||||||
authenticator_write_state(&STATE, 0);
|
authenticator_write_state(&STATE, 0);
|
||||||
|
|
||||||
printf1(TAG_CTAP, "New pin set: %s [%d]\n", pin, len);
|
printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
|
||||||
dump_hex1(TAG_ERR, STATE.PIN_CODE_HASH, sizeof(STATE.PIN_CODE_HASH));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ctap_decrement_pin_attempts()
|
uint8_t ctap_decrement_pin_attempts()
|
||||||
@ -1896,7 +1832,9 @@ uint8_t ctap_decrement_pin_attempts()
|
|||||||
|
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
lock_device_permanently();
|
memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
|
||||||
|
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||||
|
printf1(TAG_CP, "Device locked!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2052,17 +1990,8 @@ void ctap_reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctap_reset_state();
|
ctap_reset_state();
|
||||||
|
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||||
ctap_reset_key_agreement();
|
ctap_reset_key_agreement();
|
||||||
|
|
||||||
crypto_load_master_secret(STATE.key_space);
|
crypto_load_master_secret(STATE.key_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_device_permanently() {
|
|
||||||
memset(PIN_TOKEN, 0, sizeof(PIN_TOKEN));
|
|
||||||
memset(STATE.PIN_CODE_HASH, 0, sizeof(STATE.PIN_CODE_HASH));
|
|
||||||
|
|
||||||
printf1(TAG_CP, "Device locked!\n");
|
|
||||||
|
|
||||||
authenticator_write_state(&STATE, 0);
|
|
||||||
authenticator_write_state(&STATE, 1);
|
|
||||||
}
|
|
||||||
|
@ -131,7 +131,7 @@
|
|||||||
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
|
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
|
||||||
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
|
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
|
||||||
|
|
||||||
#define CTAP2_UP_DELAY_MS 29000
|
#define CTAP2_UP_DELAY_MS 5000
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -359,8 +359,5 @@ uint16_t ctap_key_len(uint8_t index);
|
|||||||
extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
||||||
extern uint8_t KEY_AGREEMENT_PUB[64];
|
extern uint8_t KEY_AGREEMENT_PUB[64];
|
||||||
|
|
||||||
void lock_device_permanently();
|
|
||||||
|
|
||||||
void ctap_load_external_keys(uint8_t * keybytes);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,7 +49,6 @@
|
|||||||
#define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37
|
#define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37
|
||||||
#define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38
|
#define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38
|
||||||
#define CTAP2_ERR_REQUEST_TOO_LARGE 0x39
|
#define CTAP2_ERR_REQUEST_TOO_LARGE 0x39
|
||||||
#define CTAP2_ERR_ACTION_TIMEOUT 0x3A
|
|
||||||
#define CTAP1_ERR_OTHER 0x7F
|
#define CTAP1_ERR_OTHER 0x7F
|
||||||
#define CTAP2_ERR_SPEC_LAST 0xDF
|
#define CTAP2_ERR_SPEC_LAST 0xDF
|
||||||
#define CTAP2_ERR_EXTENSION_FIRST 0xE0
|
#define CTAP2_ERR_EXTENSION_FIRST 0xE0
|
||||||
|
@ -715,7 +715,6 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
|||||||
CborValue it,map;
|
CborValue it,map;
|
||||||
|
|
||||||
memset(MC, 0, sizeof(CTAP_makeCredential));
|
memset(MC, 0, sizeof(CTAP_makeCredential));
|
||||||
MC->up = 0xff;
|
|
||||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
|
||||||
@ -1011,7 +1010,6 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
|||||||
|
|
||||||
memset(GA, 0, sizeof(CTAP_getAssertion));
|
memset(GA, 0, sizeof(CTAP_getAssertion));
|
||||||
GA->creds = getAssertionState.creds; // Save stack memory
|
GA->creds = getAssertionState.creds; // Save stack memory
|
||||||
GA->up = 0xff;
|
|
||||||
|
|
||||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
341
fido2/ctaphid.c
341
fido2/ctaphid.c
@ -16,7 +16,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "extensions.h"
|
#include "extensions.h"
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
// move custom SHA512 command out,
|
// move custom SHA512 command out,
|
||||||
// and the following headers too
|
// and the following headers too
|
||||||
@ -539,14 +538,11 @@ extern void _check_ret(CborError ret, int line, const char * filename);
|
|||||||
#define check_hardcore(r) _check_ret(r,__LINE__, __FILE__);\
|
#define check_hardcore(r) _check_ret(r,__LINE__, __FILE__);\
|
||||||
if ((r) != CborNoError) exit(1);
|
if ((r) != CborNoError) exit(1);
|
||||||
|
|
||||||
|
|
||||||
uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb);
|
|
||||||
|
|
||||||
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||||
{
|
{
|
||||||
uint8_t cmd = 0;
|
uint8_t cmd;
|
||||||
uint32_t cid;
|
uint32_t cid;
|
||||||
int len = 0;
|
int len;
|
||||||
#ifndef DISABLE_CTAPHID_CBOR
|
#ifndef DISABLE_CTAPHID_CBOR
|
||||||
int status;
|
int status;
|
||||||
#endif
|
#endif
|
||||||
@ -556,10 +552,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
CTAP_RESPONSE ctap_resp;
|
CTAP_RESPONSE ctap_resp;
|
||||||
|
|
||||||
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
|
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
|
||||||
ctaphid_write_buffer_init(&wb);
|
|
||||||
|
|
||||||
wb.cid = cid;
|
|
||||||
wb.cmd = cmd;
|
|
||||||
|
|
||||||
if (bufstatus == HID_IGNORE)
|
if (bufstatus == HID_IGNORE)
|
||||||
{
|
{
|
||||||
@ -595,6 +587,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
case CTAPHID_PING:
|
case CTAPHID_PING:
|
||||||
printf1(TAG_HID,"CTAPHID_PING\n");
|
printf1(TAG_HID,"CTAPHID_PING\n");
|
||||||
|
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_PING;
|
||||||
wb.bcnt = len;
|
wb.bcnt = len;
|
||||||
timestamp();
|
timestamp();
|
||||||
ctaphid_write(&wb, ctap_buffer, len);
|
ctaphid_write(&wb, ctap_buffer, len);
|
||||||
@ -607,9 +602,13 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
case CTAPHID_WINK:
|
case CTAPHID_WINK:
|
||||||
printf1(TAG_HID,"CTAPHID_WINK\n");
|
printf1(TAG_HID,"CTAPHID_WINK\n");
|
||||||
|
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
|
||||||
device_wink();
|
device_wink();
|
||||||
|
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_WINK;
|
||||||
|
|
||||||
ctaphid_write(&wb,NULL,0);
|
ctaphid_write(&wb,NULL,0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -634,6 +633,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
status = ctap_request(ctap_buffer, len, &ctap_resp);
|
status = ctap_request(ctap_buffer, len, &ctap_resp);
|
||||||
|
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_CBOR;
|
||||||
wb.bcnt = (ctap_resp.length+1);
|
wb.bcnt = (ctap_resp.length+1);
|
||||||
|
|
||||||
|
|
||||||
@ -664,6 +666,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
||||||
|
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_MSG;
|
||||||
wb.bcnt = (ctap_resp.length);
|
wb.bcnt = (ctap_resp.length);
|
||||||
|
|
||||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||||
@ -674,14 +679,209 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
||||||
is_busy = 0;
|
is_busy = 0;
|
||||||
break;
|
break;
|
||||||
|
#if defined(IS_BOOTLOADER)
|
||||||
|
case CTAPHID_BOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_BOOT\n");
|
||||||
|
ctap_response_init(&ctap_resp);
|
||||||
|
u2f_set_writeback_buffer(&ctap_resp);
|
||||||
|
is_busy = bootloader_bridge(len, ctap_buffer);
|
||||||
|
|
||||||
default:
|
ctaphid_write_buffer_init(&wb);
|
||||||
if (ctaphid_custom_command(len, &ctap_resp, &wb) != 0){
|
wb.cid = cid;
|
||||||
is_busy = 0;
|
wb.cmd = CTAPHID_BOOT;
|
||||||
}else{
|
wb.bcnt = (ctap_resp.length + 1);
|
||||||
printf2(TAG_ERR, "error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
ctaphid_write(&wb, &is_busy, 1);
|
||||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if defined(SOLO_HACKER)
|
||||||
|
case CTAPHID_ENTERBOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||||
|
boot_solo_bootloader();
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_ENTERBOOT;
|
||||||
|
wb.bcnt = 0;
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
case CTAPHID_ENTERSTBOOT:
|
||||||
|
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
||||||
|
boot_st_bootloader();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if !defined(IS_BOOTLOADER)
|
||||||
|
case CTAPHID_GETRNG:
|
||||||
|
printf1(TAG_HID,"CTAPHID_GETRNG\n");
|
||||||
|
ctap_response_init(&ctap_resp);
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_GETRNG;
|
||||||
|
wb.bcnt = ctap_buffer[0];
|
||||||
|
if (!wb.bcnt)
|
||||||
|
wb.bcnt = 57;
|
||||||
|
memset(ctap_buffer,0,wb.bcnt);
|
||||||
|
ctap_generate_rng(ctap_buffer, wb.bcnt);
|
||||||
|
ctaphid_write(&wb, &ctap_buffer, wb.bcnt);
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if defined(SOLO_HACKER) && (DEBUG_LEVEL > 0) && (!IS_BOOTLOADER == 1)
|
||||||
|
case CTAPHID_PROBE:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expects CBOR-serialized data of the form
|
||||||
|
* {"subcommand": "hash_type", "data": b"the_data"}
|
||||||
|
* with hash_type in SHA256, SHA512
|
||||||
|
*/
|
||||||
|
|
||||||
|
// some random logging
|
||||||
|
printf1(TAG_HID,"CTAPHID_PROBE\n");
|
||||||
|
// initialise CTAP response object
|
||||||
|
ctap_response_init(&ctap_resp);
|
||||||
|
// initialise write buffer
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_PROBE;
|
||||||
|
|
||||||
|
// prepare parsing (or halt)
|
||||||
|
int ret;
|
||||||
|
CborParser parser;
|
||||||
|
CborValue it, map;
|
||||||
|
ret = cbor_parser_init(
|
||||||
|
ctap_buffer, (size_t) buffer_len(),
|
||||||
|
// strictly speaking, CTAP is not RFC canonical...
|
||||||
|
CborValidateCanonicalFormat,
|
||||||
|
&parser, &it);
|
||||||
|
check_hardcore(ret);
|
||||||
|
|
||||||
|
CborType type = cbor_value_get_type(&it);
|
||||||
|
if (type != CborMapType) exit(1);
|
||||||
|
|
||||||
|
ret = cbor_value_enter_container(&it,&map);
|
||||||
|
check_hardcore(ret);
|
||||||
|
|
||||||
|
size_t map_length = 0;
|
||||||
|
ret = cbor_value_get_map_length(&it, &map_length);
|
||||||
|
if (map_length != 2) exit(1);
|
||||||
|
|
||||||
|
// parse subcommand (or halt)
|
||||||
|
CborValue val;
|
||||||
|
ret = cbor_value_map_find_value(&it, "subcommand", &val);
|
||||||
|
check_hardcore(ret);
|
||||||
|
if (!cbor_value_is_text_string(&val))
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
int sha_version = 0;
|
||||||
|
bool found = false;
|
||||||
|
if (!found) {
|
||||||
|
ret = cbor_value_text_string_equals(
|
||||||
|
&val, "SHA256", &found);
|
||||||
|
check_hardcore(ret);
|
||||||
|
if (found)
|
||||||
|
sha_version = 256;
|
||||||
}
|
}
|
||||||
|
if (!found) {
|
||||||
|
ret = cbor_value_text_string_equals(
|
||||||
|
&val, "SHA512", &found);
|
||||||
|
check_hardcore(ret);
|
||||||
|
if (found)
|
||||||
|
sha_version = 512;
|
||||||
|
}
|
||||||
|
if (sha_version == 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
// parse data (or halt)
|
||||||
|
ret = cbor_value_map_find_value(&it, "data", &val);
|
||||||
|
check_hardcore(ret);
|
||||||
|
if (!cbor_value_is_byte_string(&val))
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
size_t data_length = 0;
|
||||||
|
ret = cbor_value_calculate_string_length(&val, &data_length);
|
||||||
|
check_hardcore(ret);
|
||||||
|
if (data_length > 6*1024)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
unsigned char data[6*1024];
|
||||||
|
ret = cbor_value_copy_byte_string (
|
||||||
|
&val, &data[0], &data_length, &val);
|
||||||
|
check_hardcore(ret);
|
||||||
|
|
||||||
|
// execute subcommand
|
||||||
|
if (sha_version == 256) {
|
||||||
|
// calculate hash
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(data, data_length);
|
||||||
|
crypto_sha256_final(ctap_buffer);
|
||||||
|
// write output
|
||||||
|
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
|
||||||
|
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sha_version == 512) {
|
||||||
|
// calculate hash
|
||||||
|
crypto_sha512_init();
|
||||||
|
crypto_sha512_update(data, data_length);
|
||||||
|
crypto_sha512_final(ctap_buffer);
|
||||||
|
// write output
|
||||||
|
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
|
||||||
|
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
case CTAPHID_SHA256:
|
||||||
|
// some random logging
|
||||||
|
printf1(TAG_HID,"CTAPHID_SHA256\n");
|
||||||
|
// initialise CTAP response object
|
||||||
|
ctap_response_init(&ctap_resp);
|
||||||
|
// initialise write buffer
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_SHA256;
|
||||||
|
wb.bcnt = CF_SHA256_HASHSZ; // 32 bytes
|
||||||
|
// calculate hash
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(ctap_buffer, buffer_len());
|
||||||
|
crypto_sha256_final(ctap_buffer);
|
||||||
|
// copy to output
|
||||||
|
ctaphid_write(&wb, &ctap_buffer, CF_SHA256_HASHSZ);
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
case CTAPHID_SHA512:
|
||||||
|
// some random logging
|
||||||
|
printf1(TAG_HID,"CTAPHID_SHA512\n");
|
||||||
|
// initialise CTAP response object
|
||||||
|
ctap_response_init(&ctap_resp);
|
||||||
|
// initialise write buffer
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
wb.cid = cid;
|
||||||
|
wb.cmd = CTAPHID_SHA512;
|
||||||
|
wb.bcnt = CF_SHA512_HASHSZ; // 64 bytes
|
||||||
|
// calculate hash
|
||||||
|
crypto_sha512_init();
|
||||||
|
crypto_sha512_update(ctap_buffer, buffer_len());
|
||||||
|
crypto_sha512_final(ctap_buffer);
|
||||||
|
// copy to output
|
||||||
|
ctaphid_write(&wb, &ctap_buffer, CF_SHA512_HASHSZ);
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||||
|
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cid_del(cid);
|
cid_del(cid);
|
||||||
buffer_reset();
|
buffer_reset();
|
||||||
@ -691,112 +891,3 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
else return 0;
|
else return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ctaphid_custom_command(int len, CTAP_RESPONSE * ctap_resp, CTAPHID_WRITE_BUFFER * wb)
|
|
||||||
{
|
|
||||||
ctap_response_init(ctap_resp);
|
|
||||||
|
|
||||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
|
||||||
uint32_t param;
|
|
||||||
#endif
|
|
||||||
#if defined(IS_BOOTLOADER)
|
|
||||||
uint8_t is_busy;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch(wb->cmd)
|
|
||||||
{
|
|
||||||
#if defined(IS_BOOTLOADER)
|
|
||||||
case CTAPHID_BOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_BOOT\n");
|
|
||||||
u2f_set_writeback_buffer(ctap_resp);
|
|
||||||
is_busy = bootloader_bridge(len, ctap_buffer);
|
|
||||||
|
|
||||||
ctaphid_write(wb, &is_busy, 1);
|
|
||||||
ctaphid_write(wb, ctap_resp->data, ctap_resp->length);
|
|
||||||
ctaphid_write(wb, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
#if defined(SOLO_HACKER)
|
|
||||||
case CTAPHID_ENTERBOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
|
||||||
boot_solo_bootloader();
|
|
||||||
wb->bcnt = 0;
|
|
||||||
ctaphid_write(wb, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
case CTAPHID_ENTERSTBOOT:
|
|
||||||
printf1(TAG_HID,"CTAPHID_ENTERBOOT\n");
|
|
||||||
boot_st_bootloader();
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(IS_BOOTLOADER)
|
|
||||||
case CTAPHID_GETRNG:
|
|
||||||
printf1(TAG_HID,"CTAPHID_GETRNG\n");
|
|
||||||
wb->bcnt = ctap_buffer[0];
|
|
||||||
if (!wb->bcnt)
|
|
||||||
wb->bcnt = 57;
|
|
||||||
memset(ctap_buffer,0,wb->bcnt);
|
|
||||||
ctap_generate_rng(ctap_buffer, wb->bcnt);
|
|
||||||
ctaphid_write(wb, ctap_buffer, wb->bcnt);
|
|
||||||
ctaphid_write(wb, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case CTAPHID_GETVERSION:
|
|
||||||
printf1(TAG_HID,"CTAPHID_GETVERSION\n");
|
|
||||||
wb->bcnt = 3;
|
|
||||||
ctap_buffer[0] = SOLO_VERSION_MAJ;
|
|
||||||
ctap_buffer[1] = SOLO_VERSION_MIN;
|
|
||||||
ctap_buffer[2] = SOLO_VERSION_PATCH;
|
|
||||||
ctaphid_write(wb, ctap_buffer, 3);
|
|
||||||
ctaphid_write(wb, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if !defined(IS_BOOTLOADER) && (defined(SOLO_HACKER) || defined(SOLO_EXPERIMENTAL))
|
|
||||||
case CTAPHID_LOADKEY:
|
|
||||||
/**
|
|
||||||
* Load external key. Useful for enabling backups.
|
|
||||||
* bytes: 4 96
|
|
||||||
* payload: | counter_increase (BE) | master_key |
|
|
||||||
*
|
|
||||||
* Counter should be increased by a large amount, e.g. (0x10000000)
|
|
||||||
* to outdo any previously lost/broken keys.
|
|
||||||
*/
|
|
||||||
printf1(TAG_HID,"CTAPHID_LOADKEY\n");
|
|
||||||
if (len != 100)
|
|
||||||
{
|
|
||||||
printf2(TAG_ERR,"Error, invalid length.\n");
|
|
||||||
ctaphid_send_error(wb->cid, CTAP1_ERR_INVALID_LENGTH);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask for THREE button presses
|
|
||||||
if (ctap_user_presence_test(8000) > 0)
|
|
||||||
if (ctap_user_presence_test(8000) > 0)
|
|
||||||
if (ctap_user_presence_test(8000) > 0)
|
|
||||||
{
|
|
||||||
ctap_load_external_keys(ctap_buffer + 4);
|
|
||||||
param = ctap_buffer[3];
|
|
||||||
param |= ctap_buffer[2] << 8;
|
|
||||||
param |= ctap_buffer[1] << 16;
|
|
||||||
param |= ctap_buffer[0] << 24;
|
|
||||||
ctap_atomic_count(param);
|
|
||||||
|
|
||||||
wb->bcnt = 0;
|
|
||||||
|
|
||||||
ctaphid_write(wb, NULL, 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf2(TAG_ERR, "Error, invalid length.\n");
|
|
||||||
ctaphid_send_error(wb->cid, CTAP2_ERR_OPERATION_DENIED);
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -28,8 +28,6 @@
|
|||||||
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
|
#define CTAPHID_ENTERBOOT (TYPE_INIT | 0x51)
|
||||||
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
|
#define CTAPHID_ENTERSTBOOT (TYPE_INIT | 0x52)
|
||||||
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
|
#define CTAPHID_GETRNG (TYPE_INIT | 0x60)
|
||||||
#define CTAPHID_GETVERSION (TYPE_INIT | 0x61)
|
|
||||||
#define CTAPHID_LOADKEY (TYPE_INIT | 0x62)
|
|
||||||
// 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)
|
||||||
|
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
// Copyright 2019 SoloKeys Developers
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
|
||||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
|
||||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
|
||||||
// copied, modified, or distributed except according to those terms.
|
|
||||||
|
|
||||||
#include "data_migration.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "device.h"
|
|
||||||
#include "crypto.h"
|
|
||||||
|
|
||||||
// TODO move from macro to function/assert for better readability?
|
|
||||||
#define check(x) assert(state_prev_0xff->x == state_tmp_ptr->x);
|
|
||||||
#define check_buf(x) assert(memcmp(state_prev_0xff->x, state_tmp_ptr->x, sizeof(state_tmp_ptr->x)) == 0);
|
|
||||||
|
|
||||||
bool migrate_from_FF_to_01(AuthenticatorState_0xFF* state_prev_0xff, AuthenticatorState_0x01* state_tmp_ptr){
|
|
||||||
// Calculate PIN hash, and replace PIN raw storage with it; add version to structure
|
|
||||||
// other ingredients do not change
|
|
||||||
if (state_tmp_ptr->data_version != 0xFF)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static_assert(sizeof(AuthenticatorState_0xFF) <= sizeof(AuthenticatorState_0x01), "New state structure is smaller, than current one, which is not handled");
|
|
||||||
|
|
||||||
if (ctap_generate_rng(state_tmp_ptr->PIN_SALT, sizeof(state_tmp_ptr->PIN_SALT)) != 1) {
|
|
||||||
printf2(TAG_ERR, "Error, rng failed\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (state_prev_0xff->is_pin_set){
|
|
||||||
crypto_sha256_init();
|
|
||||||
crypto_sha256_update(state_prev_0xff->pin_code, state_prev_0xff->pin_code_length);
|
|
||||||
uint8_t intermediateHash[32];
|
|
||||||
crypto_sha256_final(intermediateHash);
|
|
||||||
|
|
||||||
crypto_sha256_init();
|
|
||||||
crypto_sha256_update(intermediateHash, 16);
|
|
||||||
memset(intermediateHash, 0, sizeof(intermediateHash));
|
|
||||||
crypto_sha256_update(state_tmp_ptr->PIN_SALT, sizeof(state_tmp_ptr->PIN_SALT));
|
|
||||||
crypto_sha256_final(state_tmp_ptr->PIN_CODE_HASH);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(state_tmp_ptr->_reserved == state_prev_0xff->pin_code_length);
|
|
||||||
state_tmp_ptr->_reserved = 0xFF;
|
|
||||||
state_tmp_ptr->data_version = 1;
|
|
||||||
|
|
||||||
check(is_initialized);
|
|
||||||
check(is_pin_set);
|
|
||||||
check(remaining_tries);
|
|
||||||
check(rk_stored);
|
|
||||||
check_buf(key_lens);
|
|
||||||
check_buf(key_space);
|
|
||||||
assert(state_tmp_ptr->data_version != 0xFF);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_migrated_state(AuthenticatorState *state_tmp_ptr) {
|
|
||||||
memmove(&STATE, state_tmp_ptr, sizeof(AuthenticatorState));
|
|
||||||
authenticator_write_state(state_tmp_ptr, 0);
|
|
||||||
authenticator_write_state(state_tmp_ptr, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_migration_if_required(AuthenticatorState* state_current){
|
|
||||||
// Currently handles only state structures with the same size, or bigger
|
|
||||||
// FIXME rework to raw buffers with fixed size to allow state structure size decrease
|
|
||||||
if(!state_current->is_initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AuthenticatorState state_tmp;
|
|
||||||
AuthenticatorState state_previous;
|
|
||||||
authenticator_read_state(&state_previous);
|
|
||||||
authenticator_read_state(&state_tmp);
|
|
||||||
if(state_current->data_version == 0xFF){
|
|
||||||
printf2(TAG_ERR, "Running migration\n");
|
|
||||||
bool success = migrate_from_FF_to_01((AuthenticatorState_0xFF *) &state_previous, &state_tmp);
|
|
||||||
if (!success){
|
|
||||||
printf2(TAG_ERR, "Failed migration from 0xFF to 1\n");
|
|
||||||
// FIXME discuss migration failure behavior
|
|
||||||
goto return_cleanup;
|
|
||||||
}
|
|
||||||
dump_hex1(TAG_ERR, (void*)&state_tmp, sizeof(state_tmp));
|
|
||||||
dump_hex1(TAG_ERR, (void*)&state_previous, sizeof(state_previous));
|
|
||||||
save_migrated_state(&state_tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(state_current->data_version == STATE_VERSION);
|
|
||||||
|
|
||||||
return_cleanup:
|
|
||||||
memset(&state_tmp, 0, sizeof(AuthenticatorState));
|
|
||||||
memset(&state_previous, 0, sizeof(AuthenticatorState));
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2019 SoloKeys Developers
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
|
||||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
|
||||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
|
||||||
// copied, modified, or distributed except according to those terms.
|
|
||||||
|
|
||||||
#ifndef FIDO2_PR_DATA_MIGRATION_H
|
|
||||||
#define FIDO2_PR_DATA_MIGRATION_H
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
|
|
||||||
void do_migration_if_required(AuthenticatorState* state_current);
|
|
||||||
|
|
||||||
#endif //FIDO2_PR_DATA_MIGRATION_H
|
|
@ -30,7 +30,6 @@ void main_loop_delay();
|
|||||||
|
|
||||||
void heartbeat();
|
void heartbeat();
|
||||||
|
|
||||||
void device_reboot();
|
|
||||||
|
|
||||||
void authenticator_read_state(AuthenticatorState * );
|
void authenticator_read_state(AuthenticatorState * );
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ void device_set_status(uint32_t status);
|
|||||||
int device_is_button_pressed();
|
int device_is_button_pressed();
|
||||||
|
|
||||||
// Test for user presence
|
// Test for user presence
|
||||||
// Return 2 for disabled, 1 for user is present, 0 user not present, -1 if cancel is requested.
|
// Return 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||||
int ctap_user_presence_test(uint32_t delay);
|
int ctap_user_presence_test(uint32_t delay);
|
||||||
|
|
||||||
// Generate @num bytes of random numbers to @dest
|
// Generate @num bytes of random numbers to @dest
|
||||||
@ -61,8 +60,8 @@ int ctap_user_presence_test(uint32_t delay);
|
|||||||
int ctap_generate_rng(uint8_t * dst, size_t num);
|
int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||||
|
|
||||||
// Increment atomic counter and return it.
|
// Increment atomic counter and return it.
|
||||||
// @param amount the amount to increase the counter by.
|
// Must support two counters, @sel selects counter0 or counter1.
|
||||||
uint32_t ctap_atomic_count(uint32_t amount);
|
uint32_t ctap_atomic_count(int sel);
|
||||||
|
|
||||||
// Verify the user
|
// Verify the user
|
||||||
// return 1 if user is verified, 0 if not
|
// return 1 if user is verified, 0 if not
|
||||||
@ -106,7 +105,7 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param);
|
|||||||
#define NFC_IS_AVAILABLE 2
|
#define NFC_IS_AVAILABLE 2
|
||||||
int device_is_nfc();
|
int device_is_nfc();
|
||||||
|
|
||||||
void device_disable_up(bool request_active);
|
void request_from_nfc(bool request_active);
|
||||||
|
|
||||||
void device_init_button();
|
void device_init_button();
|
||||||
|
|
||||||
|
@ -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,7 +50,6 @@ 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,7 +44,6 @@ typedef enum
|
|||||||
TAG_EXT = (1 << 18),
|
TAG_EXT = (1 << 18),
|
||||||
TAG_NFC = (1 << 19),
|
TAG_NFC = (1 << 19),
|
||||||
TAG_NFC_APDU = (1 << 20),
|
TAG_NFC_APDU = (1 << 20),
|
||||||
TAG_CCID = (1 << 21),
|
|
||||||
|
|
||||||
TAG_NO_TAG = (1UL << 30),
|
TAG_NO_TAG = (1UL << 30),
|
||||||
TAG_FILENO = (1UL << 31)
|
TAG_FILENO = (1UL << 31)
|
||||||
|
@ -46,7 +46,6 @@ int main(int argc, char *argv[])
|
|||||||
TAG_GREEN|
|
TAG_GREEN|
|
||||||
TAG_RED|
|
TAG_RED|
|
||||||
TAG_EXT|
|
TAG_EXT|
|
||||||
TAG_CCID|
|
|
||||||
TAG_ERR
|
TAG_ERR
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
|
|
||||||
#define KEY_SPACE_BYTES 128
|
#define KEY_SPACE_BYTES 128
|
||||||
#define MAX_KEYS (1)
|
#define MAX_KEYS (1)
|
||||||
#define PIN_SALT_LEN (32)
|
|
||||||
#define STATE_VERSION (1)
|
|
||||||
|
|
||||||
|
|
||||||
#define BACKUP_MARKER 0x5A
|
#define BACKUP_MARKER 0x5A
|
||||||
#define INITIALIZED_MARKER 0xA5
|
#define INITIALIZED_MARKER 0xA5
|
||||||
@ -22,40 +19,20 @@
|
|||||||
#define ERR_KEY_SPACE_TAKEN (-2)
|
#define ERR_KEY_SPACE_TAKEN (-2)
|
||||||
#define ERR_KEY_SPACE_EMPTY (-2)
|
#define ERR_KEY_SPACE_EMPTY (-2)
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
// Pin information
|
|
||||||
uint8_t is_initialized;
|
|
||||||
uint8_t is_pin_set;
|
|
||||||
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
|
|
||||||
int pin_code_length;
|
|
||||||
int8_t remaining_tries;
|
|
||||||
|
|
||||||
uint16_t rk_stored;
|
|
||||||
|
|
||||||
uint16_t key_lens[MAX_KEYS];
|
|
||||||
uint8_t key_space[KEY_SPACE_BYTES];
|
|
||||||
} AuthenticatorState_0xFF;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
// Pin information
|
// Pin information
|
||||||
uint8_t is_initialized;
|
uint8_t is_initialized;
|
||||||
uint8_t is_pin_set;
|
uint8_t is_pin_set;
|
||||||
uint8_t PIN_CODE_HASH[32];
|
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
|
||||||
uint8_t PIN_SALT[PIN_SALT_LEN];
|
int pin_code_length;
|
||||||
int _reserved;
|
|
||||||
int8_t remaining_tries;
|
int8_t remaining_tries;
|
||||||
|
|
||||||
uint16_t rk_stored;
|
uint16_t rk_stored;
|
||||||
|
|
||||||
uint16_t key_lens[MAX_KEYS];
|
uint16_t key_lens[MAX_KEYS];
|
||||||
uint8_t key_space[KEY_SPACE_BYTES];
|
uint8_t key_space[KEY_SPACE_BYTES];
|
||||||
uint8_t data_version;
|
} AuthenticatorState;
|
||||||
} AuthenticatorState_0x01;
|
|
||||||
|
|
||||||
typedef AuthenticatorState_0x01 AuthenticatorState;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
58
fido2/u2f.c
58
fido2/u2f.c
@ -26,7 +26,6 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
|||||||
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
||||||
void u2f_reset_response();
|
void u2f_reset_response();
|
||||||
|
|
||||||
void make_auth_tag(uint8_t * rpIdHash, uint8_t * nonce, uint32_t count, uint8_t * tag);
|
|
||||||
|
|
||||||
static CTAP_RESPONSE * _u2f_resp = NULL;
|
static CTAP_RESPONSE * _u2f_resp = NULL;
|
||||||
|
|
||||||
@ -119,9 +118,9 @@ void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONS
|
|||||||
if (!header)
|
if (!header)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
device_disable_up(true); // disable presence test
|
request_from_nfc(true); // disable presence test
|
||||||
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
|
||||||
device_disable_up(false); // enable presence test
|
request_from_nfc(false); // enable presence test
|
||||||
}
|
}
|
||||||
|
|
||||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||||
@ -161,9 +160,9 @@ static void dump_signature_der(uint8_t * sig)
|
|||||||
len = ctap_encode_der_sig(sig, sigder);
|
len = ctap_encode_der_sig(sig, sigder);
|
||||||
u2f_response_writeback(sigder, len);
|
u2f_response_writeback(sigder, len);
|
||||||
}
|
}
|
||||||
static int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t khl, uint8_t * appid)
|
static int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t * appid)
|
||||||
{
|
{
|
||||||
crypto_ecc256_load_key((uint8_t*)kh, khl, NULL, 0);
|
crypto_ecc256_load_key((uint8_t*)kh, U2F_KEY_HANDLE_SIZE, NULL, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,41 +187,21 @@ int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pu
|
|||||||
|
|
||||||
|
|
||||||
// Return 1 if authenticate, 0 if not.
|
// Return 1 if authenticate, 0 if not.
|
||||||
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t key_handle_len, uint8_t * appid)
|
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid)
|
||||||
{
|
{
|
||||||
printf1(TAG_U2F, "checked CRED SIZE %d. (FIDO2: %d)\n", key_handle_len, sizeof(CredentialId));
|
|
||||||
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
|
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
|
||||||
|
u2f_make_auth_tag(kh, appid, tag);
|
||||||
if (key_handle_len == sizeof(CredentialId))
|
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
|
||||||
{
|
{
|
||||||
printf1(TAG_U2F, "FIDO2 key handle detected.\n");
|
return 1;
|
||||||
CredentialId * cred = (CredentialId *) kh;
|
}
|
||||||
// FIDO2 credential.
|
else
|
||||||
|
{
|
||||||
if (memcmp(cred->rpIdHash, appid, 32) != 0)
|
printf1(TAG_U2F, "key handle + appid not authentic\n");
|
||||||
{
|
printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE);
|
||||||
printf1(TAG_U2F, "APPID does not match rpIdHash.\n");
|
printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
make_auth_tag(appid, cred->nonce, cred->count, tag);
|
|
||||||
|
|
||||||
if (memcmp(cred->tag, tag, CREDENTIAL_TAG_SIZE) == 0){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}else if (key_handle_len == U2F_KEY_HANDLE_SIZE)
|
|
||||||
{
|
|
||||||
u2f_make_auth_tag(kh, appid, tag);
|
|
||||||
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_U2F, "key handle + appid not authentic\n");
|
|
||||||
printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE);
|
|
||||||
printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -237,7 +216,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
|||||||
if (control == U2F_AUTHENTICATE_CHECK)
|
if (control == U2F_AUTHENTICATE_CHECK)
|
||||||
{
|
{
|
||||||
printf1(TAG_U2F, "CHECK-ONLY\r\n");
|
printf1(TAG_U2F, "CHECK-ONLY\r\n");
|
||||||
if (u2f_authenticate_credential(&req->kh, req->khl, req->app))
|
if (u2f_authenticate_credential(&req->kh, req->app))
|
||||||
{
|
{
|
||||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||||
}
|
}
|
||||||
@ -248,8 +227,9 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) ||
|
(control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) ||
|
||||||
(!u2f_authenticate_credential(&req->kh, req->khl, req->app)) || // Order of checks is important
|
req->khl != U2F_KEY_HANDLE_SIZE ||
|
||||||
u2f_load_key(&req->kh, req->khl, req->app) != 0
|
(!u2f_authenticate_credential(&req->kh, req->app)) || // Order of checks is important
|
||||||
|
u2f_load_key(&req->kh, req->app) != 0
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
|
|||||||
// @len data length
|
// @len data length
|
||||||
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
|
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
|
||||||
|
|
||||||
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t key_handle_len, uint8_t * appid);
|
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);
|
||||||
|
|
||||||
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
||||||
void u2f_reset_response();
|
void u2f_reset_response();
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#include "version.h"
|
|
||||||
|
|
||||||
|
|
||||||
const version_t firmware_version __attribute__ ((section (".flag"))) __attribute__ ((__used__)) = {
|
|
||||||
.major = SOLO_VERSION_MAJ,
|
|
||||||
.minor = SOLO_VERSION_MIN,
|
|
||||||
.patch = SOLO_VERSION_PATCH,
|
|
||||||
.reserved = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// from tinycbor, for a quick static_assert
|
|
||||||
#include <compilersupport_p.h>
|
|
||||||
cbor_static_assert(sizeof(version_t) == 4);
|
|
@ -17,23 +17,5 @@
|
|||||||
#define SOLO_VERSION __STR(SOLO_VERSION_MAJ) "." __STR(SOLO_VERSION_MIN) "." __STR(SOLO_VERSION_PATCH)
|
#define SOLO_VERSION __STR(SOLO_VERSION_MAJ) "." __STR(SOLO_VERSION_MIN) "." __STR(SOLO_VERSION_PATCH)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union{
|
|
||||||
uint32_t raw;
|
|
||||||
struct {
|
|
||||||
uint8_t major;
|
|
||||||
uint8_t minor;
|
|
||||||
uint8_t patch;
|
|
||||||
uint8_t reserved;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} version_t;
|
|
||||||
|
|
||||||
bool is_newer(const version_t* const newer, const version_t* const older);
|
|
||||||
const version_t firmware_version ;
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
34
pc/device.c
34
pc/device.c
@ -26,7 +26,6 @@
|
|||||||
#define RK_NUM 50
|
#define RK_NUM 50
|
||||||
|
|
||||||
bool use_udp = true;
|
bool use_udp = true;
|
||||||
static bool _up_disabled = false;
|
|
||||||
|
|
||||||
struct ResidentKeyStore {
|
struct ResidentKeyStore {
|
||||||
CTAP_residentKey rks[RK_NUM];
|
CTAP_residentKey rks[RK_NUM];
|
||||||
@ -44,11 +43,7 @@ void device_set_status(uint32_t status)
|
|||||||
__device_status = status;
|
__device_status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_reboot()
|
|
||||||
{
|
|
||||||
printf1(TAG_RED, "REBOOT command recieved!\r\n");
|
|
||||||
exit(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
int udp_server()
|
int udp_server()
|
||||||
{
|
{
|
||||||
@ -108,7 +103,6 @@ int udp_recv(int fd, uint8_t * buf, int size)
|
|||||||
perror( "recvfrom failed" );
|
perror( "recvfrom failed" );
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
printf1(TAG_DUMP, ">>"); dump_hex1(TAG_DUMP, buf, length);
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +119,6 @@ void udp_send(int fd, uint8_t * buf, int size)
|
|||||||
perror( "sendto failed" );
|
perror( "sendto failed" );
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_DUMP, "<<"); dump_hex1(TAG_DUMP, buf, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -303,10 +295,6 @@ void ctaphid_write_block(uint8_t * data)
|
|||||||
|
|
||||||
int ctap_user_presence_test(uint32_t d)
|
int ctap_user_presence_test(uint32_t d)
|
||||||
{
|
{
|
||||||
if (_up_disabled)
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,11 +304,20 @@ int ctap_user_verification(uint8_t arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t ctap_atomic_count(uint32_t amount)
|
uint32_t ctap_atomic_count(int sel)
|
||||||
{
|
{
|
||||||
static uint32_t counter1 = 25;
|
static uint32_t counter1 = 25;
|
||||||
counter1 += (amount + 1);
|
/*return 713;*/
|
||||||
return counter1;
|
if (sel == 0)
|
||||||
|
{
|
||||||
|
printf1(TAG_RED,"counter1: %d\n", counter1);
|
||||||
|
return counter1++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"counter2 not imple\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ctap_generate_rng(uint8_t * dst, size_t num)
|
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||||
@ -632,11 +629,6 @@ 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)
|
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -90,7 +90,8 @@ flash_dfu: solo.hex bootloader.hex
|
|||||||
# STM32_Programmer_CLI -c port=usb1 -halt -e all --readunprotect
|
# STM32_Programmer_CLI -c port=usb1 -halt -e all --readunprotect
|
||||||
STM32_Programmer_CLI -c port=usb1 -halt -rdu -d all.hex
|
STM32_Programmer_CLI -c port=usb1 -halt -rdu -d all.hex
|
||||||
|
|
||||||
flashboot: bootloader.hex
|
flashboot: solo.hex bootloader.hex
|
||||||
|
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
||||||
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
|
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
|
||||||
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
|
STM32_Programmer_CLI -c port=SWD -halt -d bootloader.hex -rst
|
||||||
|
|
||||||
|
@ -19,12 +19,6 @@
|
|||||||
#include "ctap_errors.h"
|
#include "ctap_errors.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
volatile version_t current_firmware_version __attribute__ ((section (".flag2"))) __attribute__ ((__used__)) = {
|
|
||||||
.major = SOLO_VERSION_MAJ,
|
|
||||||
.minor = SOLO_VERSION_MIN,
|
|
||||||
.patch = SOLO_VERSION_PATCH,
|
|
||||||
.reserved = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
extern uint8_t REBOOT_FLAG;
|
extern uint8_t REBOOT_FLAG;
|
||||||
|
|
||||||
@ -62,6 +56,8 @@ static void erase_application()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LAST_ADDR (APPLICATION_END_ADDR-2048 + 8)
|
||||||
|
#define LAST_PAGE (APPLICATION_END_PAGE-1)
|
||||||
static void disable_bootloader()
|
static void disable_bootloader()
|
||||||
{
|
{
|
||||||
// Clear last 4 bytes of the last application page-1, which is 108th
|
// Clear last 4 bytes of the last application page-1, which is 108th
|
||||||
@ -106,38 +102,6 @@ int is_bootloader_disabled()
|
|||||||
uint32_t * auth = (uint32_t *)(AUTH_WORD_ADDR+4);
|
uint32_t * auth = (uint32_t *)(AUTH_WORD_ADDR+4);
|
||||||
return *auth == 0;
|
return *auth == 0;
|
||||||
}
|
}
|
||||||
uint8_t * last_written_app_address;
|
|
||||||
|
|
||||||
#include "version.h"
|
|
||||||
bool is_firmware_version_newer_or_equal()
|
|
||||||
{
|
|
||||||
|
|
||||||
printf1(TAG_BOOT,"Current firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
|
|
||||||
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
|
|
||||||
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
|
|
||||||
);
|
|
||||||
volatile version_t * new_version = ((volatile version_t *) last_written_app_address);
|
|
||||||
printf1(TAG_BOOT,"Uploaded firmware version: %u.%u.%u.%u (%02x.%02x.%02x.%02x)\r\n",
|
|
||||||
new_version->major, new_version->minor, new_version->patch, new_version->reserved,
|
|
||||||
new_version->major, new_version->minor, new_version->patch, new_version->reserved
|
|
||||||
);
|
|
||||||
|
|
||||||
const bool allowed = is_newer((const version_t *)new_version, (const version_t *)¤t_firmware_version) || current_firmware_version.raw == 0xFFFFFFFF;
|
|
||||||
if (allowed){
|
|
||||||
printf1(TAG_BOOT, "Update allowed, setting new firmware version as current.\r\n");
|
|
||||||
// current_firmware_version.raw = new_version.raw;
|
|
||||||
uint8_t page[PAGE_SIZE];
|
|
||||||
memmove(page, (uint8_t*)BOOT_VERSION_ADDR, PAGE_SIZE);
|
|
||||||
memmove(page, (version_t *)new_version, 4);
|
|
||||||
printf1(TAG_BOOT, "Writing\r\n");
|
|
||||||
flash_erase_page(BOOT_VERSION_PAGE);
|
|
||||||
flash_write(BOOT_VERSION_ADDR, page, PAGE_SIZE);
|
|
||||||
printf1(TAG_BOOT, "Finish\r\n");
|
|
||||||
} else {
|
|
||||||
printf1(TAG_BOOT, "Firmware older - update not allowed.\r\n");
|
|
||||||
}
|
|
||||||
return allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute bootloader commands
|
* Execute bootloader commands
|
||||||
@ -161,7 +125,10 @@ int bootloader_bridge(int klen, uint8_t * keyh)
|
|||||||
return CTAP1_ERR_INVALID_LENGTH;
|
return CTAP1_ERR_INVALID_LENGTH;
|
||||||
}
|
}
|
||||||
#ifndef SOLO_HACKER
|
#ifndef SOLO_HACKER
|
||||||
extern uint8_t *pubkey_boot;
|
uint8_t * pubkey = (uint8_t*)"\xd2\xa4\x2f\x8f\xb2\x31\x1c\xc1\xf7\x0c\x7e\x64\x32\xfb\xbb\xb4\xa3\xdd\x32\x20"
|
||||||
|
"\x0f\x1b\x88\x9c\xda\x62\xc2\x83\x25\x93\xdd\xb8\x75\x9d\xf9\x86\xee\x03\x6c\xce"
|
||||||
|
"\x34\x47\x71\x36\xb3\xb2\xad\x6d\x12\xb7\xbe\x49\x3e\x20\xa4\x61\xac\xc7\x71\xc7"
|
||||||
|
"\x1f\xa8\x14\xf2";
|
||||||
|
|
||||||
const struct uECC_Curve_t * curve = NULL;
|
const struct uECC_Curve_t * curve = NULL;
|
||||||
#endif
|
#endif
|
||||||
@ -198,11 +165,12 @@ int bootloader_bridge(int klen, uint8_t * keyh)
|
|||||||
}
|
}
|
||||||
// Do the actual write
|
// Do the actual write
|
||||||
flash_write((uint32_t)ptr,req->payload, len);
|
flash_write((uint32_t)ptr,req->payload, len);
|
||||||
last_written_app_address = (uint8_t *)ptr + len - 8 + 4;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BootDone:
|
case BootDone:
|
||||||
// Writing to flash finished. Request code validation.
|
// Writing to flash finished. Request code validation.
|
||||||
printf1(TAG_BOOT, "BootDone: \r\n");
|
printf1(TAG_BOOT, "BootDone: ");
|
||||||
#ifndef SOLO_HACKER
|
#ifndef SOLO_HACKER
|
||||||
if (len != 64)
|
if (len != 64)
|
||||||
{
|
{
|
||||||
@ -217,23 +185,17 @@ int bootloader_bridge(int klen, uint8_t * keyh)
|
|||||||
crypto_sha256_final(hash);
|
crypto_sha256_final(hash);
|
||||||
curve = uECC_secp256r1();
|
curve = uECC_secp256r1();
|
||||||
// Verify incoming signature made over the SHA256 hash
|
// Verify incoming signature made over the SHA256 hash
|
||||||
if (
|
if (! uECC_verify(pubkey,
|
||||||
!uECC_verify(pubkey_boot, hash, 32, req->payload, curve)
|
hash,
|
||||||
)
|
32,
|
||||||
|
req->payload,
|
||||||
|
curve))
|
||||||
{
|
{
|
||||||
printf1(TAG_BOOT, "Signature invalid\r\n");
|
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
}
|
}
|
||||||
if (!is_firmware_version_newer_or_equal()){
|
|
||||||
printf1(TAG_BOOT, "Firmware older - update not allowed.\r\n");
|
|
||||||
printf1(TAG_BOOT, "Rebooting...\r\n");
|
|
||||||
REBOOT_FLAG = 1;
|
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
// Set the application validated, and mark for reboot.
|
// Set the application validated, and mark for reboot.
|
||||||
authorize_application();
|
authorize_application();
|
||||||
|
|
||||||
REBOOT_FLAG = 1;
|
REBOOT_FLAG = 1;
|
||||||
break;
|
break;
|
||||||
case BootCheck:
|
case BootCheck:
|
||||||
@ -256,7 +218,6 @@ int bootloader_bridge(int klen, uint8_t * keyh)
|
|||||||
break;
|
break;
|
||||||
case BootReboot:
|
case BootReboot:
|
||||||
printf1(TAG_BOOT, "BootReboot.\r\n");
|
printf1(TAG_BOOT, "BootReboot.\r\n");
|
||||||
printf1(TAG_BOOT, "Application authorized: %d.\r\n", is_authorized_to_boot());
|
|
||||||
REBOOT_FLAG = 1;
|
REBOOT_FLAG = 1;
|
||||||
break;
|
break;
|
||||||
case BootDisable:
|
case BootDisable:
|
||||||
@ -316,10 +277,3 @@ void bootloader_heartbeat()
|
|||||||
|
|
||||||
led_rgb(((val * g)<<8) | ((val*r) << 16) | (val*b));
|
led_rgb(((val * g)<<8) | ((val*r) << 16) | (val*b));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ctap_atomic_count(uint32_t amount)
|
|
||||||
{
|
|
||||||
static uint32_t count = 1000;
|
|
||||||
count += (amount + 1);
|
|
||||||
return count;
|
|
||||||
}
|
|
@ -138,14 +138,6 @@ int main()
|
|||||||
|
|
||||||
printf1(TAG_GEN,"recv'ing hid msg \n");
|
printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||||
|
|
||||||
extern volatile version_t current_firmware_version;
|
|
||||||
printf1(TAG_BOOT,"Current firmware version address: %p\r\n", ¤t_firmware_version);
|
|
||||||
printf1(TAG_BOOT,"Current firmware version: %d.%d.%d.%d (%02x.%02x.%02x.%02x)\r\n",
|
|
||||||
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved,
|
|
||||||
current_firmware_version.major, current_firmware_version.minor, current_firmware_version.patch, current_firmware_version.reserved
|
|
||||||
);
|
|
||||||
dump_hex1(TAG_BOOT, (uint8_t*)(¤t_firmware_version) - 16, 32);
|
|
||||||
|
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
uint8_t * pubkey_boot = (uint8_t*)"\xd2\xa4\x2f\x8f\xb2\x31\x1c\xc1\xf7\x0c\x7e\x64\x32\xfb\xbb\xb4\xa3\xdd\x32\x20"
|
|
||||||
"\x0f\x1b\x88\x9c\xda\x62\xc2\x83\x25\x93\xdd\xb8\x75\x9d\xf9\x86\xee\x03\x6c\xce"
|
|
||||||
"\x34\x47\x71\x36\xb3\xb2\xad\x6d\x12\xb7\xbe\x49\x3e\x20\xa4\x61\xac\xc7\x71\xc7"
|
|
||||||
"\x1f\xa8\x14\xf2";
|
|
@ -1,8 +0,0 @@
|
|||||||
#include "version.h"
|
|
||||||
|
|
||||||
// FIXME test version check function
|
|
||||||
bool is_newer(const version_t* const newer, const version_t* const older){
|
|
||||||
return (newer->major > older->major) ||
|
|
||||||
(newer->major == older->major && newer->minor > older->minor) ||
|
|
||||||
(newer->major == older->major && newer->minor == older->minor && newer->patch >= older->patch);
|
|
||||||
}
|
|
@ -10,8 +10,6 @@ SRC += $(DRIVER_LIBS) $(USB_LIB)
|
|||||||
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
||||||
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
|
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
|
||||||
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
|
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
|
||||||
SRC += ../../fido2/version.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
|
||||||
|
|
||||||
@ -71,7 +69,6 @@ all: $(TARGET).elf
|
|||||||
|
|
||||||
%.elf: $(OBJ)
|
%.elf: $(OBJ)
|
||||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||||
@echo "Built version: $(VERSION_FLAGS)"
|
|
||||||
|
|
||||||
%.hex: %.elf
|
%.hex: %.elf
|
||||||
$(SZ) $^
|
$(SZ) $^
|
||||||
|
@ -2,7 +2,6 @@ include build/common.mk
|
|||||||
|
|
||||||
# ST related
|
# ST related
|
||||||
SRC = bootloader/main.c bootloader/bootloader.c
|
SRC = bootloader/main.c bootloader/bootloader.c
|
||||||
SRC += bootloader/pubkey_bootloader.c bootloader/version_check.c
|
|
||||||
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
SRC += src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
||||||
SRC += src/fifo.c src/crypto.c src/attestation.c src/sense.c
|
SRC += src/fifo.c src/crypto.c src/attestation.c src/sense.c
|
||||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||||
@ -66,7 +65,6 @@ all: $(TARGET).elf
|
|||||||
|
|
||||||
%.elf: $(OBJ)
|
%.elf: $(OBJ)
|
||||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||||
arm-none-eabi-size $@
|
|
||||||
|
|
||||||
%.hex: %.elf
|
%.hex: %.elf
|
||||||
$(CP) -O ihex $^ $(TARGET).hex
|
$(CP) -O ihex $^ $(TARGET).hex
|
||||||
|
@ -10,8 +10,7 @@ DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_
|
|||||||
|
|
||||||
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
|
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
|
||||||
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
|
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
|
||||||
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \
|
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c
|
||||||
lib/usbd/usbd_ccid.c
|
|
||||||
|
|
||||||
VERSION:=$(shell git describe --abbrev=0 )
|
VERSION:=$(shell git describe --abbrev=0 )
|
||||||
VERSION_FULL:=$(shell git describe)
|
VERSION_FULL:=$(shell git describe)
|
||||||
|
@ -1,319 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "usbd_ccid.h"
|
|
||||||
#include "usbd_ctlreq.h"
|
|
||||||
#include "usbd_conf.h"
|
|
||||||
#include "usbd_core.h"
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx);
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx);
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req);
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_DataIn (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t epnum);
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_DataOut (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t epnum);
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_EP0_RxReady (USBD_HandleTypeDef *pdev);
|
|
||||||
|
|
||||||
|
|
||||||
USBD_ClassTypeDef USBD_CCID =
|
|
||||||
{
|
|
||||||
USBD_CCID_Init,
|
|
||||||
USBD_CCID_DeInit,
|
|
||||||
USBD_CCID_Setup,
|
|
||||||
NULL, /* EP0_TxSent, */
|
|
||||||
USBD_CCID_EP0_RxReady,
|
|
||||||
USBD_CCID_DataIn,
|
|
||||||
USBD_CCID_DataOut,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint8_t ccidmsg_buf[CCID_DATA_PACKET_SIZE];
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0U;
|
|
||||||
USBD_CCID_HandleTypeDef *hcdc;
|
|
||||||
|
|
||||||
//Y
|
|
||||||
USBD_LL_OpenEP(pdev, CCID_IN_EP, USBD_EP_TYPE_BULK,
|
|
||||||
CCID_DATA_PACKET_SIZE);
|
|
||||||
|
|
||||||
USBD_LL_OpenEP(pdev, CCID_OUT_EP, USBD_EP_TYPE_BULK,
|
|
||||||
CCID_DATA_PACKET_SIZE);
|
|
||||||
|
|
||||||
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 1U;
|
|
||||||
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 1U;
|
|
||||||
|
|
||||||
|
|
||||||
USBD_LL_OpenEP(pdev, CCID_CMD_EP, USBD_EP_TYPE_INTR, CCID_DATA_PACKET_SIZE);
|
|
||||||
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 1U;
|
|
||||||
|
|
||||||
// dump_pma_header("ccid.c");
|
|
||||||
|
|
||||||
static USBD_CCID_HandleTypeDef mem;
|
|
||||||
pdev->pClassData = &mem;
|
|
||||||
|
|
||||||
hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
|
|
||||||
|
|
||||||
// init transfer states
|
|
||||||
hcdc->TxState = 0U;
|
|
||||||
hcdc->RxState = 0U;
|
|
||||||
|
|
||||||
USBD_LL_PrepareReceive(&Solo_USBD_Device, CCID_OUT_EP, ccidmsg_buf,
|
|
||||||
CCID_DATA_PACKET_SIZE);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t USBD_CCID_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0U;
|
|
||||||
//N
|
|
||||||
|
|
||||||
USBD_LL_CloseEP(pdev, CCID_IN_EP);
|
|
||||||
pdev->ep_in[CCID_IN_EP & 0xFU].is_used = 0U;
|
|
||||||
|
|
||||||
USBD_LL_CloseEP(pdev, CCID_OUT_EP);
|
|
||||||
pdev->ep_out[CCID_OUT_EP & 0xFU].is_used = 0U;
|
|
||||||
|
|
||||||
USBD_LL_CloseEP(pdev, CCID_CMD_EP);
|
|
||||||
pdev->ep_in[CCID_CMD_EP & 0xFU].is_used = 0U;
|
|
||||||
|
|
||||||
/* DeInit physical Interface components */
|
|
||||||
if(pdev->pClassData != NULL)
|
|
||||||
{
|
|
||||||
pdev->pClassData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_Setup
|
|
||||||
* Handle the CDC specific requests
|
|
||||||
* @param pdev: instance
|
|
||||||
* @param req: usb requests
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_CCID_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req)
|
|
||||||
{
|
|
||||||
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
|
|
||||||
uint8_t ifalt = 0U;
|
|
||||||
uint16_t status_info = 0U;
|
|
||||||
uint8_t ret = USBD_OK;
|
|
||||||
//N
|
|
||||||
|
|
||||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
||||||
{
|
|
||||||
case USB_REQ_TYPE_CLASS :
|
|
||||||
if (req->wLength)
|
|
||||||
{
|
|
||||||
if (req->bmRequest & 0x80U)
|
|
||||||
{
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)hcdc->data, req->wLength);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hcdc->CmdOpCode = req->bRequest;
|
|
||||||
hcdc->CmdLength = (uint8_t)req->wLength;
|
|
||||||
|
|
||||||
USBD_CtlPrepareRx (pdev, (uint8_t *)(void *)hcdc->data, req->wLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_TYPE_STANDARD:
|
|
||||||
switch (req->bRequest)
|
|
||||||
{
|
|
||||||
case USB_REQ_GET_STATUS:
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&status_info, 2U);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_GET_INTERFACE:
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
USBD_CtlSendData (pdev, &ifalt, 1U);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_SET_INTERFACE:
|
|
||||||
if (pdev->dev_state != USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case USB_REQ_GET_DESCRIPTOR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_DataIn
|
|
||||||
* Data sent on non-control IN endpoint
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param epnum: endpoint number
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_CCID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
{
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
static uint8_t USBD_CCID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
{
|
|
||||||
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*)pdev->pClassData;
|
|
||||||
|
|
||||||
hcdc->TxState = 0U;
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t USBD_CCID_TransmitPacket(uint8_t * msg, int len)
|
|
||||||
{
|
|
||||||
/* Update the packet total length */
|
|
||||||
Solo_USBD_Device.ep_in[CCID_IN_EP & 0xFU].total_length = len;
|
|
||||||
|
|
||||||
while (PCD_GET_EP_TX_STATUS(USB, CCID_IN_EP & 0x0f) == USB_EP_TX_VALID)
|
|
||||||
;
|
|
||||||
/* Transmit next packet */
|
|
||||||
USBD_LL_Transmit(&Solo_USBD_Device, CCID_IN_EP, msg,
|
|
||||||
len);
|
|
||||||
|
|
||||||
printf1(TAG_CCID,"<< ");
|
|
||||||
dump_hex1(TAG_CCID, msg, len);
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ccid_send_status(CCID_HEADER * c, uint8_t status)
|
|
||||||
{
|
|
||||||
uint8_t msg[CCID_HEADER_SIZE];
|
|
||||||
memset(msg,0,sizeof(msg));
|
|
||||||
|
|
||||||
msg[0] = CCID_SLOT_STATUS_RES;
|
|
||||||
msg[6] = c->seq;
|
|
||||||
msg[7] = status;
|
|
||||||
|
|
||||||
USBD_CCID_TransmitPacket(msg, sizeof(msg));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ccid_send_data_block(CCID_HEADER * c, uint8_t status)
|
|
||||||
{
|
|
||||||
uint8_t msg[CCID_HEADER_SIZE];
|
|
||||||
memset(msg,0,sizeof(msg));
|
|
||||||
|
|
||||||
msg[0] = CCID_DATA_BLOCK_RES;
|
|
||||||
msg[6] = c->seq;
|
|
||||||
msg[7] = status;
|
|
||||||
|
|
||||||
USBD_CCID_TransmitPacket(msg, sizeof(msg));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_ccid(uint8_t * msg, int len)
|
|
||||||
{
|
|
||||||
CCID_HEADER * h = (CCID_HEADER *) msg;
|
|
||||||
switch(h->type)
|
|
||||||
{
|
|
||||||
case CCID_SLOT_STATUS:
|
|
||||||
ccid_send_status(h, CCID_STATUS_ON);
|
|
||||||
break;
|
|
||||||
case CCID_POWER_ON:
|
|
||||||
ccid_send_data_block(h, CCID_STATUS_ON);
|
|
||||||
break;
|
|
||||||
case CCID_POWER_OFF:
|
|
||||||
ccid_send_status(h, CCID_STATUS_OFF);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ccid_send_status(h, CCID_STATUS_ON);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_DataOut
|
|
||||||
* Data received on non-control Out endpoint
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param epnum: endpoint number
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
uint8_t usb_ccid_recieve_callback(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
{
|
|
||||||
|
|
||||||
USBD_CCID_HandleTypeDef *hcdc = (USBD_CCID_HandleTypeDef*) pdev->pClassData;
|
|
||||||
|
|
||||||
/* Get the received data length */
|
|
||||||
hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
|
|
||||||
|
|
||||||
printf1(TAG_CCID, ">> ");
|
|
||||||
dump_hex1(TAG_CCID, ccidmsg_buf, hcdc->RxLength);
|
|
||||||
|
|
||||||
handle_ccid(ccidmsg_buf, hcdc->RxLength);
|
|
||||||
|
|
||||||
USBD_LL_PrepareReceive(&Solo_USBD_Device, CCID_OUT_EP, ccidmsg_buf,
|
|
||||||
CCID_DATA_PACKET_SIZE);
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_CDC_EP0_RxReady
|
|
||||||
* Handle EP0 Rx Ready event
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_CCID_EP0_RxReady (USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
#ifndef _USBD_H_
|
|
||||||
#define _USBD_H_
|
|
||||||
|
|
||||||
#include "usbd_ioreq.h"
|
|
||||||
|
|
||||||
#define CCID_HEADER_SIZE 10
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t type;
|
|
||||||
uint32_t len;
|
|
||||||
uint8_t slot;
|
|
||||||
uint8_t seq;
|
|
||||||
uint8_t rsvd;
|
|
||||||
uint16_t param;
|
|
||||||
} __attribute__((packed)) CCID_HEADER;
|
|
||||||
|
|
||||||
#define CCID_IN_EP 0x86U /* EP1 for data IN */
|
|
||||||
#define CCID_OUT_EP 0x04U /* EP1 for data OUT */
|
|
||||||
#define CCID_CMD_EP 0x85U /* EP2 for CDC commands */
|
|
||||||
|
|
||||||
#define CCID_DATA_PACKET_SIZE 64
|
|
||||||
|
|
||||||
#define CCID_SET_PARAMS 0x61
|
|
||||||
#define CCID_POWER_ON 0x62
|
|
||||||
#define CCID_POWER_OFF 0x63
|
|
||||||
#define CCID_SLOT_STATUS 0x65
|
|
||||||
#define CCID_SECURE 0x69
|
|
||||||
#define CCID_GET_PARAMS 0x6C
|
|
||||||
#define CCID_RESET_PARAMS 0x6D
|
|
||||||
#define CCID_XFR_BLOCK 0x6F
|
|
||||||
|
|
||||||
#define CCID_STATUS_ON 0x00
|
|
||||||
#define CCID_STATUS_OFF 0x02
|
|
||||||
|
|
||||||
#define CCID_DATA_BLOCK_RES 0x80
|
|
||||||
#define CCID_SLOT_STATUS_RES 0x81
|
|
||||||
#define CCID_PARAMS_RES 0x82
|
|
||||||
|
|
||||||
extern USBD_ClassTypeDef USBD_CCID;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t data[CCID_DATA_PACKET_SIZE / 4U];
|
|
||||||
uint8_t CmdOpCode;
|
|
||||||
uint8_t CmdLength;
|
|
||||||
uint8_t *RxBuffer;
|
|
||||||
uint8_t *TxBuffer;
|
|
||||||
uint32_t RxLength;
|
|
||||||
uint32_t TxLength;
|
|
||||||
|
|
||||||
__IO uint32_t TxState;
|
|
||||||
__IO uint32_t RxState;
|
|
||||||
}
|
|
||||||
USBD_CCID_HandleTypeDef;
|
|
||||||
|
|
||||||
uint8_t usb_ccid_recieve_callback(USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
||||||
|
|
||||||
#endif
|
|
@ -195,9 +195,302 @@ USBD_ClassTypeDef USBD_CDC =
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
// USBD_CDC_GetHSCfgDesc,
|
||||||
|
// USBD_CDC_GetFSCfgDesc,
|
||||||
|
// USBD_CDC_GetOtherSpeedCfgDesc,
|
||||||
|
// USBD_CDC_GetDeviceQualifierDescriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* USB CDC device Configuration Descriptor */
|
||||||
|
__ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
|
||||||
|
{
|
||||||
|
/*Configuration Descriptor*/
|
||||||
|
0x09, /* bLength: Configuration Descriptor size */
|
||||||
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
||||||
|
USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
|
||||||
|
0x00,
|
||||||
|
0x02, /* bNumInterfaces: 2 interface */
|
||||||
|
0x01, /* bConfigurationValue: Configuration value */
|
||||||
|
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||||
|
0xC0, /* bmAttributes: self powered */
|
||||||
|
0x32, /* MaxPower 0 mA */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*Interface Descriptor */
|
||||||
|
0x09, /* bLength: Interface Descriptor size */
|
||||||
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
||||||
|
/* Interface descriptor type */
|
||||||
|
0x00, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x01, /* bNumEndpoints: One endpoints used */
|
||||||
|
0x02, /* bInterfaceClass: Communication Interface Class */
|
||||||
|
0x02, /* bInterfaceSubClass: Abstract Control Model */
|
||||||
|
0x01, /* bInterfaceProtocol: Common AT commands */
|
||||||
|
0x00, /* iInterface: */
|
||||||
|
|
||||||
|
/*Header Functional Descriptor*/
|
||||||
|
0x05, /* bLength: Endpoint Descriptor size */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x00, /* bDescriptorSubtype: Header Func Desc */
|
||||||
|
0x10, /* bcdCDC: spec release number */
|
||||||
|
0x01,
|
||||||
|
|
||||||
|
/*Call Management Functional Descriptor*/
|
||||||
|
0x05, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
||||||
|
0x00, /* bmCapabilities: D0+D1 */
|
||||||
|
0x01, /* bDataInterface: 1 */
|
||||||
|
|
||||||
|
/*ACM Functional Descriptor*/
|
||||||
|
0x04, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
|
||||||
|
0x02, /* bmCapabilities */
|
||||||
|
|
||||||
|
/*Union Functional Descriptor*/
|
||||||
|
0x05, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x06, /* bDescriptorSubtype: Union func desc */
|
||||||
|
0x00, /* bMasterInterface: Communication class interface */
|
||||||
|
0x01, /* bSlaveInterface0: Data Class Interface */
|
||||||
|
|
||||||
|
/*Endpoint 2 Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_CMD_EP, /* bEndpointAddress */
|
||||||
|
0x03, /* bmAttributes: Interrupt */
|
||||||
|
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_CMD_PACKET_SIZE),
|
||||||
|
CDC_HS_BINTERVAL, /* bInterval: */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*Data class interface descriptor*/
|
||||||
|
0x09, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
||||||
|
0x01, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x02, /* bNumEndpoints: Two endpoints used */
|
||||||
|
0x0A, /* bInterfaceClass: CDC */
|
||||||
|
0x00, /* bInterfaceSubClass: */
|
||||||
|
0x00, /* bInterfaceProtocol: */
|
||||||
|
0x00, /* iInterface: */
|
||||||
|
|
||||||
|
/*Endpoint OUT Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_OUT_EP, /* bEndpointAddress */
|
||||||
|
0x02, /* bmAttributes: Bulk */
|
||||||
|
LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),
|
||||||
|
0x00, /* bInterval: ignore for Bulk transfer */
|
||||||
|
|
||||||
|
/*Endpoint IN Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_IN_EP, /* bEndpointAddress */
|
||||||
|
0x02, /* bmAttributes: Bulk */
|
||||||
|
LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),
|
||||||
|
0x00 /* bInterval: ignore for Bulk transfer */
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
/* USB CDC device Configuration Descriptor */
|
||||||
|
__ALIGN_BEGIN uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
|
||||||
|
{
|
||||||
|
/*Configuration Descriptor*/
|
||||||
|
0x09, /* bLength: Configuration Descriptor size */
|
||||||
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
||||||
|
USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
|
||||||
|
0x00,
|
||||||
|
0x02, /* bNumInterfaces: 2 interface */
|
||||||
|
0x01, /* bConfigurationValue: Configuration value */
|
||||||
|
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
||||||
|
0xC0, /* bmAttributes: self powered */
|
||||||
|
0x32, /* MaxPower 0 mA */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*Interface Descriptor */
|
||||||
|
0x09, /* bLength: Interface Descriptor size */
|
||||||
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
||||||
|
/* Interface descriptor type */
|
||||||
|
0x00, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x01, /* bNumEndpoints: One endpoints used */
|
||||||
|
0x02, /* bInterfaceClass: Communication Interface Class */
|
||||||
|
0x02, /* bInterfaceSubClass: Abstract Control Model */
|
||||||
|
0x01, /* bInterfaceProtocol: Common AT commands */
|
||||||
|
0x00, /* iInterface: */
|
||||||
|
|
||||||
|
/*Header Functional Descriptor*/
|
||||||
|
0x05, /* bLength: Endpoint Descriptor size */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x00, /* bDescriptorSubtype: Header Func Desc */
|
||||||
|
0x10, /* bcdCDC: spec release number */
|
||||||
|
0x01,
|
||||||
|
|
||||||
|
/*Call Management Functional Descriptor*/
|
||||||
|
0x05, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
||||||
|
0x00, /* bmCapabilities: D0+D1 */
|
||||||
|
0x01, /* bDataInterface: 1 */
|
||||||
|
|
||||||
|
/*ACM Functional Descriptor*/
|
||||||
|
0x04, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
|
||||||
|
0x02, /* bmCapabilities */
|
||||||
|
|
||||||
|
/*Union Functional Descriptor*/
|
||||||
|
0x05, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x06, /* bDescriptorSubtype: Union func desc */
|
||||||
|
0x00, /* bMasterInterface: Communication class interface */
|
||||||
|
0x01, /* bSlaveInterface0: Data Class Interface */
|
||||||
|
|
||||||
|
/*Endpoint 2 Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_CMD_EP, /* bEndpointAddress */
|
||||||
|
0x03, /* bmAttributes: Interrupt */
|
||||||
|
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_CMD_PACKET_SIZE),
|
||||||
|
CDC_FS_BINTERVAL, /* bInterval: */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*Data class interface descriptor*/
|
||||||
|
0x09, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
||||||
|
0x01, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x02, /* bNumEndpoints: Two endpoints used */
|
||||||
|
0x0A, /* bInterfaceClass: CDC */
|
||||||
|
0x00, /* bInterfaceSubClass: */
|
||||||
|
0x00, /* bInterfaceProtocol: */
|
||||||
|
0x00, /* iInterface: */
|
||||||
|
|
||||||
|
/*Endpoint OUT Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_OUT_EP, /* bEndpointAddress */
|
||||||
|
0x02, /* bmAttributes: Bulk */
|
||||||
|
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
||||||
|
0x00, /* bInterval: ignore for Bulk transfer */
|
||||||
|
|
||||||
|
/*Endpoint IN Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_IN_EP, /* bEndpointAddress */
|
||||||
|
0x02, /* bmAttributes: Bulk */
|
||||||
|
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
||||||
|
0x00 /* bInterval: ignore for Bulk transfer */
|
||||||
|
} ;
|
||||||
|
|
||||||
|
__ALIGN_BEGIN uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
|
||||||
|
{
|
||||||
|
0x09, /* bLength: Configuation Descriptor size */
|
||||||
|
USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION,
|
||||||
|
USB_CDC_CONFIG_DESC_SIZ,
|
||||||
|
0x00,
|
||||||
|
0x02, /* bNumInterfaces: 2 interfaces */
|
||||||
|
0x01, /* bConfigurationValue: */
|
||||||
|
0x04, /* iConfiguration: */
|
||||||
|
0xC0, /* bmAttributes: */
|
||||||
|
0x32, /* MaxPower 100 mA */
|
||||||
|
|
||||||
|
/*Interface Descriptor */
|
||||||
|
0x09, /* bLength: Interface Descriptor size */
|
||||||
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
||||||
|
/* Interface descriptor type */
|
||||||
|
0x00, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x01, /* bNumEndpoints: One endpoints used */
|
||||||
|
0x02, /* bInterfaceClass: Communication Interface Class */
|
||||||
|
0x02, /* bInterfaceSubClass: Abstract Control Model */
|
||||||
|
0x01, /* bInterfaceProtocol: Common AT commands */
|
||||||
|
0x00, /* iInterface: */
|
||||||
|
|
||||||
|
/*Header Functional Descriptor*/
|
||||||
|
0x05, /* bLength: Endpoint Descriptor size */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x00, /* bDescriptorSubtype: Header Func Desc */
|
||||||
|
0x10, /* bcdCDC: spec release number */
|
||||||
|
0x01,
|
||||||
|
|
||||||
|
/*Call Management Functional Descriptor*/
|
||||||
|
0x05, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
||||||
|
0x00, /* bmCapabilities: D0+D1 */
|
||||||
|
0x01, /* bDataInterface: 1 */
|
||||||
|
|
||||||
|
/*ACM Functional Descriptor*/
|
||||||
|
0x04, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
|
||||||
|
0x02, /* bmCapabilities */
|
||||||
|
|
||||||
|
/*Union Functional Descriptor*/
|
||||||
|
0x05, /* bFunctionLength */
|
||||||
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
||||||
|
0x06, /* bDescriptorSubtype: Union func desc */
|
||||||
|
0x00, /* bMasterInterface: Communication class interface */
|
||||||
|
0x01, /* bSlaveInterface0: Data Class Interface */
|
||||||
|
|
||||||
|
/*Endpoint 2 Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT , /* bDescriptorType: Endpoint */
|
||||||
|
CDC_CMD_EP, /* bEndpointAddress */
|
||||||
|
0x03, /* bmAttributes: Interrupt */
|
||||||
|
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
|
||||||
|
HIBYTE(CDC_CMD_PACKET_SIZE),
|
||||||
|
CDC_FS_BINTERVAL, /* bInterval: */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*Data class interface descriptor*/
|
||||||
|
0x09, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
||||||
|
0x01, /* bInterfaceNumber: Number of Interface */
|
||||||
|
0x00, /* bAlternateSetting: Alternate setting */
|
||||||
|
0x02, /* bNumEndpoints: Two endpoints used */
|
||||||
|
0x0A, /* bInterfaceClass: CDC */
|
||||||
|
0x00, /* bInterfaceSubClass: */
|
||||||
|
0x00, /* bInterfaceProtocol: */
|
||||||
|
0x00, /* iInterface: */
|
||||||
|
|
||||||
|
/*Endpoint OUT Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_OUT_EP, /* bEndpointAddress */
|
||||||
|
0x02, /* bmAttributes: Bulk */
|
||||||
|
0x40, /* wMaxPacketSize: */
|
||||||
|
0x00,
|
||||||
|
0x00, /* bInterval: ignore for Bulk transfer */
|
||||||
|
|
||||||
|
/*Endpoint IN Descriptor*/
|
||||||
|
0x07, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
||||||
|
CDC_IN_EP, /* bEndpointAddress */
|
||||||
|
0x02, /* bmAttributes: Bulk */
|
||||||
|
0x40, /* wMaxPacketSize: */
|
||||||
|
0x00,
|
||||||
|
0x00 /* bInterval */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup USBD_CDC_Private_Functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USBD_CDC_Init
|
* @brief USBD_CDC_Init
|
||||||
@ -489,7 +782,45 @@ static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
|
|||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USBD_CDC_GetFSCfgDesc
|
||||||
|
* Return configuration descriptor
|
||||||
|
* @param speed : current device speed
|
||||||
|
* @param length : pointer data length
|
||||||
|
* @retval pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
/*static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
|
||||||
|
{
|
||||||
|
*length = sizeof (USBD_CDC_CfgFSDesc);
|
||||||
|
return USBD_CDC_CfgFSDesc;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief USBD_CDC_GetHSCfgDesc
|
||||||
|
* Return configuration descriptor
|
||||||
|
* @param speed : current device speed
|
||||||
|
* @param length : pointer data length
|
||||||
|
* @retval pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
/*static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
|
||||||
|
{
|
||||||
|
*length = sizeof (USBD_CDC_CfgHSDesc);
|
||||||
|
return USBD_CDC_CfgHSDesc;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief USBD_CDC_GetCfgDesc
|
||||||
|
* Return configuration descriptor
|
||||||
|
* @param speed : current device speed
|
||||||
|
* @param length : pointer data length
|
||||||
|
* @retval pointer to descriptor buffer
|
||||||
|
*/
|
||||||
|
/*static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
|
||||||
|
{
|
||||||
|
*length = sizeof (USBD_CDC_OtherSpeedCfgDesc);
|
||||||
|
return USBD_CDC_OtherSpeedCfgDesc;
|
||||||
|
}
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* @brief DeviceQualifierDescriptor
|
* @brief DeviceQualifierDescriptor
|
||||||
* return Device Qualifier descriptor
|
* return Device Qualifier descriptor
|
||||||
@ -608,10 +939,22 @@ uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
|
|||||||
/* Suspend or Resume USB Out process */
|
/* Suspend or Resume USB Out process */
|
||||||
if(pdev->pClassData != NULL)
|
if(pdev->pClassData != NULL)
|
||||||
{
|
{
|
||||||
|
if(pdev->dev_speed == USBD_SPEED_HIGH )
|
||||||
|
{
|
||||||
|
/* Prepare Out endpoint to receive next packet */
|
||||||
|
USBD_LL_PrepareReceive(pdev,
|
||||||
|
CDC_OUT_EP,
|
||||||
|
hcdc->RxBuffer,
|
||||||
|
CDC_DATA_HS_OUT_PACKET_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Prepare Out endpoint to receive next packet */
|
||||||
USBD_LL_PrepareReceive(pdev,
|
USBD_LL_PrepareReceive(pdev,
|
||||||
CDC_OUT_EP,
|
CDC_OUT_EP,
|
||||||
hcdc->RxBuffer,
|
hcdc->RxBuffer,
|
||||||
CDC_DATA_FS_OUT_PACKET_SIZE);
|
CDC_DATA_FS_OUT_PACKET_SIZE);
|
||||||
|
}
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
#include "usbd_desc.h"
|
#include "usbd_desc.h"
|
||||||
#include "usbd_hid.h"
|
#include "usbd_hid.h"
|
||||||
#include "usbd_cdc.h"
|
#include "usbd_cdc.h"
|
||||||
#include "usbd_ccid.h"
|
|
||||||
#include "usbd_ctlreq.h"
|
#include "usbd_ctlreq.h"
|
||||||
#include "app.h"
|
|
||||||
|
|
||||||
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
||||||
|
|
||||||
@ -28,33 +26,18 @@ static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length);
|
|||||||
|
|
||||||
static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
|
static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
|
||||||
|
|
||||||
#ifdef ENABLE_CCID
|
#define NUM_CLASSES 2
|
||||||
#define CCID_SIZE 84
|
#define NUM_INTERFACES 3
|
||||||
#define CCID_NUM_INTERFACE 1
|
|
||||||
|
#if NUM_INTERFACES>1
|
||||||
|
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90 + 8+9 + 4)
|
||||||
#else
|
#else
|
||||||
#define CCID_NUM_INTERFACE 0
|
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (41)
|
||||||
#define CCID_SIZE 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG_LEVEL > 0
|
|
||||||
#define CDC_SIZE (49 + 8 + 9 + 4)
|
|
||||||
#define CDC_NUM_INTERFACE 2
|
|
||||||
#else
|
|
||||||
#define CDC_SIZE 0
|
|
||||||
#define CDC_NUM_INTERFACE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HID_SIZE 41
|
|
||||||
|
|
||||||
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (HID_SIZE + CDC_SIZE + CCID_SIZE)
|
|
||||||
#define NUM_INTERFACES (1 + CDC_NUM_INTERFACE + CCID_NUM_INTERFACE)
|
|
||||||
#define NUM_CLASSES 3
|
|
||||||
|
|
||||||
|
|
||||||
#define HID_INTF_NUM 0
|
#define HID_INTF_NUM 0
|
||||||
#define CDC_MASTER_INTF_NUM 1
|
#define CDC_MASTER_INTF_NUM 1
|
||||||
#define CDC_SLAVE_INTF_NUM 2
|
#define CDC_SLAVE_INTF_NUM 2
|
||||||
#define CCID_INTF_NUM 3
|
|
||||||
__ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END =
|
__ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END =
|
||||||
{
|
{
|
||||||
/*Configuration Descriptor*/
|
/*Configuration Descriptor*/
|
||||||
@ -111,7 +94,7 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
|
|||||||
0x00,
|
0x00,
|
||||||
HID_BINTERVAL, /*bInterval: Polling Interval */
|
HID_BINTERVAL, /*bInterval: Polling Interval */
|
||||||
|
|
||||||
#if DEBUG_LEVEL > 0
|
#if NUM_INTERFACES > 1
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
/* CDC */
|
/* CDC */
|
||||||
@ -208,83 +191,6 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
|
|||||||
0x09,
|
0x09,
|
||||||
0x04,
|
0x04,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_CCID
|
|
||||||
|
|
||||||
/* CCID Interface Descriptor */
|
|
||||||
9, /* bLength: Interface Descriptor size */
|
|
||||||
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
||||||
CCID_INTF_NUM, /* bInterfaceNumber: CCID Interface */
|
|
||||||
0, /* Alternate setting for this interface */
|
|
||||||
3, /* bNumEndpoints: Bulk-IN, Bulk-OUT, Intr-IN */
|
|
||||||
0x0B, /* CCID class */
|
|
||||||
0x00, /* CCID subclass */
|
|
||||||
0x00, /* CCID protocol */
|
|
||||||
0, /* string index for interface */
|
|
||||||
|
|
||||||
/* ICC Descriptor */
|
|
||||||
54, /* bLength: */
|
|
||||||
0x21, /* bDescriptorType: USBDESCR_ICC */
|
|
||||||
0x10, 0x01, /* bcdCCID: revision 1.1 (of CCID) */
|
|
||||||
0, /* bMaxSlotIndex: */
|
|
||||||
1, /* bVoltageSupport: 5V-only */
|
|
||||||
0x02, 0, 0, 0, /* dwProtocols: T=1 */
|
|
||||||
0xa0, 0x0f, 0, 0, /* dwDefaultClock: 4000 */
|
|
||||||
0xa0, 0x0f, 0, 0, /* dwMaximumClock: 4000 */
|
|
||||||
0, /* bNumClockSupported: 0x00 */
|
|
||||||
0x80, 0x25, 0, 0, /* dwDataRate: 9600 */
|
|
||||||
0x80, 0x25, 0, 0, /* dwMaxDataRate: 9600 */
|
|
||||||
0, /* bNumDataRateSupported: 0x00 */
|
|
||||||
0xfe, 0, 0, 0, /* dwMaxIFSD: 254 */
|
|
||||||
0, 0, 0, 0, /* dwSynchProtocols: 0 */
|
|
||||||
0, 0, 0, 0, /* dwMechanical: 0 */
|
|
||||||
0x7a, 0x04, 0x02, 0x00, /* dwFeatures:
|
|
||||||
* Short and extended APDU level: 0x40000 ----
|
|
||||||
* Short APDU level : 0x20000 *
|
|
||||||
* (ICCD?) : 0x00800 ----
|
|
||||||
* Automatic IFSD : 0x00400 *
|
|
||||||
* NAD value other than 0x00 : 0x00200
|
|
||||||
* Can set ICC in clock stop : 0x00100
|
|
||||||
* Automatic PPS CUR : 0x00080
|
|
||||||
* Automatic PPS PROP : 0x00040 *
|
|
||||||
* Auto baud rate change : 0x00020 *
|
|
||||||
* Auto clock change : 0x00010 *
|
|
||||||
* Auto voltage selection : 0x00008 *
|
|
||||||
* Auto activaction of ICC : 0x00004
|
|
||||||
* Automatic conf. based on ATR : 0x00002 *
|
|
||||||
*/
|
|
||||||
0x0f, 0x01, 0, 0, /* dwMaxCCIDMessageLength: 271 */
|
|
||||||
0xff, /* bClassGetResponse: 0xff */
|
|
||||||
0x00, /* bClassEnvelope: 0 */
|
|
||||||
0, 0, /* wLCDLayout: 0 */
|
|
||||||
0, /* bPinSupport: No PIN pad */
|
|
||||||
|
|
||||||
1, /* bMaxCCIDBusySlots: 1 */
|
|
||||||
/*Endpoint IN1 Descriptor*/
|
|
||||||
7, /* bLength: Endpoint Descriptor size */
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
||||||
CCID_IN_EP, /* bEndpointAddress: (IN1) */
|
|
||||||
0x02, /* bmAttributes: Bulk */
|
|
||||||
CCID_DATA_PACKET_SIZE, 0x00, /* wMaxPacketSize: */
|
|
||||||
0x00, /* bInterval */
|
|
||||||
/*Endpoint OUT1 Descriptor*/
|
|
||||||
7, /* bLength: Endpoint Descriptor size */
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
||||||
CCID_OUT_EP, /* bEndpointAddress: (OUT1) */
|
|
||||||
0x02, /* bmAttributes: Bulk */
|
|
||||||
CCID_DATA_PACKET_SIZE, 0x00, /* wMaxPacketSize: */
|
|
||||||
0x00, /* bInterval */
|
|
||||||
/*Endpoint IN2 Descriptor*/
|
|
||||||
7, /* bLength: Endpoint Descriptor size */
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
||||||
CCID_CMD_EP, /* bEndpointAddress: (IN2) */
|
|
||||||
0x03, /* bmAttributes: Interrupt */
|
|
||||||
CCID_DATA_PACKET_SIZE, 0x00, /* wMaxPacketSize: 4 */
|
|
||||||
0xFF, /* bInterval (255ms) */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
USBD_ClassTypeDef USBD_Composite =
|
USBD_ClassTypeDef USBD_Composite =
|
||||||
@ -305,21 +211,15 @@ USBD_ClassTypeDef USBD_Composite =
|
|||||||
USBD_Composite_GetDeviceQualifierDescriptor,
|
USBD_Composite_GetDeviceQualifierDescriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
static USBD_ClassTypeDef * USBD_Classes[MAX_CLASSES];
|
static USBD_ClassTypeDef *USBD_Classes[MAX_CLASSES];
|
||||||
|
|
||||||
int in_endpoint_to_class[MAX_ENDPOINTS];
|
int in_endpoint_to_class[MAX_ENDPOINTS];
|
||||||
|
|
||||||
int out_endpoint_to_class[MAX_ENDPOINTS];
|
int out_endpoint_to_class[MAX_ENDPOINTS];
|
||||||
|
|
||||||
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *ccid_class, USBD_ClassTypeDef *cdc_class) {
|
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *cdc_class) {
|
||||||
memset(USBD_Classes, 0 , sizeof(USBD_Classes));
|
|
||||||
USBD_Classes[0] = hid_class;
|
USBD_Classes[0] = hid_class;
|
||||||
#ifdef ENABLE_CCID
|
USBD_Classes[1] = cdc_class;
|
||||||
USBD_Classes[1] = ccid_class;
|
|
||||||
#endif
|
|
||||||
#if DEBUG_LEVEL > 0
|
|
||||||
USBD_Classes[2] = cdc_class;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static USBD_ClassTypeDef * getClass(uint8_t index)
|
static USBD_ClassTypeDef * getClass(uint8_t index)
|
||||||
@ -328,15 +228,9 @@ static USBD_ClassTypeDef * getClass(uint8_t index)
|
|||||||
{
|
{
|
||||||
case HID_INTF_NUM:
|
case HID_INTF_NUM:
|
||||||
return USBD_Classes[0];
|
return USBD_Classes[0];
|
||||||
#ifdef ENABLE_CCID
|
|
||||||
case CCID_INTF_NUM:
|
|
||||||
return USBD_Classes[1];
|
|
||||||
#endif
|
|
||||||
#if DEBUG_LEVEL > 0
|
|
||||||
case CDC_MASTER_INTF_NUM:
|
case CDC_MASTER_INTF_NUM:
|
||||||
case CDC_SLAVE_INTF_NUM:
|
case CDC_SLAVE_INTF_NUM:
|
||||||
return USBD_Classes[2];
|
return USBD_Classes[1];
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -344,18 +238,18 @@ static USBD_ClassTypeDef * getClass(uint8_t index)
|
|||||||
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
|
static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < NUM_CLASSES; i++) {
|
for(i = 0; i < NUM_CLASSES; i++) {
|
||||||
if (USBD_Classes[i] != NULL && USBD_Classes[i]->Init(pdev, cfgidx) != USBD_OK) {
|
if (USBD_Classes[i]->Init(pdev, cfgidx) != USBD_OK) {
|
||||||
return USBD_FAIL;
|
return USBD_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//N
|
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
|
static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < NUM_CLASSES; i++) {
|
for(i = 0; i < NUM_CLASSES; i++) {
|
||||||
if (USBD_Classes[i] != NULL && USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) {
|
if (USBD_Classes[i]->DeInit(pdev, cfgidx) != USBD_OK) {
|
||||||
return USBD_FAIL;
|
return USBD_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,7 +275,7 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
|
|||||||
|
|
||||||
case USB_REQ_GET_DESCRIPTOR :
|
case USB_REQ_GET_DESCRIPTOR :
|
||||||
for(i = 0; i < NUM_CLASSES; i++) {
|
for(i = 0; i < NUM_CLASSES; i++) {
|
||||||
if (USBD_Classes[i] != NULL && USBD_Classes[i]->Setup(pdev, req) != USBD_OK) {
|
if (USBD_Classes[i]->Setup(pdev, req) != USBD_OK) {
|
||||||
return USBD_FAIL;
|
return USBD_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,8 +298,6 @@ static uint8_t USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) {
|
|||||||
|
|
||||||
i = in_endpoint_to_class[epnum];
|
i = in_endpoint_to_class[epnum];
|
||||||
|
|
||||||
if (USBD_Classes[i] == NULL) return USBD_FAIL;
|
|
||||||
|
|
||||||
return USBD_Classes[i]->DataIn(pdev, epnum);
|
return USBD_Classes[i]->DataIn(pdev, epnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,8 +306,6 @@ static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|||||||
|
|
||||||
i = out_endpoint_to_class[epnum];
|
i = out_endpoint_to_class[epnum];
|
||||||
|
|
||||||
if (USBD_Classes[i] == NULL) return USBD_FAIL;
|
|
||||||
|
|
||||||
return USBD_Classes[i]->DataOut(pdev, epnum);
|
return USBD_Classes[i]->DataOut(pdev, epnum);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -423,7 +313,7 @@ static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|||||||
static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) {
|
static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < NUM_CLASSES; i++) {
|
for(i = 0; i < NUM_CLASSES; i++) {
|
||||||
if (USBD_Classes[i] != NULL && USBD_Classes[i]->EP0_RxReady != NULL) {
|
if (USBD_Classes[i]->EP0_RxReady != NULL) {
|
||||||
if (USBD_Classes[i]->EP0_RxReady(pdev) != USBD_OK) {
|
if (USBD_Classes[i]->EP0_RxReady(pdev) != USBD_OK) {
|
||||||
return USBD_FAIL;
|
return USBD_FAIL;
|
||||||
}
|
}
|
||||||
@ -433,19 +323,16 @@ static uint8_t USBD_Composite_EP0_RxReady (USBD_HandleTypeDef *pdev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length) {
|
static uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length) {
|
||||||
//Y
|
|
||||||
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
||||||
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length) {
|
static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length) {
|
||||||
//N
|
|
||||||
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
||||||
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length) {
|
static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length) {
|
||||||
|
|
||||||
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
||||||
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
||||||
}
|
}
|
||||||
@ -466,7 +353,6 @@ __ALIGN_BEGIN static uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUAL
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length) {
|
uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length) {
|
||||||
//N
|
*length = sizeof (USBD_Composite_DeviceQualifierDesc);
|
||||||
*length = sizeof (USBD_Composite_DeviceQualifierDesc);
|
return USBD_Composite_DeviceQualifierDesc;
|
||||||
return USBD_Composite_DeviceQualifierDesc;
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ extern int in_endpoint_to_class[MAX_ENDPOINTS];
|
|||||||
|
|
||||||
extern int out_endpoint_to_class[MAX_ENDPOINTS];
|
extern int out_endpoint_to_class[MAX_ENDPOINTS];
|
||||||
|
|
||||||
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1, USBD_ClassTypeDef *class2);
|
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,6 @@
|
|||||||
#include "stm32l4xx_hal.h"
|
#include "stm32l4xx_hal.h"
|
||||||
#include "usbd_core.h"
|
#include "usbd_core.h"
|
||||||
#include "usbd_hid.h"
|
#include "usbd_hid.h"
|
||||||
#include "usbd_cdc.h"
|
|
||||||
#include "usbd_ccid.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
void SystemClock_Config(void);
|
void SystemClock_Config(void);
|
||||||
|
|
||||||
@ -120,14 +117,9 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
|
|||||||
USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
|
USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
|
||||||
switch(epnum)
|
switch(epnum)
|
||||||
{
|
{
|
||||||
case HID_EPOUT_ADDR:
|
case HID_ENDPOINT:
|
||||||
usb_hid_recieve_callback(epnum);
|
usb_hid_recieve_callback(epnum);
|
||||||
break;
|
break;
|
||||||
#ifdef ENABLE_CCID
|
|
||||||
case CCID_OUT_EP:
|
|
||||||
usb_ccid_recieve_callback((USBD_HandleTypeDef*)hpcd->pData, epnum);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +218,7 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
|
|||||||
{
|
{
|
||||||
USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
|
USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the low level portion of the device driver.
|
* @brief Initializes the low level portion of the device driver.
|
||||||
* @param pdev: Device handle
|
* @param pdev: Device handle
|
||||||
@ -259,20 +252,14 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
|
|||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
|
||||||
|
|
||||||
// HID
|
// HID
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR , PCD_SNG_BUF, 0x98);
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x98);
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR , PCD_SNG_BUF, 0xd8);
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xd8);
|
||||||
|
|
||||||
// CCID
|
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_OUT_EP , PCD_SNG_BUF, 0xd8 + 64); // data OUT
|
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_IN_EP , PCD_SNG_BUF, 0xd8 + 64*2); // data IN
|
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_CMD_EP , PCD_SNG_BUF, 0xd8 + 64*3); // commands
|
|
||||||
|
|
||||||
// CDC / uart
|
// CDC / uart
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_CMD_EP , PCD_SNG_BUF, 0xd8 + 64*4); // commands
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x02 , PCD_SNG_BUF, 0xd8 + 64); // data OUT
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, 0xd8 + 64*5); // data OUT
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0xd8 + 64*2); // data IN
|
||||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, 0xd8 + 64*6); // data IN
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x83 , PCD_SNG_BUF, 0xd8 + 64*3); // commands
|
||||||
|
|
||||||
// dump_pma_header("usbd_conf");
|
|
||||||
|
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
@ -323,7 +310,6 @@ USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,
|
|||||||
uint8_t ep_type,
|
uint8_t ep_type,
|
||||||
uint16_t ep_mps)
|
uint16_t ep_mps)
|
||||||
{
|
{
|
||||||
// printf1(TAG_RED,"LL_Open. ep: %x, %x\r\n", ep_addr, ep_type);
|
|
||||||
HAL_PCD_EP_Open((PCD_HandleTypeDef*) pdev->pData,
|
HAL_PCD_EP_Open((PCD_HandleTypeDef*) pdev->pData,
|
||||||
ep_addr,
|
ep_addr,
|
||||||
ep_mps,
|
ep_mps,
|
||||||
|
@ -12,17 +12,9 @@ _estack = 0x2000c000;
|
|||||||
|
|
||||||
_MIN_STACK_SIZE = 0x400;
|
_MIN_STACK_SIZE = 0x400;
|
||||||
|
|
||||||
/*
|
|
||||||
flash_cfg is for storing bootloader data, like last used firmware version.
|
|
||||||
bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin
|
|
||||||
*/
|
|
||||||
|
|
||||||
bootloader_configuration = 0x08000000 + 216*1024+8;
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K
|
flash (rx) : ORIGIN = 0x08000000, LENGTH = 20K
|
||||||
flash_cfg (rx) : ORIGIN = 0x08000000 + 216*1024+8, LENGTH = 2K-8
|
|
||||||
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
||||||
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
@ -47,11 +39,6 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
} >flash
|
} >flash
|
||||||
|
|
||||||
.flag2 bootloader_configuration :
|
|
||||||
{
|
|
||||||
KEEP(*(.flag2)) ;
|
|
||||||
} > flash_cfg
|
|
||||||
|
|
||||||
_sidata = LOADADDR(.data);
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
|
@ -12,17 +12,9 @@ _estack = 0x2000c000;
|
|||||||
|
|
||||||
_MIN_STACK_SIZE = 0x400;
|
_MIN_STACK_SIZE = 0x400;
|
||||||
|
|
||||||
/*
|
|
||||||
flash_cfg is for storing bootloader data, like last used firmware version.
|
|
||||||
bootloader_configuration should be equal to (APPLICATION_END_PAGE) page address, from targets/stm32l432/src/memory_layout.h:30; and equal to flash_cfg origin
|
|
||||||
*/
|
|
||||||
|
|
||||||
bootloader_configuration = 0x08000000 + 216*1024+8;
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K
|
flash (rx) : ORIGIN = 0x08000000, LENGTH = 32K
|
||||||
flash_cfg (rx) : ORIGIN = 0x08000000 + 216*1024+8, LENGTH = 2K-8
|
|
||||||
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
||||||
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
@ -47,11 +39,6 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
} >flash
|
} >flash
|
||||||
|
|
||||||
.flag2 bootloader_configuration :
|
|
||||||
{
|
|
||||||
KEEP(*(.flag2)) ;
|
|
||||||
} > flash_cfg
|
|
||||||
|
|
||||||
_sidata = LOADADDR(.data);
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
|
@ -13,21 +13,14 @@ _estack = 0x2000c000;
|
|||||||
_MIN_STACK_SIZE = 0x400;
|
_MIN_STACK_SIZE = 0x400;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
len | 20 KB/10p| 196KB-8-8/98p | 2kB/1p | 38 KB/19p |
|
Memory layout of device:
|
||||||
pos | 0->20 KB | 20->216KB-8-8 | 216kB -> 218 kB | 218->256 KB |
|
20 KB 198KB-8 38 KB
|
||||||
posp | 0-10 | 10-113 | 113-114 | 113-128 |
|
| bootloader | application | secrets/data |
|
||||||
desc | bootloader | application | bootloader data | secrets/data |
|
|
||||||
|
|
||||||
Last 8 bytes in application space are occupied by bootloader flags - app
|
|
||||||
authorization and bootloader activation flag.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Current firmware version number is concatenated to the firmware code - see .flag marker */
|
|
||||||
/* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader */
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rx) : ORIGIN = 0x08000000 + 20K, LENGTH = 216K - 20K - 8
|
flash (rx) : ORIGIN = 0x08005000, LENGTH = 198K - 8
|
||||||
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
||||||
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
@ -63,12 +56,6 @@ SECTIONS
|
|||||||
_edata = .;
|
_edata = .;
|
||||||
} >ram AT> flash
|
} >ram AT> flash
|
||||||
|
|
||||||
.flag :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
KEEP(*(.flag)) ;
|
|
||||||
} > flash
|
|
||||||
|
|
||||||
.bss :
|
.bss :
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -12,22 +12,9 @@ _estack = 0x2000c000;
|
|||||||
|
|
||||||
_MIN_STACK_SIZE = 0x400;
|
_MIN_STACK_SIZE = 0x400;
|
||||||
|
|
||||||
/*
|
|
||||||
len | 32 KB/16p| 184KB-8-8/92p | 2kB/1p | 38 KB/19p |
|
|
||||||
pos | 0->32 KB | 32->216KB-8-8 | 216kB -> 218 kB | 218->256 KB |
|
|
||||||
posp | 0-16 | 16-113 | 113-114 | 113-128 |
|
|
||||||
desc | bootloader | application | bootloader data | secrets/data |
|
|
||||||
|
|
||||||
Last 8 bytes in application space are occupied by bootloader flags - app
|
|
||||||
authorization and bootloader activation flag.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Current firmware version number is concatenated to the firmware code - see .flag marker */
|
|
||||||
/* flash length is (APPLICATION_END_PAGE-20*1024), where 20K is bootloader */
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash (rx) : ORIGIN = 0x08000000 + 20K + 12K, LENGTH = 216K - 20K - 12K - 8
|
flash (rx) : ORIGIN = 0x08008000, LENGTH = 186K - 8
|
||||||
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
||||||
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
sram2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
@ -63,12 +50,6 @@ SECTIONS
|
|||||||
_edata = .;
|
_edata = .;
|
||||||
} >ram AT> flash
|
} >ram AT> flash
|
||||||
|
|
||||||
.flag :
|
|
||||||
{
|
|
||||||
. = ALIGN(8);
|
|
||||||
KEEP(*(.flag)) ;
|
|
||||||
} > flash
|
|
||||||
|
|
||||||
.bss :
|
.bss :
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -8,25 +8,21 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "nfc.h"
|
#include "nfc.h"
|
||||||
|
|
||||||
static void flush_rx(void)
|
static void flush_rx()
|
||||||
{
|
{
|
||||||
while(LL_SPI_IsActiveFlag_RXNE(SPI1) != 0)
|
while(LL_SPI_IsActiveFlag_RXNE(SPI1) != 0)
|
||||||
{
|
{
|
||||||
LL_SPI_ReceiveData8(SPI1);
|
LL_SPI_ReceiveData8(SPI1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void wait_for_tx()
|
||||||
|
|
||||||
static void wait_for_tx(void)
|
|
||||||
{
|
{
|
||||||
// while (LL_SPI_IsActiveFlag_BSY(SPI1) == 1)
|
// while (LL_SPI_IsActiveFlag_BSY(SPI1) == 1)
|
||||||
// ;
|
// ;
|
||||||
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY)
|
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
static void wait_for_rx()
|
||||||
|
|
||||||
static void wait_for_rx(void)
|
|
||||||
{
|
{
|
||||||
while(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0)
|
while(LL_SPI_IsActiveFlag_RXNE(SPI1) == 0)
|
||||||
;
|
;
|
||||||
@ -274,7 +270,7 @@ void ams_print_int1(uint8_t int0)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int ams_init(void)
|
int ams_init()
|
||||||
{
|
{
|
||||||
LL_GPIO_SetPinMode(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN,LL_GPIO_MODE_OUTPUT);
|
LL_GPIO_SetPinMode(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN,LL_GPIO_MODE_OUTPUT);
|
||||||
LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN);
|
LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN);
|
||||||
@ -296,7 +292,7 @@ int ams_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ams_configure(void)
|
void ams_configure()
|
||||||
{
|
{
|
||||||
// Should not be used during passive operation.
|
// Should not be used during passive operation.
|
||||||
uint8_t block[4];
|
uint8_t block[4];
|
||||||
|
@ -39,8 +39,8 @@ typedef union
|
|||||||
#define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
#define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
||||||
#define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
#define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN)
|
||||||
|
|
||||||
int ams_init(void);
|
int ams_init();
|
||||||
void ams_configure(void);
|
void ams_configure();
|
||||||
|
|
||||||
void ams_read_buffer(uint8_t * data, int len);
|
void ams_read_buffer(uint8_t * data, int len);
|
||||||
void ams_write_buffer(uint8_t * data, int len);
|
void ams_write_buffer(uint8_t * data, int len);
|
||||||
|
@ -12,13 +12,9 @@
|
|||||||
#define DEBUG_UART USART1
|
#define DEBUG_UART USART1
|
||||||
|
|
||||||
#ifndef DEBUG_LEVEL
|
#ifndef DEBUG_LEVEL
|
||||||
// Enable the CDC ACM USB interface & debug logs (DEBUG_LEVEL > 0)
|
|
||||||
#define DEBUG_LEVEL 0
|
#define DEBUG_LEVEL 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable the CCID USB interface
|
|
||||||
// #define ENABLE_CCID
|
|
||||||
|
|
||||||
#define NON_BLOCK_PRINTING 0
|
#define NON_BLOCK_PRINTING 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,13 +61,12 @@ static uint8_t master_secret[64];
|
|||||||
static uint8_t transport_secret[32];
|
static uint8_t transport_secret[32];
|
||||||
|
|
||||||
|
|
||||||
void crypto_sha256_init(void)
|
void crypto_sha256_init()
|
||||||
{
|
{
|
||||||
sha256_init(&sha256_ctx);
|
sha256_init(&sha256_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void crypto_sha512_init(void)
|
void crypto_sha512_init() {
|
||||||
{
|
|
||||||
cf_sha512_init(&sha512_ctx);
|
cf_sha512_init(&sha512_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ void crypto_load_master_secret(uint8_t * key)
|
|||||||
memmove(transport_secret, key+64, 32);
|
memmove(transport_secret, key+64, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void crypto_reset_master_secret(void)
|
void crypto_reset_master_secret()
|
||||||
{
|
{
|
||||||
memset(master_secret, 0, 64);
|
memset(master_secret, 0, 64);
|
||||||
memset(transport_secret, 0, 32);
|
memset(transport_secret, 0, 32);
|
||||||
@ -108,8 +107,7 @@ void crypto_sha256_final(uint8_t * hash)
|
|||||||
sha256_final(&sha256_ctx, hash);
|
sha256_final(&sha256_ctx, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void crypto_sha512_final(uint8_t * hash)
|
void crypto_sha512_final(uint8_t * hash) {
|
||||||
{
|
|
||||||
// NB: there is also cf_sha512_digest
|
// NB: there is also cf_sha512_digest
|
||||||
cf_sha512_digest_final(&sha512_ctx, hash);
|
cf_sha512_digest_final(&sha512_ctx, hash);
|
||||||
}
|
}
|
||||||
@ -185,14 +183,14 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void crypto_ecc256_init(void)
|
void crypto_ecc256_init()
|
||||||
{
|
{
|
||||||
uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
|
uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
|
||||||
_es256_curve = uECC_secp256r1();
|
_es256_curve = uECC_secp256r1();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void crypto_ecc256_load_attestation_key(void)
|
void crypto_ecc256_load_attestation_key()
|
||||||
{
|
{
|
||||||
static uint8_t _key [32];
|
static uint8_t _key [32];
|
||||||
memmove(_key, (uint8_t*)ATTESTATION_KEY_ADDR, 32);
|
memmove(_key, (uint8_t*)ATTESTATION_KEY_ADDR, 32);
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#define LOW_FREQUENCY 1
|
#define LOW_FREQUENCY 1
|
||||||
#define HIGH_FREQUENCY 0
|
#define HIGH_FREQUENCY 0
|
||||||
|
|
||||||
void wait_for_usb_tether(void);
|
void wait_for_usb_tether();
|
||||||
|
|
||||||
|
|
||||||
uint32_t __90_ms = 0;
|
uint32_t __90_ms = 0;
|
||||||
@ -45,60 +45,27 @@ uint32_t __last_update = 0;
|
|||||||
extern PCD_HandleTypeDef hpcd;
|
extern PCD_HandleTypeDef hpcd;
|
||||||
static int _NFC_status = 0;
|
static int _NFC_status = 0;
|
||||||
static bool isLowFreq = 0;
|
static bool isLowFreq = 0;
|
||||||
static bool _up_disabled = false;
|
static bool _RequestComeFromNFC = false;
|
||||||
|
|
||||||
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||||
static int is_physical_button_pressed(void)
|
static int is_physical_button_pressed()
|
||||||
{
|
{
|
||||||
return (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN));
|
return (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_touch_button_pressed(void)
|
static int is_touch_button_pressed()
|
||||||
{
|
{
|
||||||
int is_pressed = (tsc_read_button(0) || tsc_read_button(1));
|
return tsc_read_button(0) || tsc_read_button(1);
|
||||||
#ifndef IS_BOOTLOADER
|
|
||||||
if (is_pressed)
|
|
||||||
{
|
|
||||||
// delay for debounce, and longer than polling timer period.
|
|
||||||
delay(95);
|
|
||||||
return (tsc_read_button(0) || tsc_read_button(1));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return is_pressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
|
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
|
||||||
|
|
||||||
static void edge_detect_touch_button(void)
|
void request_from_nfc(bool request_active) {
|
||||||
{
|
_RequestComeFromNFC = request_active;
|
||||||
static uint8_t last_touch = 0;
|
|
||||||
uint8_t current_touch = 0;
|
|
||||||
if (is_touch_button_pressed == IS_BUTTON_PRESSED)
|
|
||||||
{
|
|
||||||
current_touch = (tsc_read_button(0) || tsc_read_button(1));
|
|
||||||
|
|
||||||
// 1 sample per 25 ms
|
|
||||||
if ((millis() - __last_button_bounce_time) > 25)
|
|
||||||
{
|
|
||||||
// Detect "touch / rising edge"
|
|
||||||
if (!last_touch && current_touch)
|
|
||||||
{
|
|
||||||
__last_button_press_time = millis();
|
|
||||||
}
|
|
||||||
__last_button_bounce_time = millis();
|
|
||||||
last_touch = current_touch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void device_disable_up(bool disable)
|
|
||||||
{
|
|
||||||
_up_disabled = disable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer6 overflow handler. happens every ~90ms.
|
// Timer6 overflow handler. happens every ~90ms.
|
||||||
void TIM6_DAC_IRQHandler(void)
|
void TIM6_DAC_IRQHandler()
|
||||||
{
|
{
|
||||||
// timer is only 16 bits, so roll it over here
|
// timer is only 16 bits, so roll it over here
|
||||||
TIM6->SR = 0;
|
TIM6->SR = 0;
|
||||||
@ -111,7 +78,19 @@ void TIM6_DAC_IRQHandler(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@ -143,7 +122,7 @@ void USB_IRQHandler(void)
|
|||||||
HAL_PCD_IRQHandler(&hpcd);
|
HAL_PCD_IRQHandler(&hpcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t millis(void)
|
uint32_t millis()
|
||||||
{
|
{
|
||||||
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
||||||
}
|
}
|
||||||
@ -161,8 +140,9 @@ void device_set_status(uint32_t status)
|
|||||||
__device_status = status;
|
__device_status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_is_button_pressed(void)
|
int device_is_button_pressed()
|
||||||
{
|
{
|
||||||
|
|
||||||
return IS_BUTTON_PRESSED();
|
return IS_BUTTON_PRESSED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,13 +152,12 @@ void delay(uint32_t ms)
|
|||||||
while ((millis() - time) < ms)
|
while ((millis() - time) < ms)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
void device_reboot()
|
||||||
void device_reboot(void)
|
|
||||||
{
|
{
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_init_button(void)
|
void device_init_button()
|
||||||
{
|
{
|
||||||
if (tsc_sensor_exists())
|
if (tsc_sensor_exists())
|
||||||
{
|
{
|
||||||
@ -228,12 +207,12 @@ void device_init(int argc, char *argv[])
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_is_nfc(void)
|
int device_is_nfc()
|
||||||
{
|
{
|
||||||
return _NFC_status;
|
return _NFC_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_for_usb_tether(void)
|
void wait_for_usb_tether()
|
||||||
{
|
{
|
||||||
while (USBD_OK != CDC_Transmit_FS((uint8_t*)"tethered\r\n", 10) )
|
while (USBD_OK != CDC_Transmit_FS((uint8_t*)"tethered\r\n", 10) )
|
||||||
;
|
;
|
||||||
@ -244,7 +223,7 @@ void wait_for_usb_tether(void)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbhid_init(void)
|
void usbhid_init()
|
||||||
{
|
{
|
||||||
if (!isLowFreq)
|
if (!isLowFreq)
|
||||||
{
|
{
|
||||||
@ -294,12 +273,12 @@ void ctaphid_write_block(uint8_t * data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void usbhid_close(void)
|
void usbhid_close()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_loop_delay(void)
|
void main_loop_delay()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -309,14 +288,13 @@ static uint32_t winkt1 = 0;
|
|||||||
#ifdef LED_WINK_VALUE
|
#ifdef LED_WINK_VALUE
|
||||||
static uint32_t winkt2 = 0;
|
static uint32_t winkt2 = 0;
|
||||||
#endif
|
#endif
|
||||||
|
void device_wink()
|
||||||
void device_wink(void)
|
|
||||||
{
|
{
|
||||||
wink_time = 10;
|
wink_time = 10;
|
||||||
winkt1 = 0;
|
winkt1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void heartbeat(void)
|
void heartbeat()
|
||||||
{
|
{
|
||||||
static int state = 0;
|
static int state = 0;
|
||||||
static uint32_t val = (LED_MAX_SCALER - LED_MIN_SCALER)/2;
|
static uint32_t val = (LED_MAX_SCALER - LED_MIN_SCALER)/2;
|
||||||
@ -385,7 +363,7 @@ void authenticator_read_backup_state(AuthenticatorState * a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return 1 yes backup is init'd, else 0
|
// Return 1 yes backup is init'd, else 0
|
||||||
int authenticator_is_backup_initialized(void)
|
int authenticator_is_backup_initialized()
|
||||||
{
|
{
|
||||||
uint8_t header[16];
|
uint8_t header[16];
|
||||||
uint32_t * ptr = (uint32_t *)flash_addr(STATE2_PAGE);
|
uint32_t * ptr = (uint32_t *)flash_addr(STATE2_PAGE);
|
||||||
@ -410,8 +388,7 @@ void authenticator_write_state(AuthenticatorState * a, int backup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(IS_BOOTLOADER)
|
uint32_t ctap_atomic_count(int sel)
|
||||||
uint32_t ctap_atomic_count(uint32_t amount)
|
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
||||||
@ -426,12 +403,10 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
|||||||
|
|
||||||
uint32_t lastc = 0;
|
uint32_t lastc = 0;
|
||||||
|
|
||||||
if (amount == 0)
|
if (sel != 0)
|
||||||
{
|
{
|
||||||
// Use a random count [1-16].
|
printf2(TAG_ERR,"counter2 not imple\n");
|
||||||
uint8_t rng[1];
|
exit(1);
|
||||||
ctap_generate_rng(rng, 1);
|
|
||||||
amount = (rng[0] & 0x0f) + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (offset = 0; offset < PAGE_SIZE/4; offset += 2) // wear-level the flash
|
for (offset = 0; offset < PAGE_SIZE/4; offset += 2) // wear-level the flash
|
||||||
@ -464,7 +439,7 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
|||||||
return lastc;
|
return lastc;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastc += amount;
|
lastc++;
|
||||||
|
|
||||||
if (lastc/256 > erases)
|
if (lastc/256 > erases)
|
||||||
{
|
{
|
||||||
@ -502,10 +477,10 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
|||||||
|
|
||||||
return lastc;
|
return lastc;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void device_manage(void)
|
|
||||||
|
void device_manage()
|
||||||
{
|
{
|
||||||
#if NON_BLOCK_PRINTING
|
#if NON_BLOCK_PRINTING
|
||||||
int i = 10;
|
int i = 10;
|
||||||
@ -531,7 +506,7 @@ void device_manage(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_packets(void)
|
static int handle_packets()
|
||||||
{
|
{
|
||||||
static uint8_t hidmsg[HID_PACKET_SIZE];
|
static uint8_t hidmsg[HID_PACKET_SIZE];
|
||||||
memset(hidmsg,0, sizeof(hidmsg));
|
memset(hidmsg,0, sizeof(hidmsg));
|
||||||
@ -567,7 +542,6 @@ static int wait_for_button_activate(uint32_t wait)
|
|||||||
} while (!IS_BUTTON_PRESSED());
|
} while (!IS_BUTTON_PRESSED());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_for_button_release(uint32_t wait)
|
static int wait_for_button_release(uint32_t wait)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -589,17 +563,11 @@ static int wait_for_button_release(uint32_t wait)
|
|||||||
int ctap_user_presence_test(uint32_t up_delay)
|
int ctap_user_presence_test(uint32_t up_delay)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
|
||||||
if (device_is_nfc() == NFC_IS_ACTIVE)
|
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_up_disabled)
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
||||||
int i=500;
|
int i=500;
|
||||||
while(i--)
|
while(i--)
|
||||||
@ -661,7 +629,7 @@ int ctap_user_verification(uint8_t arg)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctap_reset_rk(void)
|
void ctap_reset_rk()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
printf1(TAG_GREEN, "resetting RK \r\n");
|
printf1(TAG_GREEN, "resetting RK \r\n");
|
||||||
@ -671,7 +639,7 @@ void ctap_reset_rk(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ctap_rk_size(void)
|
uint32_t ctap_rk_size()
|
||||||
{
|
{
|
||||||
return RK_NUM_PAGES * (PAGE_SIZE / sizeof(CTAP_residentKey));
|
return RK_NUM_PAGES * (PAGE_SIZE / sizeof(CTAP_residentKey));
|
||||||
}
|
}
|
||||||
@ -733,7 +701,7 @@ void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void boot_st_bootloader(void)
|
void boot_st_bootloader()
|
||||||
{
|
{
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
|
|
||||||
@ -745,7 +713,7 @@ void boot_st_bootloader(void)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void boot_solo_bootloader(void)
|
void boot_solo_bootloader()
|
||||||
{
|
{
|
||||||
LL_IWDG_Enable(IWDG);
|
LL_IWDG_Enable(IWDG);
|
||||||
|
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
static void flash_lock(void)
|
static void flash_lock()
|
||||||
{
|
{
|
||||||
FLASH->CR |= (1U<<31);
|
FLASH->CR |= (1U<<31);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flash_unlock(void)
|
static void flash_unlock()
|
||||||
{
|
{
|
||||||
if (FLASH->CR & FLASH_CR_LOCK)
|
if (FLASH->CR & FLASH_CR_LOCK)
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "usbd_desc.h"
|
#include "usbd_desc.h"
|
||||||
#include "usbd_hid.h"
|
#include "usbd_hid.h"
|
||||||
#include "usbd_cdc.h"
|
#include "usbd_cdc.h"
|
||||||
#include "usbd_ccid.h"
|
|
||||||
#include "usbd_composite.h"
|
#include "usbd_composite.h"
|
||||||
#include "usbd_cdc_if.h"
|
#include "usbd_cdc_if.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -699,33 +698,33 @@ void SystemClock_Config_LF20(void)
|
|||||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_usb(void)
|
void init_usb()
|
||||||
{
|
{
|
||||||
// enable USB power
|
// enable USB power
|
||||||
SET_BIT(PWR->CR2, PWR_CR2_USV);
|
SET_BIT(PWR->CR2, PWR_CR2_USV);
|
||||||
|
|
||||||
// Enable USB Clock
|
// Enable USB Clock
|
||||||
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN);
|
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN);
|
||||||
#ifndef IS_BOOTLOADER
|
|
||||||
USBD_Composite_Set_Classes(&USBD_HID, &USBD_CCID, &USBD_CDC);
|
#if DEBUG_LEVEL > 0
|
||||||
|
USBD_Composite_Set_Classes(&USBD_HID, &USBD_CDC);
|
||||||
in_endpoint_to_class[HID_EPIN_ADDR & 0x7F] = 0;
|
in_endpoint_to_class[HID_EPIN_ADDR & 0x7F] = 0;
|
||||||
out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0;
|
out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0;
|
||||||
|
|
||||||
in_endpoint_to_class[CCID_IN_EP & 0x7F] = 1;
|
in_endpoint_to_class[CDC_IN_EP & 0x7F] = 1;
|
||||||
out_endpoint_to_class[CCID_OUT_EP & 0x7F] = 1;
|
out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 1;
|
||||||
|
|
||||||
in_endpoint_to_class[CDC_IN_EP & 0x7F] = 2;
|
|
||||||
out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 2;
|
|
||||||
|
|
||||||
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
|
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
|
||||||
USBD_RegisterClass(&Solo_USBD_Device, &USBD_Composite);
|
USBD_RegisterClass(&Solo_USBD_Device, &USBD_Composite);
|
||||||
#if DEBUG_LEVEL > 0
|
// USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
|
||||||
|
//
|
||||||
|
// USBD_RegisterClass(&Solo_USBD_Device, &USBD_CDC);
|
||||||
USBD_CDC_RegisterInterface(&Solo_USBD_Device, &USBD_Interface_fops_FS);
|
USBD_CDC_RegisterInterface(&Solo_USBD_Device, &USBD_Interface_fops_FS);
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
|
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
|
||||||
USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
|
USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
USBD_Start(&Solo_USBD_Device);
|
USBD_Start(&Solo_USBD_Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#ifndef _INIT_H_
|
#ifndef _INIT_H_
|
||||||
#define _INIT_H_
|
#define _INIT_H_
|
||||||
|
|
||||||
void init_usb(void);
|
void init_usb();
|
||||||
void init_gpio(void);
|
void init_gpio(void);
|
||||||
void init_debug_uart(void);
|
void init_debug_uart(void);
|
||||||
void init_pwm(void);
|
void init_pwm(void);
|
||||||
|
@ -57,11 +57,10 @@ void TIM6_DAC_IRQHandler()
|
|||||||
__90_ms += 1;
|
__90_ms += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t millis(void)
|
uint32_t millis()
|
||||||
{
|
{
|
||||||
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Error_Handler(char *file, int line)
|
void _Error_Handler(char *file, int line)
|
||||||
{
|
{
|
||||||
while(1)
|
while(1)
|
||||||
|
@ -37,33 +37,10 @@
|
|||||||
|
|
||||||
// End of application code. Leave some extra room for future data storage.
|
// End of application code. Leave some extra room for future data storage.
|
||||||
// NOT included in application
|
// NOT included in application
|
||||||
#define APPLICATION_END_PAGE ((PAGES - 20))
|
#define APPLICATION_END_PAGE ((PAGES - 19))
|
||||||
#define APPLICATION_END_ADDR ((0x08000000 + ((APPLICATION_END_PAGE)*PAGE_SIZE))-8)
|
#define APPLICATION_END_ADDR ((0x08000000 + ((APPLICATION_END_PAGE)*PAGE_SIZE))-8)
|
||||||
|
|
||||||
// Bootloader state.
|
// Bootloader state.
|
||||||
#define AUTH_WORD_ADDR (APPLICATION_END_ADDR)
|
#define AUTH_WORD_ADDR (APPLICATION_END_ADDR)
|
||||||
|
|
||||||
#define LAST_ADDR (APPLICATION_END_ADDR-2048 + 8)
|
|
||||||
#define BOOT_VERSION_PAGE (APPLICATION_END_PAGE)
|
|
||||||
#define BOOT_VERSION_ADDR (0x08000000 + BOOT_VERSION_PAGE*FLASH_PAGE_SIZE + 8)
|
|
||||||
#define LAST_PAGE (APPLICATION_END_PAGE-1)
|
|
||||||
|
|
||||||
|
|
||||||
struct flash_memory_st{
|
|
||||||
uint8_t bootloader[APPLICATION_START_PAGE*2*1024];
|
|
||||||
uint8_t application[(APPLICATION_END_PAGE-APPLICATION_START_PAGE)*2*1024-8];
|
|
||||||
uint8_t auth_word[4];
|
|
||||||
uint8_t bootloader_disabled[4];
|
|
||||||
// place for more user data
|
|
||||||
uint8_t _reserved_application_end_mark[8];
|
|
||||||
uint8_t bootloader_data[2*1024-8];
|
|
||||||
uint8_t user_data[38*1024];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
typedef struct flash_memory_st flash_memory_st;
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
static_assert(sizeof(flash_memory_st) == 256*1024, "Data structure doesn't match flash size");
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,23 +14,6 @@
|
|||||||
|
|
||||||
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
|
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
|
||||||
|
|
||||||
// chain buffer for 61XX responses
|
|
||||||
static uint8_t chain_buffer[2048] = {0};
|
|
||||||
static size_t chain_buffer_len = 0;
|
|
||||||
static bool chain_buffer_tx = false;
|
|
||||||
static uint8_t current_cid = 0;
|
|
||||||
|
|
||||||
// forward declarations
|
|
||||||
void rblock_acknowledge(uint8_t req0, bool ack);
|
|
||||||
|
|
||||||
uint8_t p14443_have_cid(uint8_t pcb) {
|
|
||||||
// CID
|
|
||||||
if (pcb & 0x08)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t p14443_block_offset(uint8_t pcb) {
|
uint8_t p14443_block_offset(uint8_t pcb) {
|
||||||
uint8_t offset = 1;
|
uint8_t offset = 1;
|
||||||
// NAD following
|
// NAD following
|
||||||
@ -203,7 +186,7 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
||||||
res[1] = current_cid;
|
res[1] = 0;
|
||||||
res[2] = 0;
|
res[2] = 0;
|
||||||
|
|
||||||
uint8_t block_offset = p14443_block_offset(req0);
|
uint8_t block_offset = p14443_block_offset(req0);
|
||||||
@ -230,7 +213,7 @@ bool nfc_write_response(uint8_t req0, uint16_t resp)
|
|||||||
return nfc_write_response_ex(req0, NULL, 0, resp);
|
return nfc_write_response_ex(req0, NULL, 0, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
|
void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
|
||||||
{
|
{
|
||||||
uint8_t res[32 + 2];
|
uint8_t res[32 + 2];
|
||||||
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
||||||
@ -240,8 +223,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
|
|||||||
{
|
{
|
||||||
uint8_t res[32] = {0};
|
uint8_t res[32] = {0};
|
||||||
res[0] = iBlock;
|
res[0] = iBlock;
|
||||||
res[1] = current_cid;
|
|
||||||
res[2] = 0;
|
|
||||||
if (len && data)
|
if (len && data)
|
||||||
memcpy(&res[block_offset], data, len);
|
memcpy(&res[block_offset], data, len);
|
||||||
nfc_write_frame(res, len + block_offset);
|
nfc_write_frame(res, len + block_offset);
|
||||||
@ -251,7 +232,7 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
|
|||||||
// transmit I block
|
// transmit I block
|
||||||
int vlen = MIN(32 - block_offset, len - sendlen);
|
int vlen = MIN(32 - block_offset, len - sendlen);
|
||||||
res[0] = iBlock;
|
res[0] = iBlock;
|
||||||
res[1] = current_cid;
|
res[1] = 0;
|
||||||
res[2] = 0;
|
res[2] = 0;
|
||||||
memcpy(&res[block_offset], &data[sendlen], vlen);
|
memcpy(&res[block_offset], &data[sendlen], vlen);
|
||||||
|
|
||||||
@ -282,20 +263,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
|
|||||||
printf1(TAG_NFC, "R block RX timeout %d/%d.\r\n",sendlen,len);
|
printf1(TAG_NFC, "R block RX timeout %d/%d.\r\n",sendlen,len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_RBLOCK(recbuf[0]))
|
|
||||||
{
|
|
||||||
printf1(TAG_NFC, "R block RX error. Not a R block(0x%02x) %d/%d.\r\n", recbuf[0], sendlen, len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NAK check
|
|
||||||
if (recbuf[0] & NFC_CMD_RBLOCK_ACK)
|
|
||||||
{
|
|
||||||
rblock_acknowledge(recbuf[0], true);
|
|
||||||
printf1(TAG_NFC, "R block RX error. NAK received. %d/%d.\r\n", recbuf[0], sendlen, len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t rblock_offset = p14443_block_offset(recbuf[0]);
|
uint8_t rblock_offset = p14443_block_offset(recbuf[0]);
|
||||||
if (reclen != rblock_offset)
|
if (reclen != rblock_offset)
|
||||||
@ -317,38 +284,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void append_get_response(uint8_t *data, size_t rest_len)
|
|
||||||
{
|
|
||||||
data[0] = 0x61;
|
|
||||||
data[1] = 0x00;
|
|
||||||
if (rest_len <= 0xff)
|
|
||||||
data[1] = rest_len & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len, bool extapdu)
|
|
||||||
{
|
|
||||||
chain_buffer_len = 0;
|
|
||||||
chain_buffer_tx = true;
|
|
||||||
|
|
||||||
// if we dont need to break data to parts that need to exchange via GET RESPONSE command (ISO 7816-4 7.1.3)
|
|
||||||
if (len <= 255 || extapdu)
|
|
||||||
{
|
|
||||||
nfc_write_response_chaining_plain(req0, data, len);
|
|
||||||
} else {
|
|
||||||
size_t pcklen = MIN(253, len);
|
|
||||||
chain_buffer_len = len - pcklen;
|
|
||||||
printf1(TAG_NFC, "61XX chaining %d/%d.\r\n", pcklen, chain_buffer_len);
|
|
||||||
|
|
||||||
memmove(chain_buffer, data, pcklen);
|
|
||||||
append_get_response(&chain_buffer[pcklen], chain_buffer_len);
|
|
||||||
|
|
||||||
nfc_write_response_chaining_plain(req0, chain_buffer, pcklen + 2); // 2 for 61XX
|
|
||||||
|
|
||||||
// put the rest data into chain buffer
|
|
||||||
memmove(chain_buffer, &data[pcklen], chain_buffer_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WTX on/off:
|
// WTX on/off:
|
||||||
// sends/receives WTX frame to reader every `WTX_time` time in ms
|
// sends/receives WTX frame to reader every `WTX_time` time in ms
|
||||||
// works via timer interrupts
|
// works via timer interrupts
|
||||||
@ -359,7 +294,7 @@ static uint32_t WTX_timer;
|
|||||||
|
|
||||||
bool WTX_process(int read_timeout);
|
bool WTX_process(int read_timeout);
|
||||||
|
|
||||||
void WTX_clear(void)
|
void WTX_clear()
|
||||||
{
|
{
|
||||||
WTX_sent = false;
|
WTX_sent = false;
|
||||||
WTX_fail = false;
|
WTX_fail = false;
|
||||||
@ -374,7 +309,7 @@ bool WTX_on(int WTX_time)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WTX_off(void)
|
bool WTX_off()
|
||||||
{
|
{
|
||||||
WTX_timer = 0;
|
WTX_timer = 0;
|
||||||
|
|
||||||
@ -398,7 +333,7 @@ bool WTX_off(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WTX_timer_exec(void)
|
void WTX_timer_exec()
|
||||||
{
|
{
|
||||||
// condition: (timer on) or (not expired[300ms])
|
// condition: (timer on) or (not expired[300ms])
|
||||||
if ((WTX_timer == 0) || WTX_timer + 300 > millis())
|
if ((WTX_timer == 0) || WTX_timer + 300 > millis())
|
||||||
@ -494,9 +429,7 @@ void rblock_acknowledge(uint8_t req0, bool ack)
|
|||||||
NFC_STATE.block_num = !NFC_STATE.block_num;
|
NFC_STATE.block_num = !NFC_STATE.block_num;
|
||||||
|
|
||||||
buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f);
|
buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f);
|
||||||
buf[1] = current_cid;
|
if (ack)
|
||||||
// iso14443-4:2001 page 16. ACK, if bit is set to 0, NAK, if bit is set to 1
|
|
||||||
if (!ack)
|
|
||||||
buf[0] |= NFC_CMD_RBLOCK_ACK;
|
buf[0] |= NFC_CMD_RBLOCK_ACK;
|
||||||
|
|
||||||
nfc_write_frame(buf, block_offset);
|
nfc_write_frame(buf, block_offset);
|
||||||
@ -550,70 +483,34 @@ int select_applet(uint8_t * aid, int len)
|
|||||||
return APP_NOTHING;
|
return APP_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
void nfc_process_iblock(uint8_t * buf, int len)
|
||||||
{
|
{
|
||||||
int selected;
|
int selected;
|
||||||
CTAP_RESPONSE ctap_resp;
|
CTAP_RESPONSE ctap_resp;
|
||||||
int status;
|
int status;
|
||||||
uint16_t reslen;
|
uint16_t reslen;
|
||||||
|
|
||||||
|
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||||
|
|
||||||
|
APDU_STRUCT apdu;
|
||||||
|
if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) {
|
||||||
|
printf1(TAG_NFC,"apdu decode error\r\n");
|
||||||
|
nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
|
||||||
|
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
|
||||||
|
|
||||||
// check CLA
|
// check CLA
|
||||||
if (apdu->cla != 0x00 && apdu->cla != 0x80) {
|
if (apdu.cla != 0x00 && apdu.cla != 0x80) {
|
||||||
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu->cla);
|
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla);
|
||||||
nfc_write_response(buf0, SW_CLA_INVALID);
|
nfc_write_response(buf[0], SW_CLA_INVALID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this needs to be organized better
|
// TODO this needs to be organized better
|
||||||
switch(apdu->ins)
|
switch(apdu.ins)
|
||||||
{
|
{
|
||||||
// ISO 7816. 7.1 GET RESPONSE command
|
|
||||||
case APDU_GET_RESPONSE:
|
|
||||||
if (apdu->p1 != 0x00 || apdu->p2 != 0x00)
|
|
||||||
{
|
|
||||||
nfc_write_response(buf0, SW_INCORRECT_P1P2);
|
|
||||||
printf1(TAG_NFC, "P1 or P2 error\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// too many bytes needs. 0x00 and 0x100 - any length
|
|
||||||
if (apdu->le != 0 && apdu->le != 0x100 && apdu->le > chain_buffer_len)
|
|
||||||
{
|
|
||||||
uint16_t wlresp = SW_WRONG_LENGTH; // here can be 6700, 6C00, 6FXX. but the most standard way - 67XX or 6700
|
|
||||||
if (chain_buffer_len <= 0xff)
|
|
||||||
wlresp += chain_buffer_len & 0xff;
|
|
||||||
nfc_write_response(buf0, wlresp);
|
|
||||||
printf1(TAG_NFC, "buffer length less than requesteds\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create temporary packet
|
|
||||||
uint8_t pck[255] = {0};
|
|
||||||
size_t pcklen = 253;
|
|
||||||
if (apdu->le)
|
|
||||||
pcklen = apdu->le;
|
|
||||||
if (pcklen > chain_buffer_len)
|
|
||||||
pcklen = chain_buffer_len;
|
|
||||||
|
|
||||||
printf1(TAG_NFC, "GET RESPONSE. pck len: %d buffer len: %d\r\n", pcklen, chain_buffer_len);
|
|
||||||
|
|
||||||
// create packet and add 61XX there if we have another portion(s) of data
|
|
||||||
memmove(pck, chain_buffer, pcklen);
|
|
||||||
size_t dlen = 0;
|
|
||||||
if (chain_buffer_len - pcklen)
|
|
||||||
{
|
|
||||||
append_get_response(&pck[pcklen], chain_buffer_len - pcklen);
|
|
||||||
dlen = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send
|
|
||||||
nfc_write_response_chaining_plain(buf0, pck, pcklen + dlen); // dlen for 61XX
|
|
||||||
|
|
||||||
// shift the buffer
|
|
||||||
chain_buffer_len -= pcklen;
|
|
||||||
memmove(chain_buffer, &chain_buffer[pcklen], chain_buffer_len);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case APDU_INS_SELECT:
|
case APDU_INS_SELECT:
|
||||||
// if (apdu->p1 == 0 && apdu->p2 == 0x0c)
|
// if (apdu->p1 == 0 && apdu->p2 == 0x0c)
|
||||||
// {
|
// {
|
||||||
@ -629,49 +526,49 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
|||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
{
|
{
|
||||||
selected = select_applet(apdu->data, apdu->lc);
|
selected = select_applet(apdu.data, apdu.lc);
|
||||||
if (selected == APP_FIDO)
|
if (selected == APP_FIDO)
|
||||||
{
|
{
|
||||||
nfc_write_response_ex(buf0, (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
|
||||||
printf1(TAG_NFC, "FIDO applet selected.\r\n");
|
printf1(TAG_NFC, "FIDO applet selected.\r\n");
|
||||||
}
|
}
|
||||||
else if (selected != APP_NOTHING)
|
else if (selected != APP_NOTHING)
|
||||||
{
|
{
|
||||||
nfc_write_response(buf0, SW_SUCCESS);
|
nfc_write_response(buf[0], SW_SUCCESS);
|
||||||
printf1(TAG_NFC, "SELECTED %d\r\n", selected);
|
printf1(TAG_NFC, "SELECTED %d\r\n", selected);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nfc_write_response(buf0, SW_FILE_NOT_FOUND);
|
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
||||||
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu->data, apdu->lc);
|
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APDU_FIDO_U2F_VERSION:
|
case APDU_FIDO_U2F_VERSION:
|
||||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||||
nfc_write_response(buf0, SW_INS_INVALID);
|
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
||||||
|
|
||||||
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp);
|
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||||
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APDU_FIDO_U2F_REGISTER:
|
case APDU_FIDO_U2F_REGISTER:
|
||||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||||
nfc_write_response(buf0, SW_INS_INVALID);
|
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_NFC, "U2F Register command.\r\n");
|
printf1(TAG_NFC, "U2F Register command.\r\n");
|
||||||
|
|
||||||
if (apdu->lc != 64)
|
if (apdu.lc != 64)
|
||||||
{
|
{
|
||||||
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu->lc);
|
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc);
|
||||||
nfc_write_response(buf0, SW_WRONG_LENGTH);
|
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,59 +579,59 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
|||||||
// SystemClock_Config_LF32();
|
// SystemClock_Config_LF32();
|
||||||
// delay(300);
|
// delay(300);
|
||||||
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
|
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
|
||||||
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp);
|
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||||
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
||||||
// if (!WTX_off())
|
// if (!WTX_off())
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||||
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
|
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
|
||||||
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||||
|
|
||||||
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
|
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APDU_FIDO_U2F_AUTHENTICATE:
|
case APDU_FIDO_U2F_AUTHENTICATE:
|
||||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||||
nfc_write_response(buf0, SW_INS_INVALID);
|
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_NFC, "U2F Authenticate command.\r\n");
|
printf1(TAG_NFC, "U2F Authenticate command.\r\n");
|
||||||
|
|
||||||
if (apdu->lc != 64 + 1 + apdu->data[64])
|
if (apdu.lc != 64 + 1 + apdu.data[64])
|
||||||
{
|
{
|
||||||
delay(5);
|
delay(5);
|
||||||
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu->lc, apdu->data[64]);
|
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu.lc, apdu.data[64]);
|
||||||
nfc_write_response(buf0, SW_WRONG_LENGTH);
|
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp();
|
timestamp();
|
||||||
// WTX_on(WTX_TIME_DEFAULT);
|
// WTX_on(WTX_TIME_DEFAULT);
|
||||||
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp);
|
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||||
// if (!WTX_off())
|
// if (!WTX_off())
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||||
printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp());
|
printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp());
|
||||||
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||||
printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp);
|
printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APDU_FIDO_NFCCTAP_MSG:
|
case APDU_FIDO_NFCCTAP_MSG:
|
||||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||||
nfc_write_response(buf0, SW_INS_INVALID);
|
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
||||||
|
|
||||||
// WTX_on(WTX_TIME_DEFAULT);
|
// WTX_on(WTX_TIME_DEFAULT);
|
||||||
device_disable_up(true);
|
request_from_nfc(true);
|
||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
status = ctap_request(apdu->data, apdu->lc, &ctap_resp);
|
status = ctap_request(apdu.data, apdu.lc, &ctap_resp);
|
||||||
device_disable_up(false);
|
request_from_nfc(false);
|
||||||
// if (!WTX_off())
|
// if (!WTX_off())
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
@ -752,102 +649,42 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
|||||||
ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff;
|
ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff;
|
||||||
|
|
||||||
printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp());
|
printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp());
|
||||||
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||||
printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp());
|
printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APDU_INS_READ_BINARY:
|
case APDU_INS_READ_BINARY:
|
||||||
// response length
|
// response length
|
||||||
reslen = apdu->le & 0xffff;
|
reslen = apdu.le & 0xffff;
|
||||||
switch(NFC_STATE.selected_applet)
|
switch(NFC_STATE.selected_applet)
|
||||||
{
|
{
|
||||||
case APP_CAPABILITY_CONTAINER:
|
case APP_CAPABILITY_CONTAINER:
|
||||||
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
|
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
|
||||||
if (reslen == 0 || reslen > sizeof(NFC_CC))
|
if (reslen == 0 || reslen > sizeof(NFC_CC))
|
||||||
reslen = sizeof(NFC_CC);
|
reslen = sizeof(NFC_CC);
|
||||||
nfc_write_response_ex(buf0, (uint8_t *)&NFC_CC, reslen, SW_SUCCESS);
|
nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS);
|
||||||
ams_wait_for_tx(10);
|
ams_wait_for_tx(10);
|
||||||
break;
|
break;
|
||||||
case APP_NDEF_TAG:
|
case APP_NDEF_TAG:
|
||||||
printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
|
printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
|
||||||
if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1)
|
if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1)
|
||||||
reslen = sizeof(NDEF_SAMPLE) - 1;
|
reslen = sizeof(NDEF_SAMPLE) - 1;
|
||||||
nfc_write_response_ex(buf0, NDEF_SAMPLE, reslen, SW_SUCCESS);
|
nfc_write_response_ex(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS);
|
||||||
ams_wait_for_tx(10);
|
ams_wait_for_tx(10);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nfc_write_response(buf0, SW_FILE_NOT_FOUND);
|
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
||||||
printf1(TAG_ERR, "No binary applet selected!\r\n");
|
printf1(TAG_ERR, "No binary applet selected!\r\n");
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APDU_SOLO_RESET:
|
|
||||||
if (apdu->lc == 4 && !memcmp(apdu->data, "\x12\x56\xab\xf0", 4)) {
|
|
||||||
printf1(TAG_NFC, "Reset...\r\n");
|
|
||||||
nfc_write_response(buf0, SW_SUCCESS);
|
|
||||||
delay(20);
|
|
||||||
device_reboot();
|
|
||||||
while(1);
|
|
||||||
} else {
|
|
||||||
printf1(TAG_NFC, "Reset FAIL\r\n");
|
|
||||||
nfc_write_response(buf0, SW_INS_INVALID);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins);
|
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins);
|
||||||
nfc_write_response(buf0, SW_INS_INVALID);
|
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_process_iblock(uint8_t * buf, int len)
|
|
||||||
{
|
|
||||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
|
||||||
|
|
||||||
// clear tx chain buffer if we have some other command than GET RESPONSE
|
|
||||||
if (chain_buffer_tx && buf[block_offset + 1] != APDU_GET_RESPONSE) {
|
|
||||||
chain_buffer_len = 0;
|
|
||||||
chain_buffer_tx = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
APDU_STRUCT apdu;
|
|
||||||
uint16_t ret = apdu_decode(buf + block_offset, len - block_offset, &apdu);
|
|
||||||
if (ret != 0) {
|
|
||||||
printf1(TAG_NFC,"apdu decode error\r\n");
|
|
||||||
nfc_write_response(buf[0], ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
|
|
||||||
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
|
|
||||||
|
|
||||||
// APDU level chaining. ISO7816-4, 5.1.1. class byte
|
|
||||||
if (!chain_buffer_tx && buf[block_offset] & 0x10) {
|
|
||||||
|
|
||||||
if (chain_buffer_len + len > sizeof(chain_buffer)) {
|
|
||||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memmove(&chain_buffer[chain_buffer_len], apdu.data, apdu.lc);
|
|
||||||
chain_buffer_len += apdu.lc;
|
|
||||||
nfc_write_response(buf[0], SW_SUCCESS);
|
|
||||||
printf1(TAG_NFC, "APDU chaining ok. %d/%d\r\n", apdu.lc, chain_buffer_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have ISO 7816 APDU chain - move there all the data
|
|
||||||
if (!chain_buffer_tx && chain_buffer_len > 0) {
|
|
||||||
memmove(&apdu.data[chain_buffer_len], apdu.data, apdu.lc);
|
|
||||||
memmove(apdu.data, chain_buffer, chain_buffer_len);
|
|
||||||
apdu.lc += chain_buffer_len; // here apdu struct does not match with memory!
|
|
||||||
printf1(TAG_NFC, "APDU chaining merge. %d/%d\r\n", chain_buffer_len, apdu.lc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
apdu_process(buf[0], &buf[block_offset], &apdu);
|
|
||||||
|
|
||||||
printf1(TAG_NFC,"prev.Iblock: ");
|
printf1(TAG_NFC,"prev.Iblock: ");
|
||||||
dump_hex1(TAG_NFC, buf, len);
|
dump_hex1(TAG_NFC, buf, len);
|
||||||
@ -856,7 +693,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
|
|||||||
static uint8_t ibuf[1024];
|
static uint8_t ibuf[1024];
|
||||||
static int ibuflen = 0;
|
static int ibuflen = 0;
|
||||||
|
|
||||||
void clear_ibuf(void)
|
void clear_ibuf()
|
||||||
{
|
{
|
||||||
ibuflen = 0;
|
ibuflen = 0;
|
||||||
memset(ibuf, 0, sizeof(ibuf));
|
memset(ibuf, 0, sizeof(ibuf));
|
||||||
@ -882,11 +719,9 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
|||||||
else if (IS_IBLOCK(buf[0]))
|
else if (IS_IBLOCK(buf[0]))
|
||||||
{
|
{
|
||||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||||
if (p14443_have_cid(buf[0]))
|
|
||||||
current_cid = buf[1];
|
|
||||||
if (buf[0] & 0x10)
|
if (buf[0] & 0x10)
|
||||||
{
|
{
|
||||||
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d offs=%d\r\n", ibuflen, len, block_offset);
|
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len);
|
||||||
if (ibuflen + len > sizeof(ibuf))
|
if (ibuflen + len > sizeof(ibuf))
|
||||||
{
|
{
|
||||||
printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf));
|
printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf));
|
||||||
@ -919,24 +754,21 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
|||||||
memmove(ibuf, buf, block_offset);
|
memmove(ibuf, buf, block_offset);
|
||||||
ibuflen += block_offset;
|
ibuflen += block_offset;
|
||||||
|
|
||||||
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d offset=%d\r\n", ibuflen, len, block_offset);
|
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len);
|
||||||
|
|
||||||
printf1(TAG_NFC_APDU,"i> ");
|
printf1(TAG_NFC_APDU,"i> ");
|
||||||
dump_hex1(TAG_NFC_APDU, buf, len);
|
dump_hex1(TAG_NFC_APDU, buf, len);
|
||||||
|
|
||||||
nfc_process_iblock(ibuf, ibuflen);
|
nfc_process_iblock(ibuf, ibuflen);
|
||||||
} else {
|
} else {
|
||||||
memcpy(ibuf, buf, len); // because buf only 32b
|
nfc_process_iblock(buf, len);
|
||||||
nfc_process_iblock(ibuf, len);
|
|
||||||
}
|
}
|
||||||
clear_ibuf();
|
clear_ibuf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IS_RBLOCK(buf[0]))
|
else if (IS_RBLOCK(buf[0]))
|
||||||
{
|
{
|
||||||
if (p14443_have_cid(buf[0]))
|
rblock_acknowledge(buf[0], false);
|
||||||
current_cid = buf[1];
|
|
||||||
rblock_acknowledge(buf[0], true);
|
|
||||||
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
|
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
|
||||||
}
|
}
|
||||||
else if (IS_SBLOCK(buf[0]))
|
else if (IS_SBLOCK(buf[0]))
|
||||||
@ -945,10 +777,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
|||||||
if ((buf[0] & NFC_SBLOCK_DESELECT) == 0)
|
if ((buf[0] & NFC_SBLOCK_DESELECT) == 0)
|
||||||
{
|
{
|
||||||
printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n");
|
printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n");
|
||||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
nfc_write_frame(buf, 1);
|
||||||
if (p14443_have_cid(buf[0]))
|
|
||||||
current_cid = buf[1];
|
|
||||||
nfc_write_frame(buf, block_offset);
|
|
||||||
ams_wait_for_tx(2);
|
ams_wait_for_tx(2);
|
||||||
ams_write_command(AMS_CMD_SLEEP);
|
ams_write_command(AMS_CMD_SLEEP);
|
||||||
nfc_state_init();
|
nfc_state_init();
|
||||||
@ -969,7 +798,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfc_loop(void)
|
int nfc_loop()
|
||||||
{
|
{
|
||||||
uint8_t buf[32];
|
uint8_t buf[32];
|
||||||
AMS_DEVICE ams;
|
AMS_DEVICE ams;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
|
|
||||||
// Return number of bytes read if any.
|
// Return number of bytes read if any.
|
||||||
int nfc_loop(void);
|
int nfc_loop();
|
||||||
|
|
||||||
int nfc_init(void);
|
int nfc_init();
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -34,9 +34,9 @@ typedef struct
|
|||||||
#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS)
|
#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS)
|
||||||
#define NFC_CMD_IBLOCK 0x00
|
#define NFC_CMD_IBLOCK 0x00
|
||||||
#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) )
|
#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) )
|
||||||
#define NFC_CMD_RBLOCK 0xa0
|
#define NFC_CMD_RBLOCK 0x80
|
||||||
#define NFC_CMD_RBLOCK_ACK 0x10
|
#define NFC_CMD_RBLOCK_ACK 0x20
|
||||||
#define IS_RBLOCK(x) ( (((x) & 0xe0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
|
#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
|
||||||
#define NFC_CMD_SBLOCK 0xc0
|
#define NFC_CMD_SBLOCK 0xc0
|
||||||
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
|
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
|
||||||
|
|
||||||
@ -61,6 +61,6 @@ typedef enum
|
|||||||
APP_FIDO,
|
APP_FIDO,
|
||||||
} APPLETS;
|
} APPLETS;
|
||||||
|
|
||||||
void WTX_timer_exec(void);
|
void WTX_timer_exec();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#define ELECTRODE_0 TSC_GROUP2_IO1
|
#define ELECTRODE_0 TSC_GROUP2_IO1
|
||||||
#define ELECTRODE_1 TSC_GROUP2_IO2
|
#define ELECTRODE_1 TSC_GROUP2_IO2
|
||||||
|
|
||||||
void tsc_init(void)
|
void tsc_init()
|
||||||
{
|
{
|
||||||
LL_GPIO_InitTypeDef GPIO_InitStruct;
|
LL_GPIO_InitTypeDef GPIO_InitStruct;
|
||||||
// Enable TSC clock
|
// Enable TSC clock
|
||||||
@ -74,7 +74,7 @@ void tsc_set_electrode(uint32_t channel_ids)
|
|||||||
TSC->IOCCR = (channel_ids);
|
TSC->IOCCR = (channel_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsc_start_acq(void)
|
void tsc_start_acq()
|
||||||
{
|
{
|
||||||
TSC->CR &= ~(TSC_CR_START);
|
TSC->CR &= ~(TSC_CR_START);
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ void tsc_start_acq(void)
|
|||||||
TSC->CR |= TSC_CR_START;
|
TSC->CR |= TSC_CR_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsc_wait_on_acq(void)
|
void tsc_wait_on_acq()
|
||||||
{
|
{
|
||||||
while ( ! (TSC->ISR & TSC_FLAG_EOA) )
|
while ( ! (TSC->ISR & TSC_FLAG_EOA) )
|
||||||
;
|
;
|
||||||
@ -117,7 +117,7 @@ uint32_t tsc_read_button(uint32_t index)
|
|||||||
return tsc_read(1) < 45;
|
return tsc_read(1) < 45;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tsc_sensor_exists(void)
|
int tsc_sensor_exists()
|
||||||
{
|
{
|
||||||
static uint8_t does = 0;
|
static uint8_t does = 0;
|
||||||
if (does) return 1;
|
if (does) return 1;
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void tsc_init(void);
|
void tsc_init();
|
||||||
|
|
||||||
int tsc_sensor_exists(void);
|
int tsc_sensor_exists();
|
||||||
|
|
||||||
// Read button0 or button1
|
// Read button0 or button1
|
||||||
// Returns 1 if pressed, 0 if not.
|
// Returns 1 if pressed, 0 if not.
|
||||||
|
Reference in New Issue
Block a user