Compare commits
5 Commits
key-backup
...
nfc_fido2_
Author | SHA1 | Date | |
---|---|---|---|
525ff0c5d6 | |||
79d986197b | |||
9045c0ca3e | |||
508f2e1e1c | |||
6dfdf36654 |
@ -168,25 +168,6 @@
|
||||
"infra",
|
||||
"tool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kimusan",
|
||||
"name": "Kim Schulz",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/1150049?v=4",
|
||||
"profile": "http://www.schulz.dk",
|
||||
"contributions": [
|
||||
"business",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "oplik0",
|
||||
"name": "Jakub",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/25460763?v=4",
|
||||
"profile": "https://github.com/oplik0",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
2
Makefile
2
Makefile
@ -39,7 +39,7 @@ INCLUDES += -I./crypto/cifra/src
|
||||
|
||||
CFLAGS += $(INCLUDES)
|
||||
# for crypto/tiny-AES-c
|
||||
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\" -DSOLO_EXPERIMENTAL=1
|
||||
CFLAGS += -DAES256=1 -DAPP_CONFIG=\"app.h\"
|
||||
|
||||
name = main
|
||||
|
||||
|
@ -134,8 +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="https://github.com/m3hm00d"><img src="https://avatars1.githubusercontent.com/u/42179593?v=4" width="100px;" alt="f.m3hm00d"/><br /><sub><b>f.m3hm00d</b></sub></a><br /><a href="https://github.com/solokeys/solo/commits?author=m3hm00d" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://blogs.gnome.org/hughsie/"><img src="https://avatars0.githubusercontent.com/u/151380?v=4" width="100px;" alt="Richard Hughes"/><br /><sub><b>Richard Hughes</b></sub></a><br /><a href="#ideas-hughsie" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/solokeys/solo/commits?author=hughsie" title="Code">💻</a> <a href="#infra-hughsie" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#tool-hughsie" title="Tools">🔧</a></td>
|
||||
<td align="center"><a href="http://www.schulz.dk"><img src="https://avatars1.githubusercontent.com/u/1150049?v=4" width="100px;" alt="Kim Schulz"/><br /><sub><b>Kim Schulz</b></sub></a><br /><a href="#business-kimusan" title="Business development">💼</a> <a href="#ideas-kimusan" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/oplik0"><img src="https://avatars2.githubusercontent.com/u/25460763?v=4" width="100px;" alt="Jakub"/><br /><sub><b>Jakub</b></sub></a><br /><a href="https://github.com/solokeys/solo/issues?q=author%3Aoplik0" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -169,7 +167,7 @@ You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solok
|
||||
<br/>
|
||||
|
||||
[](https://github.com/solokeys/solo/blob/master/LICENSE)
|
||||
[](#contributors)
|
||||
[](#contributors)
|
||||
[](https://travis-ci.com/solokeys/solo)
|
||||
[](https://discourse.solokeys.com)
|
||||
[](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
|
||||
|
||||
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
|
||||
@ -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.
|
||||
|
||||
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.
|
||||
|
||||
@ -131,11 +131,11 @@ Print your attestation key in a hex string format.
|
||||
python tools/print_x_y.py device_key.pem
|
||||
```
|
||||
|
||||
Merge the `bootloader.hex`, `solo.hex`, and attestion key into one firmware file.
|
||||
Merge the bootloader.hex, solo.hex, and attestion key into one firmware file.
|
||||
|
||||
```
|
||||
solo mergehex --attestation-key <attestation-key-hex-string> bootloader.hex solo.hex all.hex
|
||||
```
|
||||
|
||||
Now you have a newly create `all.hex` file with a custom attestation key. You can [program this `all.hex` file
|
||||
with Solo in DFU mode](/solo/programming#procedure).
|
||||
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).
|
@ -85,13 +85,14 @@ brew install arm-none-eabi-gcc
|
||||
### Install flashing software
|
||||
|
||||
ST provides a CLI flashing tool - `STM32_Programmer_CLI`. It can be downloaded directly from the vendor's site:
|
||||
1. Go to [download site URL](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html), go to bottom page and from STM32CubeProg row select Download button.
|
||||
2. Unzip contents of the archive.
|
||||
3. Run \*Linux setup
|
||||
4. In installation directory go to `./bin` - there the `./STM32_Programmer_CLI` is located
|
||||
5. Add symlink to the STM32 CLI binary to `.local/bin`. Make sure the latter it is in `$PATH`.
|
||||
1\. Go to [download site URL](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html),
|
||||
go to bottom page and from STM32CubeProg row select Download button.
|
||||
2\. Unzip contents of the archive.
|
||||
3\. Run \*Linux setup
|
||||
4\. In installation directory go to ./bin - there the ./STM32_Programmer_CLI is located
|
||||
5\. Add symlink to the STM32 CLI binary to .local/bin. Make sure the latter it is in $PATH.
|
||||
|
||||
If you're on 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_profile
|
||||
|
@ -3,16 +3,16 @@
|
||||
## Random number generation
|
||||
|
||||
Solo contains a True Random Number Generator (TRNG). A TRNG is a hardware based mechanism
|
||||
that leverages natural phenomenon to generate random numbers, which 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.
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
|
@ -1,33 +1,30 @@
|
||||
# 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:
|
||||
|
||||
- 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:
|
||||
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):
|
||||
|
||||
```
|
||||
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
|
||||
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.
|
||||
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
|
||||
```
|
||||
We are working on getting user access to Solo keys enabled automatically in common Linux distributions: <https://github.com/solokeys/solo/issues/144>.
|
||||
|
||||
|
||||
|
||||
# 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"
|
||||
|
||||
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;
|
||||
|
||||
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any
|
||||
apdu->cla = hapdu->cla;
|
||||
apdu->ins = hapdu->ins;
|
||||
apdu->p1 = hapdu->p1;
|
||||
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)
|
||||
{
|
||||
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
|
||||
|
||||
if (len - 7 < extlen)
|
||||
{
|
||||
return SW_WRONG_LENGTH;
|
||||
}
|
||||
|
||||
// case 2E (Le) - extended
|
||||
if (len == 7)
|
||||
@ -108,18 +103,9 @@ uint16_t apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
|
||||
apdu->le = 0x10000;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((len > 5) && (len - 5 < hapdu->lc[0]))
|
||||
{
|
||||
return SW_WRONG_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
if (!apdu->case_type)
|
||||
{
|
||||
return SW_COND_USE_NOT_SATISFIED;
|
||||
}
|
||||
return 1;
|
||||
|
||||
if (apdu->lc)
|
||||
{
|
||||
|
@ -36,26 +36,20 @@ typedef struct
|
||||
uint8_t case_type;
|
||||
} __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_AUTHENTICATE 0x02
|
||||
#define APDU_FIDO_U2F_VERSION 0x03
|
||||
#define APDU_FIDO_NFCCTAP_MSG 0x10
|
||||
#define APDU_FIDO_U2F_VENDOR_FIRST 0xc0 // First vendor defined command
|
||||
#define APDU_FIDO_U2F_VENDOR_LAST 0xff // Last vendor defined command
|
||||
#define APDU_SOLO_RESET 0xee
|
||||
|
||||
#define APDU_INS_SELECT 0xA4
|
||||
#define APDU_INS_READ_BINARY 0xB0
|
||||
#define APDU_GET_RESPONSE 0xC0
|
||||
|
||||
#define SW_SUCCESS 0x9000
|
||||
#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE.
|
||||
#define SW_WRONG_LENGTH 0x6700
|
||||
#define SW_COND_USE_NOT_SATISFIED 0x6985
|
||||
#define SW_FILE_NOT_FOUND 0x6a82
|
||||
#define SW_INCORRECT_P1P2 0x6a86
|
||||
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
|
||||
#define SW_CLA_INVALID 0x6e00
|
||||
#define SW_INTERNAL_EXCEPTION 0x6f00
|
||||
|
169
fido2/ctap.c
169
fido2/ctap.c
@ -25,11 +25,11 @@
|
||||
#include "extensions.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "data_migration.h"
|
||||
|
||||
uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
||||
uint8_t KEY_AGREEMENT_PUB[64];
|
||||
static uint8_t KEY_AGREEMENT_PRIV[32];
|
||||
static uint8_t PIN_CODE_HASH[32];
|
||||
static int8_t PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||
|
||||
AuthenticatorState STATE;
|
||||
@ -437,23 +437,7 @@ static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred)
|
||||
static int ctap2_user_presence_test()
|
||||
{
|
||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||
int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||
if ( ret > 1 )
|
||||
{
|
||||
return CTAP2_ERR_PROCESSING;
|
||||
}
|
||||
else if ( ret > 0 )
|
||||
{
|
||||
return CTAP1_ERR_SUCCESS;
|
||||
}
|
||||
else if (ret < 0)
|
||||
{
|
||||
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CTAP2_ERR_ACTION_TIMEOUT;
|
||||
}
|
||||
return ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
authData->head.flags = (1 << 0); // User presence
|
||||
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
||||
}
|
||||
|
||||
|
||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||
|
||||
authData->head.flags = (but << 0);
|
||||
authData->head.flags |= (ctap_is_pin_set() << 2);
|
||||
|
||||
|
||||
@ -682,16 +666,7 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d
|
||||
switch(desc->type)
|
||||
{
|
||||
case PUB_KEY_CRED_PUB_KEY:
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(rp->id, rp->size);
|
||||
crypto_sha256_final(rpIdHash);
|
||||
|
||||
printf1(TAG_RED,"rpId: %s\r\n", rp->id); dump_hex1(TAG_RED,rp->id, rp->size);
|
||||
if (memcmp(desc->credential.id.rpIdHash, rpIdHash, 32) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
make_auth_tag(rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
||||
make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
|
||||
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
||||
break;
|
||||
case PUB_KEY_CRED_CTAP1:
|
||||
@ -732,7 +707,10 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -1165,7 +1143,10 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
|
||||
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;
|
||||
}
|
||||
if (GA.pinAuthPresent)
|
||||
@ -1248,9 +1229,8 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
device_disable_up(GA.up == 0);
|
||||
|
||||
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, &auth_data_buf_sz, NULL);
|
||||
device_disable_up(false);
|
||||
check_retr(ret);
|
||||
|
||||
((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];
|
||||
int ret;
|
||||
|
||||
// Validate incoming data packet len
|
||||
if (len < 64)
|
||||
{
|
||||
return CTAP1_ERR_OTHER;
|
||||
}
|
||||
|
||||
// Validate device's state
|
||||
if (ctap_is_pin_set()) // Check first, prevent SCA
|
||||
{
|
||||
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_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;
|
||||
}
|
||||
|
||||
// decrypt new PIN with shared secret
|
||||
crypto_aes256_init(shared_secret, NULL);
|
||||
|
||||
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);
|
||||
|
||||
// validate new PIN (length)
|
||||
|
||||
|
||||
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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_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_decrypt(pinHashEnc, 16);
|
||||
|
||||
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)
|
||||
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
||||
{
|
||||
ctap_reset_key_agreement();
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
|
||||
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Pin does not match!\n");
|
||||
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,"platform-pubkey: "); dump_hex1(TAG_ERR, platform_pubkey, 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;
|
||||
case CTAP_RESET:
|
||||
printf1(TAG_CTAP,"CTAP_RESET\n");
|
||||
status = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||
if (status == CTAP1_ERR_SUCCESS)
|
||||
if (ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||
{
|
||||
ctap_reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CTAP2_ERR_OPERATION_DENIED;
|
||||
}
|
||||
break;
|
||||
case GET_NEXT_ASSERTION:
|
||||
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;
|
||||
default:
|
||||
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:
|
||||
@ -1750,29 +1715,8 @@ static void ctap_state_init()
|
||||
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||
STATE.is_pin_set = 0;
|
||||
STATE.rk_stored = 0;
|
||||
STATE.data_version = STATE_VERSION;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ctap_init()
|
||||
@ -1805,12 +1749,14 @@ void ctap_init()
|
||||
}
|
||||
}
|
||||
|
||||
do_migration_if_required(&STATE);
|
||||
|
||||
crypto_load_master_secret(STATE.key_space);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
@ -1842,38 +1788,34 @@ uint8_t ctap_is_pin_set()
|
||||
return STATE.is_pin_set == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new PIN, by updating PIN hash. Save state.
|
||||
* Globals: STATE
|
||||
* @param pin new PIN (raw)
|
||||
* @param len pin array length
|
||||
*/
|
||||
uint8_t ctap_pin_matches(uint8_t * pin, int len)
|
||||
{
|
||||
return memcmp(pin, STATE.pin_code, len) == 0;
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
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_update(pin, len);
|
||||
uint8_t intermediateHash[32];
|
||||
crypto_sha256_final(intermediateHash);
|
||||
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(intermediateHash, 16);
|
||||
memset(intermediateHash, 0, sizeof(intermediateHash));
|
||||
crypto_sha256_update(STATE.PIN_SALT, sizeof(STATE.PIN_SALT));
|
||||
crypto_sha256_final(STATE.PIN_CODE_HASH);
|
||||
crypto_sha256_update(STATE.pin_code, len);
|
||||
crypto_sha256_final(PIN_CODE_HASH);
|
||||
|
||||
STATE.is_pin_set = 1;
|
||||
|
||||
authenticator_write_state(&STATE, 1);
|
||||
authenticator_write_state(&STATE, 0);
|
||||
|
||||
printf1(TAG_CTAP, "New pin set: %s [%d]\n", pin, len);
|
||||
dump_hex1(TAG_ERR, STATE.PIN_CODE_HASH, sizeof(STATE.PIN_CODE_HASH));
|
||||
printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
|
||||
}
|
||||
|
||||
uint8_t ctap_decrement_pin_attempts()
|
||||
@ -1890,7 +1832,9 @@ uint8_t ctap_decrement_pin_attempts()
|
||||
|
||||
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
|
||||
@ -2046,17 +1990,8 @@ void ctap_reset()
|
||||
}
|
||||
|
||||
ctap_reset_state();
|
||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||
ctap_reset_key_agreement();
|
||||
|
||||
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_BOOT_ATTEMPTS 3 // number of attempts per boot
|
||||
|
||||
#define CTAP2_UP_DELAY_MS 29000
|
||||
#define CTAP2_UP_DELAY_MS 5000
|
||||
|
||||
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 KEY_AGREEMENT_PUB[64];
|
||||
|
||||
void lock_device_permanently();
|
||||
|
||||
void ctap_load_external_keys(uint8_t * keybytes);
|
||||
|
||||
#endif
|
||||
|
@ -49,7 +49,6 @@
|
||||
#define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37
|
||||
#define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38
|
||||
#define CTAP2_ERR_REQUEST_TOO_LARGE 0x39
|
||||
#define CTAP2_ERR_ACTION_TIMEOUT 0x3A
|
||||
#define CTAP1_ERR_OTHER 0x7F
|
||||
#define CTAP2_ERR_SPEC_LAST 0xDF
|
||||
#define CTAP2_ERR_EXTENSION_FIRST 0xE0
|
||||
|
@ -715,7 +715,6 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
||||
CborValue it,map;
|
||||
|
||||
memset(MC, 0, sizeof(CTAP_makeCredential));
|
||||
MC->up = 0xff;
|
||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||
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));
|
||||
GA->creds = getAssertionState.creds; // Save stack memory
|
||||
GA->up = 0xff;
|
||||
|
||||
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||
check_ret(ret);
|
||||
|
341
fido2/ctaphid.c
341
fido2/ctaphid.c
@ -16,7 +16,6 @@
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "extensions.h"
|
||||
#include "version.h"
|
||||
|
||||
// move custom SHA512 command out,
|
||||
// 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__);\
|
||||
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 cmd = 0;
|
||||
uint8_t cmd;
|
||||
uint32_t cid;
|
||||
int len = 0;
|
||||
int len;
|
||||
#ifndef DISABLE_CTAPHID_CBOR
|
||||
int status;
|
||||
#endif
|
||||
@ -556,10 +552,6 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
|
||||
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)
|
||||
{
|
||||
@ -595,6 +587,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
case CTAPHID_PING:
|
||||
printf1(TAG_HID,"CTAPHID_PING\n");
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_PING;
|
||||
wb.bcnt = len;
|
||||
timestamp();
|
||||
ctaphid_write(&wb, ctap_buffer, len);
|
||||
@ -607,9 +602,13 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
case CTAPHID_WINK:
|
||||
printf1(TAG_HID,"CTAPHID_WINK\n");
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
|
||||
device_wink();
|
||||
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_WINK;
|
||||
|
||||
ctaphid_write(&wb,NULL,0);
|
||||
|
||||
break;
|
||||
@ -634,6 +633,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
ctap_response_init(&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);
|
||||
|
||||
|
||||
@ -664,6 +666,9 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
ctap_response_init(&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);
|
||||
|
||||
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");
|
||||
is_busy = 0;
|
||||
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:
|
||||
if (ctaphid_custom_command(len, &ctap_resp, &wb) != 0){
|
||||
is_busy = 0;
|
||||
}else{
|
||||
printf2(TAG_ERR, "error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_BOOT;
|
||||
wb.bcnt = (ctap_resp.length + 1);
|
||||
ctaphid_write(&wb, &is_busy, 1);
|
||||
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);
|
||||
buffer_reset();
|
||||
@ -691,112 +891,3 @@ uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
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_ENTERSTBOOT (TYPE_INIT | 0x52)
|
||||
#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
|
||||
#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 device_reboot();
|
||||
|
||||
void authenticator_read_state(AuthenticatorState * );
|
||||
|
||||
@ -53,7 +52,7 @@ void device_set_status(uint32_t status);
|
||||
int device_is_button_pressed();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// Increment atomic counter and return it.
|
||||
// @param amount the amount to increase the counter by.
|
||||
uint32_t ctap_atomic_count(uint32_t amount);
|
||||
// Must support two counters, @sel selects counter0 or counter1.
|
||||
uint32_t ctap_atomic_count(int sel);
|
||||
|
||||
// Verify the user
|
||||
// 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
|
||||
int device_is_nfc();
|
||||
|
||||
void device_disable_up(bool request_active);
|
||||
void request_from_nfc(bool request_active);
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
// printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code);
|
||||
printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code);
|
||||
|
||||
break;
|
||||
case CP_cmdChangePin:
|
||||
|
@ -50,7 +50,6 @@ struct logtag tagtable[] = {
|
||||
{TAG_EXT,"[1;37mEXT[0m"},
|
||||
{TAG_NFC,"[1;38mNFC[0m"},
|
||||
{TAG_NFC_APDU, "NAPDU"},
|
||||
{TAG_CCID, "CCID"},
|
||||
};
|
||||
|
||||
|
||||
|
@ -44,7 +44,6 @@ typedef enum
|
||||
TAG_EXT = (1 << 18),
|
||||
TAG_NFC = (1 << 19),
|
||||
TAG_NFC_APDU = (1 << 20),
|
||||
TAG_CCID = (1 << 21),
|
||||
|
||||
TAG_NO_TAG = (1UL << 30),
|
||||
TAG_FILENO = (1UL << 31)
|
||||
|
@ -46,7 +46,6 @@ int main(int argc, char *argv[])
|
||||
TAG_GREEN|
|
||||
TAG_RED|
|
||||
TAG_EXT|
|
||||
TAG_CCID|
|
||||
TAG_ERR
|
||||
);
|
||||
|
||||
|
@ -11,9 +11,6 @@
|
||||
|
||||
#define KEY_SPACE_BYTES 128
|
||||
#define MAX_KEYS (1)
|
||||
#define PIN_SALT_LEN (32)
|
||||
#define STATE_VERSION (1)
|
||||
|
||||
|
||||
#define BACKUP_MARKER 0x5A
|
||||
#define INITIALIZED_MARKER 0xA5
|
||||
@ -22,40 +19,20 @@
|
||||
#define ERR_KEY_SPACE_TAKEN (-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
|
||||
{
|
||||
// Pin information
|
||||
uint8_t is_initialized;
|
||||
uint8_t is_pin_set;
|
||||
uint8_t PIN_CODE_HASH[32];
|
||||
uint8_t PIN_SALT[PIN_SALT_LEN];
|
||||
int _reserved;
|
||||
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];
|
||||
uint8_t data_version;
|
||||
} AuthenticatorState_0x01;
|
||||
|
||||
typedef AuthenticatorState_0x01 AuthenticatorState;
|
||||
} AuthenticatorState;
|
||||
|
||||
|
||||
typedef struct
|
||||
|
@ -118,9 +118,9 @@ void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONS
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
device_disable_up(true); // disable presence test
|
||||
request_from_nfc(true); // disable presence test
|
||||
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)
|
||||
|
31
pc/device.c
31
pc/device.c
@ -26,7 +26,6 @@
|
||||
#define RK_NUM 50
|
||||
|
||||
bool use_udp = true;
|
||||
static bool _up_disabled = false;
|
||||
|
||||
struct ResidentKeyStore {
|
||||
CTAP_residentKey rks[RK_NUM];
|
||||
@ -44,11 +43,7 @@ void device_set_status(uint32_t status)
|
||||
__device_status = status;
|
||||
}
|
||||
|
||||
void device_reboot()
|
||||
{
|
||||
printf1(TAG_RED, "REBOOT command recieved!\r\n");
|
||||
exit(100);
|
||||
}
|
||||
|
||||
|
||||
int udp_server()
|
||||
{
|
||||
@ -300,10 +295,6 @@ void ctaphid_write_block(uint8_t * data)
|
||||
|
||||
int ctap_user_presence_test(uint32_t d)
|
||||
{
|
||||
if (_up_disabled)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -313,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;
|
||||
counter1 += amount;
|
||||
return counter1;
|
||||
/*return 713;*/
|
||||
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)
|
||||
@ -629,11 +629,6 @@ int device_is_nfc()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void device_disable_up(bool disable)
|
||||
{
|
||||
_up_disabled = disable;
|
||||
}
|
||||
|
||||
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
|
||||
{
|
||||
|
||||
|
@ -10,7 +10,6 @@ SRC += $(DRIVER_LIBS) $(USB_LIB)
|
||||
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
|
||||
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
|
||||
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
|
||||
SRC += ../../fido2/data_migration.c
|
||||
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c
|
||||
SRC += ../../fido2/extensions/wallet.c
|
||||
|
||||
|
@ -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 \
|
||||
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_ccid.c
|
||||
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c
|
||||
|
||||
VERSION:=$(shell git describe --abbrev=0 )
|
||||
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,
|
||||
// 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
|
||||
@ -489,7 +782,45 @@ static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
|
||||
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
|
||||
* return Device Qualifier descriptor
|
||||
@ -608,10 +939,22 @@ uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
|
||||
/* Suspend or Resume USB Out process */
|
||||
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,
|
||||
CDC_OUT_EP,
|
||||
hcdc->RxBuffer,
|
||||
CDC_DATA_FS_OUT_PACKET_SIZE);
|
||||
}
|
||||
return USBD_OK;
|
||||
}
|
||||
else
|
||||
|
@ -2,9 +2,7 @@
|
||||
#include "usbd_desc.h"
|
||||
#include "usbd_hid.h"
|
||||
#include "usbd_cdc.h"
|
||||
#include "usbd_ccid.h"
|
||||
#include "usbd_ctlreq.h"
|
||||
#include "app.h"
|
||||
|
||||
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);
|
||||
|
||||
#ifdef ENABLE_CCID
|
||||
#define CCID_SIZE 84
|
||||
#define CCID_NUM_INTERFACE 1
|
||||
#define NUM_CLASSES 2
|
||||
#define NUM_INTERFACES 3
|
||||
|
||||
#if NUM_INTERFACES>1
|
||||
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (90 + 8+9 + 4)
|
||||
#else
|
||||
#define CCID_NUM_INTERFACE 0
|
||||
#define CCID_SIZE 0
|
||||
#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (41)
|
||||
#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 CDC_MASTER_INTF_NUM 1
|
||||
#define CDC_SLAVE_INTF_NUM 2
|
||||
#define CCID_INTF_NUM 3
|
||||
#define CDC_SLAVE_INTF_NUM 2
|
||||
__ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END =
|
||||
{
|
||||
/*Configuration Descriptor*/
|
||||
@ -111,7 +94,7 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
|
||||
0x00,
|
||||
HID_BINTERVAL, /*bInterval: Polling Interval */
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
#if NUM_INTERFACES > 1
|
||||
|
||||
/* */
|
||||
/* CDC */
|
||||
@ -208,83 +191,6 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
|
||||
0x09,
|
||||
0x04,
|
||||
#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 =
|
||||
@ -305,21 +211,15 @@ USBD_ClassTypeDef USBD_Composite =
|
||||
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 out_endpoint_to_class[MAX_ENDPOINTS];
|
||||
|
||||
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *ccid_class, USBD_ClassTypeDef *cdc_class) {
|
||||
memset(USBD_Classes, 0 , sizeof(USBD_Classes));
|
||||
void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *cdc_class) {
|
||||
USBD_Classes[0] = hid_class;
|
||||
#ifdef ENABLE_CCID
|
||||
USBD_Classes[1] = ccid_class;
|
||||
#endif
|
||||
#if DEBUG_LEVEL > 0
|
||||
USBD_Classes[2] = cdc_class;
|
||||
#endif
|
||||
USBD_Classes[1] = cdc_class;
|
||||
}
|
||||
|
||||
static USBD_ClassTypeDef * getClass(uint8_t index)
|
||||
@ -328,15 +228,9 @@ static USBD_ClassTypeDef * getClass(uint8_t index)
|
||||
{
|
||||
case HID_INTF_NUM:
|
||||
return USBD_Classes[0];
|
||||
#ifdef ENABLE_CCID
|
||||
case CCID_INTF_NUM:
|
||||
return USBD_Classes[1];
|
||||
#endif
|
||||
#if DEBUG_LEVEL > 0
|
||||
case CDC_MASTER_INTF_NUM:
|
||||
case CDC_SLAVE_INTF_NUM:
|
||||
return USBD_Classes[2];
|
||||
#endif
|
||||
return USBD_Classes[1];
|
||||
}
|
||||
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) {
|
||||
int 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;
|
||||
}
|
||||
}
|
||||
//N
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
|
||||
int 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;
|
||||
}
|
||||
}
|
||||
@ -381,7 +275,7 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
|
||||
|
||||
case USB_REQ_GET_DESCRIPTOR :
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -404,8 +298,6 @@ static uint8_t USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) {
|
||||
|
||||
i = in_endpoint_to_class[epnum];
|
||||
|
||||
if (USBD_Classes[i] == NULL) return USBD_FAIL;
|
||||
|
||||
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];
|
||||
|
||||
if (USBD_Classes[i] == NULL) return USBD_FAIL;
|
||||
|
||||
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) {
|
||||
int 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) {
|
||||
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) {
|
||||
//Y
|
||||
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
||||
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length) {
|
||||
//N
|
||||
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
||||
return COMPOSITE_CDC_HID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length) {
|
||||
|
||||
*length = COMPOSITE_CDC_HID_DESCRIPTOR_SIZE;
|
||||
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) {
|
||||
//N
|
||||
*length = sizeof (USBD_Composite_DeviceQualifierDesc);
|
||||
return USBD_Composite_DeviceQualifierDesc;
|
||||
*length = sizeof (USBD_Composite_DeviceQualifierDesc);
|
||||
return USBD_Composite_DeviceQualifierDesc;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ extern int in_endpoint_to_class[MAX_ENDPOINTS];
|
||||
|
||||
extern int out_endpoint_to_class[MAX_ENDPOINTS];
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -50,9 +50,6 @@
|
||||
#include "stm32l4xx_hal.h"
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_hid.h"
|
||||
#include "usbd_cdc.h"
|
||||
#include "usbd_ccid.h"
|
||||
#include "log.h"
|
||||
|
||||
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);
|
||||
switch(epnum)
|
||||
{
|
||||
case HID_EPOUT_ADDR:
|
||||
case HID_ENDPOINT:
|
||||
usb_hid_recieve_callback(epnum);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the low level portion of the device driver.
|
||||
* @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);
|
||||
|
||||
// HID
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR , PCD_SNG_BUF, 0x98);
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR , PCD_SNG_BUF, 0xd8);
|
||||
|
||||
// CCID
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_OUT_EP , PCD_SNG_BUF, 0xd8 + 64); // data OUT
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_IN_EP , PCD_SNG_BUF, 0xd8 + 64*2); // data IN
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CCID_CMD_EP , PCD_SNG_BUF, 0xd8 + 64*3); // commands
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x98);
|
||||
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xd8);
|
||||
|
||||
// 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 , CDC_OUT_EP , PCD_SNG_BUF, 0xd8 + 64*5); // data OUT
|
||||
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 , 0x02 , PCD_SNG_BUF, 0xd8 + 64); // 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 , 0x83 , PCD_SNG_BUF, 0xd8 + 64*3); // commands
|
||||
|
||||
// dump_pma_header("usbd_conf");
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
@ -323,7 +310,6 @@ USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev,
|
||||
uint8_t ep_type,
|
||||
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,
|
||||
ep_addr,
|
||||
ep_mps,
|
||||
|
@ -12,13 +12,9 @@
|
||||
#define DEBUG_UART USART1
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
// Enable the CDC ACM USB interface & debug logs (DEBUG_LEVEL > 0)
|
||||
#define DEBUG_LEVEL 0
|
||||
#endif
|
||||
|
||||
// Enable the CCID USB interface
|
||||
// #define ENABLE_CCID
|
||||
|
||||
#define NON_BLOCK_PRINTING 0
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ uint32_t __last_update = 0;
|
||||
extern PCD_HandleTypeDef hpcd;
|
||||
static int _NFC_status = 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))
|
||||
static int is_physical_button_pressed()
|
||||
@ -55,45 +55,13 @@ static int is_physical_button_pressed()
|
||||
|
||||
static int is_touch_button_pressed()
|
||||
{
|
||||
int is_pressed = (tsc_read_button(0) || tsc_read_button(1));
|
||||
#ifndef IS_BOOTLOADER
|
||||
if (is_pressed)
|
||||
{
|
||||
// delay for debounce, and longer than polling timer period.
|
||||
delay(95);
|
||||
return (tsc_read_button(0) || tsc_read_button(1));
|
||||
}
|
||||
#endif
|
||||
return is_pressed;
|
||||
return tsc_read_button(0) || tsc_read_button(1);
|
||||
}
|
||||
|
||||
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
|
||||
|
||||
static void edge_detect_touch_button()
|
||||
{
|
||||
static uint8_t last_touch = 0;
|
||||
uint8_t current_touch = 0;
|
||||
if (is_touch_button_pressed == IS_BUTTON_PRESSED)
|
||||
{
|
||||
current_touch = (tsc_read_button(0) || tsc_read_button(1));
|
||||
|
||||
// 1 sample per 25 ms
|
||||
if ((millis() - __last_button_bounce_time) > 25)
|
||||
{
|
||||
// Detect "touch / rising edge"
|
||||
if (!last_touch && current_touch)
|
||||
{
|
||||
__last_button_press_time = millis();
|
||||
}
|
||||
__last_button_bounce_time = millis();
|
||||
last_touch = current_touch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void device_disable_up(bool disable) {
|
||||
_up_disabled = disable;
|
||||
void request_from_nfc(bool request_active) {
|
||||
_RequestComeFromNFC = request_active;
|
||||
}
|
||||
|
||||
// Timer6 overflow handler. happens every ~90ms.
|
||||
@ -110,7 +78,19 @@ void TIM6_DAC_IRQHandler()
|
||||
}
|
||||
}
|
||||
|
||||
edge_detect_touch_button();
|
||||
|
||||
if (is_touch_button_pressed == IS_BUTTON_PRESSED)
|
||||
{
|
||||
if (IS_BUTTON_PRESSED())
|
||||
{
|
||||
// Only allow 1 press per 25 ms.
|
||||
if ((millis() - __last_button_bounce_time) > 25)
|
||||
{
|
||||
__last_button_press_time = millis();
|
||||
}
|
||||
__last_button_bounce_time = millis();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IS_BOOTLOADER
|
||||
// NFC sending WTX if needs
|
||||
@ -162,6 +142,7 @@ void device_set_status(uint32_t status)
|
||||
|
||||
int device_is_button_pressed()
|
||||
{
|
||||
|
||||
return IS_BUTTON_PRESSED();
|
||||
}
|
||||
|
||||
@ -407,7 +388,7 @@ void authenticator_write_state(AuthenticatorState * a, int backup)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ctap_atomic_count(uint32_t amount)
|
||||
uint32_t ctap_atomic_count(int sel)
|
||||
{
|
||||
int offset = 0;
|
||||
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
||||
@ -422,12 +403,10 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
||||
|
||||
uint32_t lastc = 0;
|
||||
|
||||
if (amount == 0)
|
||||
if (sel != 0)
|
||||
{
|
||||
// Use a random count [1-16].
|
||||
uint8_t rng[1];
|
||||
ctap_generate_rng(rng, 1);
|
||||
amount = (rng[0] & 0x0f) + 1;
|
||||
printf2(TAG_ERR,"counter2 not imple\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (offset = 0; offset < PAGE_SIZE/4; offset += 2) // wear-level the flash
|
||||
@ -460,7 +439,7 @@ uint32_t ctap_atomic_count(uint32_t amount)
|
||||
return lastc;
|
||||
}
|
||||
|
||||
lastc += amount;
|
||||
lastc++;
|
||||
|
||||
if (lastc/256 > erases)
|
||||
{
|
||||
@ -584,17 +563,11 @@ static int wait_for_button_release(uint32_t wait)
|
||||
int ctap_user_presence_test(uint32_t up_delay)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (device_is_nfc() == NFC_IS_ACTIVE)
|
||||
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_up_disabled)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
||||
int i=500;
|
||||
while(i--)
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "usbd_desc.h"
|
||||
#include "usbd_hid.h"
|
||||
#include "usbd_cdc.h"
|
||||
#include "usbd_ccid.h"
|
||||
#include "usbd_composite.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "device.h"
|
||||
@ -706,26 +705,26 @@ void init_usb()
|
||||
|
||||
// Enable USB Clock
|
||||
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;
|
||||
out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0;
|
||||
|
||||
in_endpoint_to_class[CCID_IN_EP & 0x7F] = 1;
|
||||
out_endpoint_to_class[CCID_OUT_EP & 0x7F] = 1;
|
||||
|
||||
in_endpoint_to_class[CDC_IN_EP & 0x7F] = 2;
|
||||
out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 2;
|
||||
in_endpoint_to_class[CDC_IN_EP & 0x7F] = 1;
|
||||
out_endpoint_to_class[CDC_OUT_EP & 0x7F] = 1;
|
||||
|
||||
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
|
||||
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);
|
||||
#endif
|
||||
#else
|
||||
USBD_Init(&Solo_USBD_Device, &Solo_Desc, 0);
|
||||
USBD_RegisterClass(&Solo_USBD_Device, &USBD_HID);
|
||||
#endif
|
||||
|
||||
USBD_Start(&Solo_USBD_Device);
|
||||
}
|
||||
|
||||
|
@ -14,23 +14,6 @@
|
||||
|
||||
#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 offset = 1;
|
||||
// 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;
|
||||
|
||||
res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f);
|
||||
res[1] = current_cid;
|
||||
res[1] = 0;
|
||||
res[2] = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 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};
|
||||
res[0] = iBlock;
|
||||
res[1] = current_cid;
|
||||
res[2] = 0;
|
||||
if (len && data)
|
||||
memcpy(&res[block_offset], data, len);
|
||||
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
|
||||
int vlen = MIN(32 - block_offset, len - sendlen);
|
||||
res[0] = iBlock;
|
||||
res[1] = current_cid;
|
||||
res[1] = 0;
|
||||
res[2] = 0;
|
||||
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);
|
||||
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]);
|
||||
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:
|
||||
// sends/receives WTX frame to reader every `WTX_time` time in ms
|
||||
// works via timer interrupts
|
||||
@ -494,9 +429,7 @@ void rblock_acknowledge(uint8_t req0, bool ack)
|
||||
NFC_STATE.block_num = !NFC_STATE.block_num;
|
||||
|
||||
buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f);
|
||||
buf[1] = current_cid;
|
||||
// iso14443-4:2001 page 16. ACK, if bit is set to 0, NAK, if bit is set to 1
|
||||
if (!ack)
|
||||
if (ack)
|
||||
buf[0] |= NFC_CMD_RBLOCK_ACK;
|
||||
|
||||
nfc_write_frame(buf, block_offset);
|
||||
@ -550,70 +483,34 @@ int select_applet(uint8_t * aid, int len)
|
||||
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;
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
int status;
|
||||
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
|
||||
if (apdu->cla != 0x00 && apdu->cla != 0x80) {
|
||||
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu->cla);
|
||||
nfc_write_response(buf0, SW_CLA_INVALID);
|
||||
if (apdu.cla != 0x00 && apdu.cla != 0x80) {
|
||||
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla);
|
||||
nfc_write_response(buf[0], SW_CLA_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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:
|
||||
// if (apdu->p1 == 0 && apdu->p2 == 0x0c)
|
||||
// {
|
||||
@ -629,49 +526,49 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
||||
// }
|
||||
// else
|
||||
{
|
||||
selected = select_applet(apdu->data, apdu->lc);
|
||||
selected = select_applet(apdu.data, apdu.lc);
|
||||
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");
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
nfc_write_response(buf0, SW_FILE_NOT_FOUND);
|
||||
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu->data, apdu->lc);
|
||||
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
|
||||
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_VERSION:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf0, SW_INS_INVALID);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
|
||||
|
||||
u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp);
|
||||
nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu);
|
||||
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
|
||||
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_REGISTER:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf0, SW_INS_INVALID);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
nfc_write_response(buf0, SW_WRONG_LENGTH);
|
||||
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc);
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -682,59 +579,59 @@ void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu)
|
||||
// SystemClock_Config_LF32();
|
||||
// delay(300);
|
||||
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 (!WTX_off())
|
||||
// return;
|
||||
|
||||
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||
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());
|
||||
break;
|
||||
|
||||
case APDU_FIDO_U2F_AUTHENTICATE:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf0, SW_INS_INVALID);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu.lc, apdu.data[64]);
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp();
|
||||
// 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())
|
||||
// return;
|
||||
|
||||
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
|
||||
printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp());
|
||||
nfc_write_response_chaining(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);
|
||||
break;
|
||||
|
||||
case APDU_FIDO_NFCCTAP_MSG:
|
||||
if (NFC_STATE.selected_applet != APP_FIDO) {
|
||||
nfc_write_response(buf0, SW_INS_INVALID);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
|
||||
|
||||
// WTX_on(WTX_TIME_DEFAULT);
|
||||
device_disable_up(true);
|
||||
request_from_nfc(true);
|
||||
ctap_response_init(&ctap_resp);
|
||||
status = ctap_request(apdu->data, apdu->lc, &ctap_resp);
|
||||
device_disable_up(false);
|
||||
status = ctap_request(apdu.data, apdu.lc, &ctap_resp);
|
||||
request_from_nfc(false);
|
||||
// if (!WTX_off())
|
||||
// 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;
|
||||
|
||||
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());
|
||||
break;
|
||||
|
||||
case APDU_INS_READ_BINARY:
|
||||
// response length
|
||||
reslen = apdu->le & 0xffff;
|
||||
reslen = apdu.le & 0xffff;
|
||||
switch(NFC_STATE.selected_applet)
|
||||
{
|
||||
case APP_CAPABILITY_CONTAINER:
|
||||
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
|
||||
if (reslen == 0 || 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);
|
||||
break;
|
||||
case APP_NDEF_TAG:
|
||||
printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
|
||||
if (reslen == 0 || 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);
|
||||
break;
|
||||
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");
|
||||
return;
|
||||
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:
|
||||
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins);
|
||||
nfc_write_response(buf0, SW_INS_INVALID);
|
||||
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins);
|
||||
nfc_write_response(buf[0], SW_INS_INVALID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_process_iblock(uint8_t * buf, int len)
|
||||
{
|
||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||
|
||||
// clear tx chain buffer if we have some other command than GET RESPONSE
|
||||
if (chain_buffer_tx && buf[block_offset + 1] != APDU_GET_RESPONSE) {
|
||||
chain_buffer_len = 0;
|
||||
chain_buffer_tx = false;
|
||||
}
|
||||
|
||||
APDU_STRUCT apdu;
|
||||
uint16_t ret = apdu_decode(buf + block_offset, len - block_offset, &apdu);
|
||||
if (ret != 0) {
|
||||
printf1(TAG_NFC,"apdu decode error\r\n");
|
||||
nfc_write_response(buf[0], ret);
|
||||
return;
|
||||
}
|
||||
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
|
||||
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
|
||||
|
||||
// APDU level chaining. ISO7816-4, 5.1.1. class byte
|
||||
if (!chain_buffer_tx && buf[block_offset] & 0x10) {
|
||||
|
||||
if (chain_buffer_len + len > sizeof(chain_buffer)) {
|
||||
nfc_write_response(buf[0], SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(&chain_buffer[chain_buffer_len], apdu.data, apdu.lc);
|
||||
chain_buffer_len += apdu.lc;
|
||||
nfc_write_response(buf[0], SW_SUCCESS);
|
||||
printf1(TAG_NFC, "APDU chaining ok. %d/%d\r\n", apdu.lc, chain_buffer_len);
|
||||
return;
|
||||
}
|
||||
|
||||
// if we have ISO 7816 APDU chain - move there all the data
|
||||
if (!chain_buffer_tx && chain_buffer_len > 0) {
|
||||
memmove(&apdu.data[chain_buffer_len], apdu.data, apdu.lc);
|
||||
memmove(apdu.data, chain_buffer, chain_buffer_len);
|
||||
apdu.lc += chain_buffer_len; // here apdu struct does not match with memory!
|
||||
printf1(TAG_NFC, "APDU chaining merge. %d/%d\r\n", chain_buffer_len, apdu.lc);
|
||||
}
|
||||
|
||||
|
||||
apdu_process(buf[0], &buf[block_offset], &apdu);
|
||||
|
||||
printf1(TAG_NFC,"prev.Iblock: ");
|
||||
dump_hex1(TAG_NFC, buf, len);
|
||||
@ -882,11 +719,9 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
|
||||
else if (IS_IBLOCK(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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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);
|
||||
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> ");
|
||||
dump_hex1(TAG_NFC_APDU, buf, len);
|
||||
|
||||
nfc_process_iblock(ibuf, ibuflen);
|
||||
} else {
|
||||
memcpy(ibuf, buf, len); // because buf only 32b
|
||||
nfc_process_iblock(ibuf, len);
|
||||
nfc_process_iblock(buf, len);
|
||||
}
|
||||
clear_ibuf();
|
||||
}
|
||||
}
|
||||
else if (IS_RBLOCK(buf[0]))
|
||||
{
|
||||
if (p14443_have_cid(buf[0]))
|
||||
current_cid = buf[1];
|
||||
rblock_acknowledge(buf[0], true);
|
||||
rblock_acknowledge(buf[0], false);
|
||||
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
|
||||
}
|
||||
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)
|
||||
{
|
||||
printf1(TAG_NFC, "NFC_CMD_SBLOCK, DESELECTED\r\n");
|
||||
uint8_t block_offset = p14443_block_offset(buf[0]);
|
||||
if (p14443_have_cid(buf[0]))
|
||||
current_cid = buf[1];
|
||||
nfc_write_frame(buf, block_offset);
|
||||
nfc_write_frame(buf, 1);
|
||||
ams_wait_for_tx(2);
|
||||
ams_write_command(AMS_CMD_SLEEP);
|
||||
nfc_state_init();
|
||||
|
@ -34,9 +34,9 @@ typedef struct
|
||||
#define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS)
|
||||
#define NFC_CMD_IBLOCK 0x00
|
||||
#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
#define NFC_CMD_RBLOCK 0xa0
|
||||
#define NFC_CMD_RBLOCK_ACK 0x10
|
||||
#define IS_RBLOCK(x) ( (((x) & 0xe0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
#define NFC_CMD_RBLOCK 0x80
|
||||
#define NFC_CMD_RBLOCK_ACK 0x20
|
||||
#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
#define NFC_CMD_SBLOCK 0xc0
|
||||
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
|
||||
|
||||
|
Reference in New Issue
Block a user