Merge branch 'master' into macosx
This commit is contained in:
commit
fad474ad2c
2
Makefile
2
Makefile
@ -16,6 +16,7 @@ src = $(wildcard pc/*.c) $(wildcard fido2/*.c) $(wildcard crypto/sha256/*.c) cry
|
|||||||
obj = $(src:.c=.o) uECC.o
|
obj = $(src:.c=.o) uECC.o
|
||||||
|
|
||||||
LIBCBOR = tinycbor/lib/libtinycbor.a
|
LIBCBOR = tinycbor/lib/libtinycbor.a
|
||||||
|
|
||||||
ifeq ($(shell uname -s),Darwin)
|
ifeq ($(shell uname -s),Darwin)
|
||||||
export LDFLAGS = -Wl,-dead_strip
|
export LDFLAGS = -Wl,-dead_strip
|
||||||
else
|
else
|
||||||
@ -116,4 +117,3 @@ clean:
|
|||||||
fi ;\
|
fi ;\
|
||||||
done
|
done
|
||||||
rm -rf venv
|
rm -rf venv
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ bulk order and provide open source security tokens for everyone that is interest
|
|||||||
Clone solo and build it
|
Clone solo and build it
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/SoloKeysSec/solo
|
git clone --recurse-submodules https://github.com/SoloKeysSec/solo
|
||||||
cd solo/
|
cd solo/
|
||||||
|
|
||||||
git submodules init
|
git submodules init
|
||||||
|
@ -29,7 +29,7 @@ int main(int argc, char * argv[])
|
|||||||
uint8_t key[32];
|
uint8_t key[32];
|
||||||
uint8_t authtag[BLOCK_SIZE];
|
uint8_t authtag[BLOCK_SIZE];
|
||||||
|
|
||||||
uint8_t * authtag1 = "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b";
|
// uint8_t * authtag1 = (uint8_t *)"\x53\x0f\x8a\xfb\xc7\x45\x36\xb9\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b";
|
||||||
|
|
||||||
memset(nonce,0,16);
|
memset(nonce,0,16);
|
||||||
memset(key,0,16);
|
memset(key,0,16);
|
||||||
|
40
docs/code-overview.md
Normal file
40
docs/code-overview.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Overview of firmware
|
||||||
|
|
||||||
|
This is a high level overview of the code. We aim to make the code self documenting
|
||||||
|
and easy to understand, especially when paired with a high level overview.
|
||||||
|
|
||||||
|
## FIDO2 codebase
|
||||||
|
|
||||||
|
* main.c - calls high level functions and implements event loop.
|
||||||
|
|
||||||
|
* ctaphid.c - implements [USBHID protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb) for FIDO.
|
||||||
|
|
||||||
|
* u2f.c - implements [U2F protocol](https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html).
|
||||||
|
|
||||||
|
* ctap.c - implements [CTAP2 protocol](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html).
|
||||||
|
|
||||||
|
* ctap_parse.c - implements parsing for CTAP protocol.
|
||||||
|
* this could use some work minimizing.
|
||||||
|
|
||||||
|
* log.c - embedded friendly debug logging.
|
||||||
|
|
||||||
|
* crypto.c - software implementation of the crypto needs of the application. Generally this will be copied and edited for different platforms. API defined in crypto.h should be the same.
|
||||||
|
|
||||||
|
* device.h - definitions of functions that are platform specific and should be implemented separately. See device.c in any of the implementations to see examples.
|
||||||
|
|
||||||
|
## Data flow
|
||||||
|
|
||||||
|
The main loop will poll the USB peripheral to see if any messages arrived,
|
||||||
|
and then pass each one to the USBHID layer.
|
||||||
|
|
||||||
|
Once a USBHID message is fully buffered, it will be acted on, unless there was a previous error.
|
||||||
|
This will get passed up to U2F or CTAP2 layer. The response is buffered and then written out to USB.
|
||||||
|
|
||||||
|
Depending on platform, there should be a minimum number of interrupts configured. USB will need interrupts,
|
||||||
|
and possibly timer interrupts for keeping track of time. ST implementation users a 16-bit timer to track time,
|
||||||
|
and interrupts to count overflows.
|
||||||
|
|
||||||
|
If the application is waiting on user input in CTAP2, then USBHID messages need to be continued to be polled,
|
||||||
|
to catch any [cancel command](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-hid-cancel).
|
||||||
|
Also, every 100ms or so, an update needs to be sent via USBHID if the CTAP2 application is still processing a getAssertion request,
|
||||||
|
a makeCredential request, or is waiting on user input. ST leverages same 16-bit timer interrupt for this.
|
@ -2,6 +2,10 @@ Documentation of the `master` branch is deployed to Netlify automatically.
|
|||||||
|
|
||||||
To host or develop locally:
|
To host or develop locally:
|
||||||
|
|
||||||
- `make docsrv` and visit [localhost:8000](http://localhost:8000).
|
```
|
||||||
|
pip install mkdocs mkdocs-material
|
||||||
|
```
|
||||||
|
|
||||||
|
`make docsrv` and visit [localhost:8000](http://localhost:8000).
|
||||||
|
|
||||||
The file `runtime.txt` is necessary to tell Netlify to use Python3.
|
The file `runtime.txt` is necessary to tell Netlify to use Python3.
|
||||||
|
@ -39,7 +39,11 @@ Try reading and writing to the device node you identified in the previous step.
|
|||||||
* write: try `echo "hello, Solo" > /dev/hidraw0`. Again, if you don't get denied permission, you're OK.
|
* write: try `echo "hello, Solo" > /dev/hidraw0`. Again, if you don't get denied permission, you're OK.
|
||||||
|
|
||||||
## Which rule should I use, and how do I do it?
|
## Which rule should I use, and how do I do it?
|
||||||
Simplest is probably to copy [Yubico's rule file](https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules) to `/etc/udev/rules.d/fido.rules` on your system. This contains rules for Yubico's keys, the U2F Zero, and many others. The relevant line for U2F Zero is:
|
Simplest is probably to copy [Yubico's rule file](https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules) to `/etc/udev/rules.d/fido.rules` on your system, for instance:
|
||||||
|
```
|
||||||
|
$ (cd /etc/udev/rules.d/ && sudo curl https://raw.githubusercontent.com/Yubico/libu2f-host/master/70-u2f.rules -O)
|
||||||
|
```
|
||||||
|
This contains rules for Yubico's keys, the U2F Zero, and many others. The relevant line for U2F Zero is:
|
||||||
```
|
```
|
||||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess"
|
||||||
```
|
```
|
||||||
|
@ -53,11 +53,9 @@ static const uint8_t * _signing_key = NULL;
|
|||||||
static int _key_len = 0;
|
static int _key_len = 0;
|
||||||
|
|
||||||
// Secrets for testing only
|
// Secrets for testing only
|
||||||
static uint8_t master_secret[32] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
|
static uint8_t master_secret[32];
|
||||||
"\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00";
|
|
||||||
|
|
||||||
static uint8_t transport_secret[32] = "\x10\x01\x22\x33\x44\x55\x66\x77\x87\x90\x0a\xbb\x3c\xd8\xee\xff"
|
static uint8_t transport_secret[32];
|
||||||
"\xff\xee\x8d\x1c\x3b\xfa\x99\x88\x77\x86\x55\x44\xd3\xff\x33\x00";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -71,6 +69,11 @@ void crypto_reset_master_secret()
|
|||||||
ctap_generate_rng(master_secret, 32);
|
ctap_generate_rng(master_secret, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void crypto_load_master_secret(uint8_t * key)
|
||||||
|
{
|
||||||
|
memmove(master_secret, key, 32);
|
||||||
|
memmove(transport_secret, key+32, 32);
|
||||||
|
}
|
||||||
|
|
||||||
void crypto_sha256_update(uint8_t * data, size_t len)
|
void crypto_sha256_update(uint8_t * data, size_t len)
|
||||||
{
|
{
|
||||||
@ -353,5 +356,3 @@ const uint16_t attestation_key_size = sizeof(attestation_key)-1;
|
|||||||
#else
|
#else
|
||||||
#error "No crypto implementation defined"
|
#error "No crypto implementation defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,9 +49,8 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
|
|||||||
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
||||||
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
|
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
|
||||||
|
|
||||||
// Key must be 32 bytes
|
#define CRYPTO_TRANSPORT_KEY ((uint8_t*)1)
|
||||||
#define CRYPTO_TRANSPORT_KEY NULL
|
#define CRYPTO_MASTER_KEY ((uint8_t*)0)
|
||||||
#define CRYPTO_MASTER_KEY NULL
|
|
||||||
|
|
||||||
void crypto_aes256_init(uint8_t * key, uint8_t * nonce);
|
void crypto_aes256_init(uint8_t * key, uint8_t * nonce);
|
||||||
void crypto_aes256_reset_iv(uint8_t * nonce);
|
void crypto_aes256_reset_iv(uint8_t * nonce);
|
||||||
@ -61,11 +60,13 @@ void crypto_aes256_decrypt(uint8_t * buf, int lenth);
|
|||||||
void crypto_aes256_encrypt(uint8_t * buf, int lenth);
|
void crypto_aes256_encrypt(uint8_t * buf, int lenth);
|
||||||
|
|
||||||
void crypto_reset_master_secret();
|
void crypto_reset_master_secret();
|
||||||
|
void crypto_load_master_secret(uint8_t * key);
|
||||||
|
|
||||||
|
|
||||||
extern const uint8_t attestation_cert_der[];
|
extern const uint8_t attestation_cert_der[];
|
||||||
extern const uint16_t attestation_cert_der_size;
|
extern const uint16_t attestation_cert_der_size;
|
||||||
|
|
||||||
|
extern const uint8_t attestation_key[];
|
||||||
|
extern const uint16_t attestation_key_size;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
217
fido2/ctap.c
217
fido2/ctap.c
@ -26,6 +26,7 @@
|
|||||||
#include "cbor.h"
|
#include "cbor.h"
|
||||||
|
|
||||||
#include "ctap.h"
|
#include "ctap.h"
|
||||||
|
#include "ctaphid.h"
|
||||||
#include "ctap_parse.h"
|
#include "ctap_parse.h"
|
||||||
#include "ctap_errors.h"
|
#include "ctap_errors.h"
|
||||||
#include "cose_key.h"
|
#include "cose_key.h"
|
||||||
@ -43,6 +44,7 @@ uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
|||||||
uint8_t KEY_AGREEMENT_PUB[64];
|
uint8_t KEY_AGREEMENT_PUB[64];
|
||||||
static uint8_t KEY_AGREEMENT_PRIV[32];
|
static uint8_t KEY_AGREEMENT_PRIV[32];
|
||||||
static uint8_t PIN_CODE_HASH[32];
|
static uint8_t PIN_CODE_HASH[32];
|
||||||
|
static int8_t PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||||
|
|
||||||
AuthenticatorState STATE;
|
AuthenticatorState STATE;
|
||||||
|
|
||||||
@ -264,15 +266,15 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void make_auth_tag(struct rpId * rp, CTAP_userEntity * user, uint32_t count, uint8_t * tag)
|
void make_auth_tag(uint8_t * nonce, CTAP_userEntity * user, uint32_t count, uint8_t * tag)
|
||||||
{
|
{
|
||||||
uint8_t hashbuf[32];
|
uint8_t hashbuf[32];
|
||||||
crypto_sha256_hmac_init(NULL, 0, hashbuf);
|
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, hashbuf);
|
||||||
crypto_sha256_update(rp->id, rp->size);
|
crypto_sha256_update(nonce, CREDENTIAL_NONCE_SIZE);
|
||||||
crypto_sha256_update(user->id, user->id_size);
|
crypto_sha256_update(user->id, user->id_size);
|
||||||
crypto_sha256_update(user->name, strnlen((const char*)user->name, USER_NAME_LIMIT));
|
crypto_sha256_update(user->name, strnlen((const char*)user->name, USER_NAME_LIMIT));
|
||||||
crypto_sha256_update((uint8_t*)&count, 4);
|
crypto_sha256_update((uint8_t*)&count, 4);
|
||||||
crypto_sha256_hmac_final(NULL,0,hashbuf);
|
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY,0,hashbuf);
|
||||||
|
|
||||||
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
|
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
|
||||||
}
|
}
|
||||||
@ -283,21 +285,19 @@ static uint32_t auth_data_update_count(CTAP_authDataHeader * authData)
|
|||||||
if (count == 0) // count 0 will indicate invalid token
|
if (count == 0) // count 0 will indicate invalid token
|
||||||
{
|
{
|
||||||
count = ctap_atomic_count( 0 );
|
count = ctap_atomic_count( 0 );
|
||||||
|
|
||||||
}
|
}
|
||||||
uint8_t * byte = (uint8_t*) &authData->signCount;
|
uint8_t * byte = (uint8_t*) &authData->signCount;
|
||||||
|
|
||||||
*byte++ = count & 0xff;
|
*byte++ = (count >> 0) & 0xff;
|
||||||
count = count >> 8;
|
*byte++ = (count >> 8) & 0xff;
|
||||||
*byte++ = count & 0xff;
|
*byte++ = (count >> 16) & 0xff;
|
||||||
count = count >> 8;
|
*byte++ = (count >> 24) & 0xff;
|
||||||
*byte++ = count & 0xff;
|
|
||||||
count = count >> 8;
|
|
||||||
*byte++ = count & 0xff;
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, int len, CTAP_userEntity * user, uint8_t credtype, int32_t algtype)
|
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, int len, CTAP_userEntity * user, uint8_t credtype, int32_t algtype, int32_t * sz)
|
||||||
{
|
{
|
||||||
CborEncoder cose_key;
|
CborEncoder cose_key;
|
||||||
int auth_data_sz, ret;
|
int auth_data_sz, ret;
|
||||||
@ -318,10 +318,24 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
|
|
||||||
count = auth_data_update_count(&authData->head);
|
count = auth_data_update_count(&authData->head);
|
||||||
|
|
||||||
authData->head.flags = (ctap_user_presence_test() << 0);
|
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||||
|
int but = ctap_user_presence_test();
|
||||||
|
|
||||||
|
if (!but)
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
|
else if (but < 0) // Cancel
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
||||||
|
}
|
||||||
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
|
|
||||||
|
authData->head.flags = (but << 0);
|
||||||
authData->head.flags |= (ctap_user_verification(0) << 2);
|
authData->head.flags |= (ctap_user_verification(0) << 2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (credtype != 0)
|
if (credtype != 0)
|
||||||
{
|
{
|
||||||
// add attestedCredentialData
|
// add attestedCredentialData
|
||||||
@ -338,19 +352,19 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
#else
|
#else
|
||||||
memset((uint8_t*)&authData->attest.credential, 0, sizeof(struct Credential));
|
memset((uint8_t*)&authData->attest.credential, 0, sizeof(struct Credential));
|
||||||
|
|
||||||
// Make a tag we can later check to make sure this is a token we made
|
ctap_generate_rng(authData->attest.credential.nonce, CREDENTIAL_NONCE_SIZE);
|
||||||
make_auth_tag(rp, user, count, authData->attest.credential.tag);
|
|
||||||
|
|
||||||
memmove(&authData->attest.credential.enc.user, user, sizeof(CTAP_userEntity)); //TODO encrypt this
|
memmove(&authData->attest.credential.enc.user, user, sizeof(CTAP_userEntity));
|
||||||
authData->attest.credential.enc.count = count;
|
authData->attest.credential.enc.count = count;
|
||||||
|
|
||||||
|
// Make a tag we can later check to make sure this is a token we made
|
||||||
|
make_auth_tag(authData->attest.credential.nonce, user, count, authData->attest.credential.tag);
|
||||||
|
|
||||||
crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL);
|
crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL);
|
||||||
crypto_aes256_encrypt((uint8_t*)&authData->attest.credential.enc, CREDENTIAL_ENC_SIZE);
|
crypto_aes256_encrypt((uint8_t*)&authData->attest.credential.enc, CREDENTIAL_ENC_SIZE);
|
||||||
|
|
||||||
ctap_generate_cose_key(&cose_key, (uint8_t*)&authData->attest.credential, sizeof(struct Credential), credtype, algtype);
|
ctap_generate_cose_key(&cose_key, (uint8_t*)&authData->attest.credential, sizeof(struct Credential), credtype, algtype);
|
||||||
|
|
||||||
printf1(TAG_MC,"COSE_KEY: "); dump_hex1(TAG_MC, cose_key_buf, cbor_encoder_get_buffer_size(&cose_key, cose_key_buf));
|
|
||||||
|
|
||||||
auth_data_sz = sizeof(CTAP_authData) + cbor_encoder_get_buffer_size(&cose_key, cose_key_buf);
|
auth_data_sz = sizeof(CTAP_authData) + cbor_encoder_get_buffer_size(&cose_key, cose_key_buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -367,7 +381,8 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return auth_data_sz;
|
if (sz) *sz = auth_data_sz;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -419,7 +434,6 @@ int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHa
|
|||||||
crypto_sha256_update(clientDataHash, CLIENT_DATA_HASH_SIZE);
|
crypto_sha256_update(clientDataHash, CLIENT_DATA_HASH_SIZE);
|
||||||
crypto_sha256_final(hashbuf);
|
crypto_sha256_final(hashbuf);
|
||||||
|
|
||||||
printf1(TAG_GREEN, "sha256: "); dump_hex1(TAG_DUMP,hashbuf,32);
|
|
||||||
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
||||||
|
|
||||||
return ctap_encode_der_sig(sigbuf,sigder);
|
return ctap_encode_der_sig(sigbuf,sigder);
|
||||||
@ -471,13 +485,8 @@ uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
|
|||||||
int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * desc)
|
int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * desc)
|
||||||
{
|
{
|
||||||
uint8_t tag[16];
|
uint8_t tag[16];
|
||||||
if (desc->type != PUB_KEY_CRED_PUB_KEY)
|
|
||||||
{
|
|
||||||
printf1(TAG_GA,"unsupported credential type: %d\n", desc->type);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
make_auth_tag(rp, &desc->credential.enc.user, desc->credential.enc.count, tag);
|
make_auth_tag(desc->credential.nonce, &desc->credential.enc.user, desc->credential.enc.count, tag);
|
||||||
|
|
||||||
return (memcmp(desc->credential.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
return (memcmp(desc->credential.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
|
||||||
}
|
}
|
||||||
@ -519,6 +528,12 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MC.up)
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_INVALID_OPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL);
|
||||||
for (i = 0; i < MC.excludeListSize; i++)
|
for (i = 0; i < MC.excludeListSize; i++)
|
||||||
{
|
{
|
||||||
ret = parse_credential_descriptor(&MC.excludeList, excl_cred);
|
ret = parse_credential_descriptor(&MC.excludeList, excl_cred);
|
||||||
@ -528,8 +543,11 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
|
||||||
|
crypto_aes256_reset_iv(NULL);
|
||||||
|
crypto_aes256_decrypt((uint8_t*)& excl_cred->credential.enc, CREDENTIAL_ENC_SIZE);
|
||||||
if (ctap_authenticate_credential(&MC.rp, excl_cred))
|
if (ctap_authenticate_credential(&MC.rp, excl_cred))
|
||||||
{
|
{
|
||||||
|
printf1(TAG_MC, "Cred %d failed!\r\n",i);
|
||||||
return CTAP2_ERR_CREDENTIAL_EXCLUDED;
|
return CTAP2_ERR_CREDENTIAL_EXCLUDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,9 +558,11 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
CborEncoder map;
|
CborEncoder map;
|
||||||
ret = cbor_encoder_create_map(encoder, &map, 3);
|
ret = cbor_encoder_create_map(encoder, &map, 3);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
int32_t auth_data_sz;
|
||||||
|
|
||||||
int auth_data_sz = ctap_make_auth_data(&MC.rp, &map, auth_data_buf, sizeof(auth_data_buf),
|
ret = ctap_make_auth_data(&MC.rp, &map, auth_data_buf, sizeof(auth_data_buf),
|
||||||
&MC.user, MC.publicKeyCredentialType, MC.COSEAlgorithmIdentifier);
|
&MC.user, MC.publicKeyCredentialType, MC.COSEAlgorithmIdentifier, &auth_data_sz);
|
||||||
|
check_retr(ret);
|
||||||
|
|
||||||
crypto_ecc256_load_attestation_key();
|
crypto_ecc256_load_attestation_key();
|
||||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_sz, MC.clientDataHash, auth_data_buf, sigbuf, sigder);
|
int sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_sz, MC.clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||||
@ -724,11 +744,6 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
|||||||
|
|
||||||
crypto_ecc256_load_key((uint8_t*)&cred->credential, sizeof(struct Credential), NULL, 0);
|
crypto_ecc256_load_key((uint8_t*)&cred->credential, sizeof(struct Credential), NULL, 0);
|
||||||
|
|
||||||
/*printf1(TAG_GREEN,"auth_data_buf: "); dump_hex1(TAG_DUMP, auth_data_buf, sizeof(CTAP_authDataHeader));*/
|
|
||||||
/*printf1(TAG_GREEN,"clientdatahash: "); dump_hex1(TAG_DUMP, clientDataHash, 32);*/
|
|
||||||
/*printf1(TAG_GREEN,"credential: # %d\n", cred->credential.enc.count);*/
|
|
||||||
/*dump_hex1(TAG_DUMP, clientDataHash, 32);*/
|
|
||||||
|
|
||||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -801,12 +816,16 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!GA.rp.size || !GA.clientDataHashPresent)
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_MISSING_PARAMETER;
|
||||||
|
}
|
||||||
CborEncoder map;
|
CborEncoder map;
|
||||||
ret = cbor_encoder_create_map(encoder, &map, 5);
|
ret = cbor_encoder_create_map(encoder, &map, 5);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
|
||||||
ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0);
|
ret = ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0,NULL);
|
||||||
|
check_retr(ret);
|
||||||
|
|
||||||
printf1(TAG_GA, "ALLOW_LIST has %d creds\n", GA.credLen);
|
printf1(TAG_GA, "ALLOW_LIST has %d creds\n", GA.credLen);
|
||||||
/*for (int j = 0; j < GA.credLen; j++)*/
|
/*for (int j = 0; j < GA.credLen; j++)*/
|
||||||
@ -834,13 +853,13 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Error, no authentic credential\n");
|
printf2(TAG_ERR,"Error, no authentic credential\n");
|
||||||
return CTAP2_ERR_CREDENTIAL_NOT_VALID;
|
return CTAP2_ERR_NO_CREDENTIALS;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_RED,"resulting order of creds:\n");
|
printf1(TAG_GA,"resulting order of creds:\n");
|
||||||
for (int j = 0; j < GA.credLen; j++)
|
for (int j = 0; j < GA.credLen; j++)
|
||||||
{
|
{
|
||||||
printf1(TAG_RED,"CRED ID (# %d)\n", GA.creds[j].credential.enc.count);
|
printf1(TAG_GA,"CRED ID (# %d)\n", GA.creds[j].credential.enc.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -861,6 +880,18 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return how many trailing zeros in a buffer
|
||||||
|
static int trailing_zeros(uint8_t * buf, int indx)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
while(0==buf[indx] && indx)
|
||||||
|
{
|
||||||
|
indx--;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platform_pubkey, uint8_t * pinAuth, uint8_t * pinHashEnc)
|
uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platform_pubkey, uint8_t * pinAuth, uint8_t * pinHashEnc)
|
||||||
{
|
{
|
||||||
uint8_t shared_secret[32];
|
uint8_t shared_secret[32];
|
||||||
@ -876,7 +907,11 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
{
|
{
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
return CTAP2_ERR_PIN_BLOCKED;
|
||||||
|
}
|
||||||
|
if (ctap_device_boot_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,25 +946,31 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
|
|
||||||
crypto_aes256_decrypt(pinEnc, len);
|
crypto_aes256_decrypt(pinEnc, len);
|
||||||
|
|
||||||
printf1(TAG_CP,"new pin: %s\n", pinEnc);
|
|
||||||
|
|
||||||
ret = strnlen((const char *)pinEnc, NEW_PIN_ENC_MAX_SIZE);
|
|
||||||
if (ret == NEW_PIN_ENC_MAX_SIZE)
|
ret = trailing_zeros(pinEnc, NEW_PIN_ENC_MIN_SIZE - 1);
|
||||||
|
ret = NEW_PIN_ENC_MIN_SIZE - ret;
|
||||||
|
|
||||||
|
if (ret < NEW_PIN_MIN_SIZE || ret >= NEW_PIN_MAX_SIZE)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"No NULL terminator in new pin string\n");
|
printf2(TAG_ERR,"new PIN is too short or too long [%d bytes]\n", ret);
|
||||||
return CTAP1_ERR_OTHER;
|
|
||||||
}
|
|
||||||
else if (ret < 4)
|
|
||||||
{
|
|
||||||
printf2(TAG_ERR,"new PIN is too short\n");
|
|
||||||
return CTAP2_ERR_PIN_POLICY_VIOLATION;
|
return CTAP2_ERR_PIN_POLICY_VIOLATION;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf1(TAG_CP,"new pin: %s [%d bytes]\n", pinEnc, ret);
|
||||||
|
dump_hex1(TAG_CP, pinEnc, ret);
|
||||||
|
}
|
||||||
|
|
||||||
if (ctap_is_pin_set())
|
if (ctap_is_pin_set())
|
||||||
{
|
{
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
return CTAP2_ERR_PIN_BLOCKED;
|
||||||
|
}
|
||||||
|
if (ctap_device_boot_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||||
}
|
}
|
||||||
crypto_aes256_reset_iv(NULL);
|
crypto_aes256_reset_iv(NULL);
|
||||||
crypto_aes256_decrypt(pinHashEnc, 16);
|
crypto_aes256_decrypt(pinHashEnc, 16);
|
||||||
@ -937,6 +978,10 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
{
|
{
|
||||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||||
ctap_decrement_pin_attempts();
|
ctap_decrement_pin_attempts();
|
||||||
|
if (ctap_device_boot_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||||
|
}
|
||||||
return CTAP2_ERR_PIN_INVALID;
|
return CTAP2_ERR_PIN_INVALID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -976,6 +1021,10 @@ uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubke
|
|||||||
// Generate new keyAgreement pair
|
// Generate new keyAgreement pair
|
||||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||||
ctap_decrement_pin_attempts();
|
ctap_decrement_pin_attempts();
|
||||||
|
if (ctap_device_boot_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||||
|
}
|
||||||
return CTAP2_ERR_PIN_INVALID;
|
return CTAP2_ERR_PIN_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,6 +1044,20 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
|
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
|
||||||
int ret = ctap_parse_client_pin(&CP,request,length);
|
int ret = ctap_parse_client_pin(&CP,request,length);
|
||||||
|
|
||||||
|
switch(CP.subCommand)
|
||||||
|
{
|
||||||
|
case CP_cmdSetPin:
|
||||||
|
case CP_cmdChangePin:
|
||||||
|
case CP_cmdGetPinToken:
|
||||||
|
if (ctap_device_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_BLOCKED;
|
||||||
|
}
|
||||||
|
if (ctap_device_boot_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
@ -1104,7 +1167,7 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_map)
|
if (num_map || CP.getRetries)
|
||||||
{
|
{
|
||||||
ret = cbor_encoder_close_container(encoder, &map);
|
ret = cbor_encoder_close_container(encoder, &map);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
@ -1141,10 +1204,14 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
{
|
{
|
||||||
case CTAP_MAKE_CREDENTIAL:
|
case CTAP_MAKE_CREDENTIAL:
|
||||||
case CTAP_GET_ASSERTION:
|
case CTAP_GET_ASSERTION:
|
||||||
case CTAP_CLIENT_PIN:
|
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
status = CTAP2_ERR_OPERATION_DENIED;
|
status = CTAP2_ERR_PIN_BLOCKED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ctap_device_boot_locked())
|
||||||
|
{
|
||||||
|
status = CTAP2_ERR_PIN_AUTH_BLOCKED;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1153,6 +1220,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
switch(cmd)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case CTAP_MAKE_CREDENTIAL:
|
case CTAP_MAKE_CREDENTIAL:
|
||||||
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
printf1(TAG_CTAP,"CTAP_MAKE_CREDENTIAL\n");
|
printf1(TAG_CTAP,"CTAP_MAKE_CREDENTIAL\n");
|
||||||
t1 = millis();
|
t1 = millis();
|
||||||
status = ctap_make_credential(&encoder, pkt_raw, length);
|
status = ctap_make_credential(&encoder, pkt_raw, length);
|
||||||
@ -1164,6 +1232,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
||||||
break;
|
break;
|
||||||
case CTAP_GET_ASSERTION:
|
case CTAP_GET_ASSERTION:
|
||||||
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
printf1(TAG_CTAP,"CTAP_GET_ASSERTION\n");
|
printf1(TAG_CTAP,"CTAP_GET_ASSERTION\n");
|
||||||
t1 = millis();
|
t1 = millis();
|
||||||
status = ctap_get_assertion(&encoder, pkt_raw, length);
|
status = ctap_get_assertion(&encoder, pkt_raw, length);
|
||||||
@ -1190,6 +1259,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
case CTAP_CLIENT_PIN:
|
case CTAP_CLIENT_PIN:
|
||||||
printf1(TAG_CTAP,"CTAP_CLIENT_PIN\n");
|
printf1(TAG_CTAP,"CTAP_CLIENT_PIN\n");
|
||||||
status = ctap_client_pin(&encoder, pkt_raw, length);
|
status = ctap_client_pin(&encoder, pkt_raw, length);
|
||||||
|
|
||||||
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
||||||
dump_hex1(TAG_DUMP, buf, cbor_encoder_get_buffer_size(&encoder, buf));
|
dump_hex1(TAG_DUMP, buf, cbor_encoder_get_buffer_size(&encoder, buf));
|
||||||
break;
|
break;
|
||||||
@ -1228,6 +1298,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
device_set_status(CTAPHID_STATUS_IDLE);
|
||||||
getAssertionState.lastcmd = cmd;
|
getAssertionState.lastcmd = cmd;
|
||||||
|
|
||||||
if (status != CTAP1_ERR_SUCCESS)
|
if (status != CTAP1_ERR_SUCCESS)
|
||||||
@ -1235,7 +1306,7 @@ done:
|
|||||||
resp->length = 0;
|
resp->length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_CTAP,"cbor output structure: %d bytes\n", resp->length);
|
printf1(TAG_CTAP,"cbor output structure: %d bytes. Return 0x%02x\n", resp->length, status);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -1253,6 +1324,9 @@ static void ctap_state_init()
|
|||||||
{
|
{
|
||||||
// Set to 0xff instead of 0x00 to be easier on flash
|
// Set to 0xff instead of 0x00 to be easier on flash
|
||||||
memset(&STATE, 0xff, sizeof(AuthenticatorState));
|
memset(&STATE, 0xff, sizeof(AuthenticatorState));
|
||||||
|
// Fresh RNG for key
|
||||||
|
ctap_generate_rng(STATE.key_space, KEY_SPACE_BYTES);
|
||||||
|
|
||||||
STATE.is_initialized = INITIALIZED_MARKER;
|
STATE.is_initialized = INITIALIZED_MARKER;
|
||||||
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||||
STATE.is_pin_set = 0;
|
STATE.is_pin_set = 0;
|
||||||
@ -1264,6 +1338,8 @@ void ctap_init()
|
|||||||
|
|
||||||
authenticator_read_state(&STATE);
|
authenticator_read_state(&STATE);
|
||||||
|
|
||||||
|
device_set_status(CTAPHID_STATUS_IDLE);
|
||||||
|
|
||||||
if (STATE.is_initialized == INITIALIZED_MARKER)
|
if (STATE.is_initialized == INITIALIZED_MARKER)
|
||||||
{
|
{
|
||||||
printf1(TAG_STOR,"Auth state is initialized\n");
|
printf1(TAG_STOR,"Auth state is initialized\n");
|
||||||
@ -1286,11 +1362,13 @@ void ctap_init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crypto_load_master_secret(STATE.key_space);
|
||||||
|
|
||||||
if (ctap_is_pin_set())
|
if (ctap_is_pin_set())
|
||||||
{
|
{
|
||||||
printf1(TAG_STOR,"pin code: \"%s\"\n", STATE.pin_code);
|
printf1(TAG_STOR,"pin code: \"%s\"\n", STATE.pin_code);
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
crypto_sha256_update(STATE.pin_code, strnlen(STATE.pin_code, NEW_PIN_ENC_MAX_SIZE));
|
crypto_sha256_update(STATE.pin_code, STATE.pin_code_length);
|
||||||
crypto_sha256_final(PIN_CODE_HASH);
|
crypto_sha256_final(PIN_CODE_HASH);
|
||||||
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
|
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
|
||||||
}
|
}
|
||||||
@ -1303,7 +1381,6 @@ void ctap_init()
|
|||||||
printf1(TAG_ERR, "DEVICE LOCKED!\n");
|
printf1(TAG_ERR, "DEVICE LOCKED!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ctap_generate_rng(PIN_TOKEN, PIN_TOKEN_SIZE) != 1)
|
if (ctap_generate_rng(PIN_TOKEN, PIN_TOKEN_SIZE) != 1)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Error, rng failed\n");
|
printf2(TAG_ERR,"Error, rng failed\n");
|
||||||
@ -1331,14 +1408,15 @@ uint8_t ctap_pin_matches(uint8_t * pin, int len)
|
|||||||
|
|
||||||
void ctap_update_pin(uint8_t * pin, int len)
|
void ctap_update_pin(uint8_t * pin, int len)
|
||||||
{
|
{
|
||||||
// TODO this should go in flash
|
if (len > NEW_PIN_ENC_MIN_SIZE || len < 4)
|
||||||
if (len > NEW_PIN_ENC_MAX_SIZE-1 || len < 4)
|
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR, "Update pin fail length\n");
|
printf2(TAG_ERR, "Update pin fail length\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memset(STATE.pin_code, 0, NEW_PIN_ENC_MAX_SIZE);
|
memset(STATE.pin_code, 0, NEW_PIN_ENC_MIN_SIZE);
|
||||||
memmove(STATE.pin_code, pin, len);
|
memmove(STATE.pin_code, pin, len);
|
||||||
|
STATE.pin_code_length = len;
|
||||||
|
STATE.pin_code[NEW_PIN_ENC_MIN_SIZE - 1] = 0;
|
||||||
|
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
crypto_sha256_update(STATE.pin_code, len);
|
crypto_sha256_update(STATE.pin_code, len);
|
||||||
@ -1346,18 +1424,25 @@ void ctap_update_pin(uint8_t * pin, int len)
|
|||||||
|
|
||||||
STATE.is_pin_set = 1;
|
STATE.is_pin_set = 1;
|
||||||
|
|
||||||
|
authenticator_write_state(&STATE, 1);
|
||||||
|
authenticator_write_state(&STATE, 0);
|
||||||
|
|
||||||
printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
|
printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ctap_decrement_pin_attempts()
|
uint8_t ctap_decrement_pin_attempts()
|
||||||
{
|
{
|
||||||
if (STATE.remaining_tries > 0)
|
if (PIN_BOOT_ATTEMPTS_LEFT > 0)
|
||||||
|
{
|
||||||
|
PIN_BOOT_ATTEMPTS_LEFT--;
|
||||||
|
}
|
||||||
|
if (! ctap_device_locked())
|
||||||
{
|
{
|
||||||
STATE.remaining_tries--;
|
STATE.remaining_tries--;
|
||||||
ctap_flush_state(0);
|
ctap_flush_state(0);
|
||||||
printf1(TAG_CP, "ATTEMPTS left: %d\n", STATE.remaining_tries);
|
printf1(TAG_CP, "ATTEMPTS left: %d\n", STATE.remaining_tries);
|
||||||
|
|
||||||
if (STATE.remaining_tries == 0)
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
|
memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
|
||||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||||
@ -1374,7 +1459,12 @@ uint8_t ctap_decrement_pin_attempts()
|
|||||||
|
|
||||||
int8_t ctap_device_locked()
|
int8_t ctap_device_locked()
|
||||||
{
|
{
|
||||||
return STATE.remaining_tries == 0;
|
return STATE.remaining_tries <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ctap_device_boot_locked()
|
||||||
|
{
|
||||||
|
return PIN_BOOT_ATTEMPTS_LEFT <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t ctap_leftover_pin_attempts()
|
int8_t ctap_leftover_pin_attempts()
|
||||||
@ -1385,6 +1475,7 @@ int8_t ctap_leftover_pin_attempts()
|
|||||||
void ctap_reset_pin_attempts()
|
void ctap_reset_pin_attempts()
|
||||||
{
|
{
|
||||||
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||||
|
PIN_BOOT_ATTEMPTS_LEFT = PIN_BOOT_ATTEMPTS;
|
||||||
ctap_flush_state(0);
|
ctap_flush_state(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1459,7 +1550,6 @@ int8_t ctap_store_key(uint8_t index, uint8_t * key, uint16_t len)
|
|||||||
|
|
||||||
memmove(STATE.key_space + offset, key, len);
|
memmove(STATE.key_space + offset, key, len);
|
||||||
|
|
||||||
ctap_flush_state(0);
|
|
||||||
ctap_flush_state(1);
|
ctap_flush_state(1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1511,6 +1601,5 @@ void ctap_reset()
|
|||||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||||
|
|
||||||
crypto_reset_master_secret(); // Not sure what the significance of this is??
|
crypto_reset_master_secret();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
fido2/ctap.h
16
fido2/ctap.h
@ -34,7 +34,8 @@
|
|||||||
#define CTAP_VENDOR_FIRST 0x40
|
#define CTAP_VENDOR_FIRST 0x40
|
||||||
#define CTAP_VENDOR_LAST 0xBF
|
#define CTAP_VENDOR_LAST 0xBF
|
||||||
|
|
||||||
#define CTAP_AAGUID ((uint8_t*)"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")
|
// AAGUID For Solo
|
||||||
|
#define CTAP_AAGUID ((uint8_t*)"\x88\x76\x63\x1b\xd4\xa0\x42\x7f\x57\x73\x0e\xc7\x1c\x9e\x02\x79")
|
||||||
|
|
||||||
#define MC_clientDataHash 0x01
|
#define MC_clientDataHash 0x01
|
||||||
#define MC_rp 0x02
|
#define MC_rp 0x02
|
||||||
@ -126,10 +127,14 @@
|
|||||||
#define ALLOW_LIST_MAX_SIZE 20
|
#define ALLOW_LIST_MAX_SIZE 20
|
||||||
|
|
||||||
#define NEW_PIN_ENC_MAX_SIZE 256 // includes NULL terminator
|
#define NEW_PIN_ENC_MAX_SIZE 256 // includes NULL terminator
|
||||||
|
#define NEW_PIN_ENC_MIN_SIZE 64
|
||||||
|
#define NEW_PIN_MAX_SIZE 64
|
||||||
|
#define NEW_PIN_MIN_SIZE 4
|
||||||
|
|
||||||
#define CTAP_RESPONSE_BUFFER_SIZE 1024
|
#define CTAP_RESPONSE_BUFFER_SIZE 4096
|
||||||
|
|
||||||
#define PIN_LOCKOUT_ATTEMPTS 8
|
#define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total
|
||||||
|
#define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -198,6 +203,7 @@ typedef struct
|
|||||||
|
|
||||||
uint8_t rk;
|
uint8_t rk;
|
||||||
uint8_t uv;
|
uint8_t uv;
|
||||||
|
uint8_t up;
|
||||||
|
|
||||||
uint8_t pinAuth[16];
|
uint8_t pinAuth[16];
|
||||||
uint8_t pinAuthPresent;
|
uint8_t pinAuthPresent;
|
||||||
@ -215,6 +221,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
uint32_t paramsParsed;
|
uint32_t paramsParsed;
|
||||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||||
|
uint8_t clientDataHashPresent;
|
||||||
|
|
||||||
struct rpId rp;
|
struct rpId rp;
|
||||||
|
|
||||||
@ -222,12 +229,14 @@ typedef struct
|
|||||||
|
|
||||||
uint8_t rk;
|
uint8_t rk;
|
||||||
uint8_t uv;
|
uint8_t uv;
|
||||||
|
uint8_t up;
|
||||||
|
|
||||||
uint8_t pinAuth[16];
|
uint8_t pinAuth[16];
|
||||||
uint8_t pinAuthPresent;
|
uint8_t pinAuthPresent;
|
||||||
int pinProtocol;
|
int pinProtocol;
|
||||||
|
|
||||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
||||||
|
uint8_t allowListPresent;
|
||||||
} CTAP_getAssertion;
|
} CTAP_getAssertion;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -281,6 +290,7 @@ uint8_t ctap_is_pin_set();
|
|||||||
uint8_t ctap_pin_matches(uint8_t * pin, int len);
|
uint8_t ctap_pin_matches(uint8_t * pin, int len);
|
||||||
void ctap_reset();
|
void ctap_reset();
|
||||||
int8_t ctap_device_locked();
|
int8_t ctap_device_locked();
|
||||||
|
int8_t ctap_device_boot_locked();
|
||||||
|
|
||||||
// Key storage API
|
// Key storage API
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ const char * cbor_value_get_type_string(const CborValue *value)
|
|||||||
uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||||
{
|
{
|
||||||
size_t sz, map_length;
|
size_t sz, map_length;
|
||||||
uint8_t key[8];
|
uint8_t key[24];
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
CborValue map;
|
CborValue map;
|
||||||
@ -126,6 +126,7 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
|||||||
printf2(TAG_ERR,"Error, rp map key is too large\n");
|
printf2(TAG_ERR,"Error, rp map key is too large\n");
|
||||||
return CTAP2_ERR_LIMIT_EXCEEDED;
|
return CTAP2_ERR_LIMIT_EXCEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
key[sizeof(key) - 1] = 0;
|
key[sizeof(key) - 1] = 0;
|
||||||
|
|
||||||
@ -153,6 +154,11 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
|||||||
}
|
}
|
||||||
else if (strcmp((const char *)key, "name") == 0)
|
else if (strcmp((const char *)key, "name") == 0)
|
||||||
{
|
{
|
||||||
|
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"Error, expecting text string type for user.name value\n");
|
||||||
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
|
}
|
||||||
sz = USER_NAME_LIMIT;
|
sz = USER_NAME_LIMIT;
|
||||||
ret = cbor_value_copy_text_string(&map, (char *)MC->user.name, &sz, NULL);
|
ret = cbor_value_copy_text_string(&map, (char *)MC->user.name, &sz, NULL);
|
||||||
if (ret != CborErrorOutOfMemory)
|
if (ret != CborErrorOutOfMemory)
|
||||||
@ -161,6 +167,22 @@ uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val)
|
|||||||
}
|
}
|
||||||
MC->user.name[USER_NAME_LIMIT - 1] = 0;
|
MC->user.name[USER_NAME_LIMIT - 1] = 0;
|
||||||
}
|
}
|
||||||
|
else if (strcmp((const char *)key, "displayName") == 0)
|
||||||
|
{
|
||||||
|
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"Error, expecting text string type for user.displayName value\n");
|
||||||
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp((const char *)key, "icon") == 0)
|
||||||
|
{
|
||||||
|
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"Error, expecting text string type for user.icon value\n");
|
||||||
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf1(TAG_PARSE,"ignoring key %s for user map\n", key);
|
printf1(TAG_PARSE,"ignoring key %s for user map\n", key);
|
||||||
@ -263,6 +285,19 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
|||||||
ret = cbor_value_get_array_length(val, &arr_length);
|
ret = cbor_value_get_array_length(val, &arr_length);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
|
||||||
|
for (i = 0; i < arr_length; i++)
|
||||||
|
{
|
||||||
|
if ((ret = parse_pub_key_cred_param(&arr, &cred_type, &alg_type)) != 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = cbor_value_advance(&arr);
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_enter_container(val,&arr);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
for (i = 0; i < arr_length; i++)
|
for (i = 0; i < arr_length; i++)
|
||||||
{
|
{
|
||||||
if ((ret = parse_pub_key_cred_param(&arr, &cred_type, &alg_type)) == 0)
|
if ((ret = parse_pub_key_cred_param(&arr, &cred_type, &alg_type)) == 0)
|
||||||
@ -275,11 +310,6 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Continue? fail?
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret = cbor_value_advance(&arr);
|
ret = cbor_value_advance(&arr);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
@ -309,10 +339,40 @@ uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t parse_verify_exclude_list(CborValue * val)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
CborValue arr;
|
||||||
|
size_t size;
|
||||||
|
CTAP_credentialDescriptor cred;
|
||||||
|
if (cbor_value_get_type(val) != CborArrayType)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"error, exclude list is not a map\n");
|
||||||
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
|
}
|
||||||
|
ret = cbor_value_get_array_length(val, &size);
|
||||||
|
check_ret(ret);
|
||||||
|
ret = cbor_value_enter_container(val,&arr);
|
||||||
|
check_ret(ret);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
ret = parse_credential_descriptor(&arr, &cred);
|
||||||
|
check_ret(ret);
|
||||||
|
ret = cbor_value_advance(&arr);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t parse_rp_id(struct rpId * rp, CborValue * val)
|
uint8_t parse_rp_id(struct rpId * rp, CborValue * val)
|
||||||
{
|
{
|
||||||
size_t sz = DOMAIN_NAME_MAX_SIZE;
|
size_t sz = DOMAIN_NAME_MAX_SIZE;
|
||||||
|
if (cbor_value_get_type(val) != CborTextStringType)
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
|
}
|
||||||
int ret = cbor_value_copy_text_string(val, (char*)rp->id, &sz, NULL);
|
int ret = cbor_value_copy_text_string(val, (char*)rp->id, &sz, NULL);
|
||||||
if (ret == CborErrorOutOfMemory)
|
if (ret == CborErrorOutOfMemory)
|
||||||
{
|
{
|
||||||
@ -413,7 +473,7 @@ uint8_t parse_rp(struct rpId * rp, CborValue * val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv)
|
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up)
|
||||||
{
|
{
|
||||||
size_t sz, map_length;
|
size_t sz, map_length;
|
||||||
char key[8];
|
char key[8];
|
||||||
@ -463,21 +523,27 @@ uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv)
|
|||||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(key, "rk") == 0)
|
if (strncmp(key, "rk",2) == 0)
|
||||||
{
|
{
|
||||||
ret = cbor_value_get_boolean(&map, &b);
|
ret = cbor_value_get_boolean(&map, &b);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
*rk = b;
|
*rk = b;
|
||||||
}
|
}
|
||||||
else if (strcmp(key, "uv") == 0)
|
else if (strncmp(key, "uv",2) == 0)
|
||||||
{
|
{
|
||||||
ret = cbor_value_get_boolean(&map, &b);
|
ret = cbor_value_get_boolean(&map, &b);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
*uv = b;
|
*uv = b;
|
||||||
}
|
}
|
||||||
|
else if (strncmp(key, "up",2) == 0)
|
||||||
|
{
|
||||||
|
ret = cbor_value_get_boolean(&map, &b);
|
||||||
|
check_ret(ret);
|
||||||
|
*up = b;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf1(TAG_PARSE,"ignoring key %s for option map\n", key);
|
printf2(TAG_PARSE,"ignoring option specified %s\n", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -576,27 +642,30 @@ uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encod
|
|||||||
break;
|
break;
|
||||||
case MC_excludeList:
|
case MC_excludeList:
|
||||||
printf1(TAG_MC,"CTAP_excludeList\n");
|
printf1(TAG_MC,"CTAP_excludeList\n");
|
||||||
if( cbor_value_get_type(&map) == CborArrayType )
|
ret = parse_verify_exclude_list(&map);
|
||||||
{
|
check_ret(ret);
|
||||||
|
|
||||||
ret = cbor_value_enter_container(&map, &MC->excludeList);
|
ret = cbor_value_enter_container(&map, &MC->excludeList);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
|
||||||
ret = cbor_value_get_array_length(&map, &MC->excludeListSize);
|
ret = cbor_value_get_array_length(&map, &MC->excludeListSize);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
|
||||||
}
|
|
||||||
printf1(TAG_MC,"CTAP_excludeList done\n");
|
printf1(TAG_MC,"CTAP_excludeList done\n");
|
||||||
break;
|
break;
|
||||||
case MC_extensions:
|
case MC_extensions:
|
||||||
printf1(TAG_MC,"CTAP_extensions\n");
|
printf1(TAG_MC,"CTAP_extensions\n");
|
||||||
|
type = cbor_value_get_type(&map);
|
||||||
|
if (type != CborMapType)
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_INVALID_CBOR_TYPE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MC_options:
|
case MC_options:
|
||||||
printf1(TAG_MC,"CTAP_options\n");
|
printf1(TAG_MC,"CTAP_options\n");
|
||||||
ret = parse_options(&map, &MC->rk, &MC->uv);
|
ret = parse_options(&map, &MC->rk, &MC->uv, &MC->up);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
break;
|
break;
|
||||||
case MC_pinAuth:
|
case MC_pinAuth:
|
||||||
@ -661,8 +730,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
|||||||
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential, &buflen, NULL);
|
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential, &buflen, NULL);
|
||||||
if (buflen != CREDENTIAL_ID_SIZE)
|
if (buflen != CREDENTIAL_ID_SIZE)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Error, credential is incorrect length\n");
|
printf2(TAG_ERR,"Ignoring credential is incorrect length\n");
|
||||||
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail?
|
//return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail?
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cbor_value_map_find_value(arr, "type", &val);
|
ret = cbor_value_map_find_value(arr, "type", &val);
|
||||||
@ -677,13 +746,14 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
|
|||||||
buflen = sizeof(type);
|
buflen = sizeof(type);
|
||||||
cbor_value_copy_text_string(&val, type, &buflen, NULL);
|
cbor_value_copy_text_string(&val, type, &buflen, NULL);
|
||||||
|
|
||||||
if (strcmp(type, "public-key") == 0)
|
if (strncmp(type, "public-key",11) == 0)
|
||||||
{
|
{
|
||||||
cred->type = PUB_KEY_CRED_PUB_KEY;
|
cred->type = PUB_KEY_CRED_PUB_KEY;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cred->type = PUB_KEY_CRED_UNKNOWN;
|
cred->type = PUB_KEY_CRED_UNKNOWN;
|
||||||
|
printf1(TAG_RED, "Unknown type: %s\r\n", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -783,6 +853,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
|||||||
|
|
||||||
ret = parse_fixed_byte_string(&map, GA->clientDataHash, CLIENT_DATA_HASH_SIZE);
|
ret = parse_fixed_byte_string(&map, GA->clientDataHash, CLIENT_DATA_HASH_SIZE);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
GA->clientDataHashPresent = 1;
|
||||||
|
|
||||||
printf1(TAG_GA," "); dump_hex1(TAG_GA, GA->clientDataHash, 32);
|
printf1(TAG_GA," "); dump_hex1(TAG_GA, GA->clientDataHash, 32);
|
||||||
break;
|
break;
|
||||||
@ -796,10 +867,9 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
|||||||
case GA_allowList:
|
case GA_allowList:
|
||||||
printf1(TAG_GA,"GA_allowList\n");
|
printf1(TAG_GA,"GA_allowList\n");
|
||||||
ret = parse_allow_list(GA, &map);
|
ret = parse_allow_list(GA, &map);
|
||||||
if (ret == 0)
|
check_ret(ret);
|
||||||
{
|
GA->allowListPresent = 1;
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case GA_extensions:
|
case GA_extensions:
|
||||||
printf1(TAG_GA,"GA_extensions\n");
|
printf1(TAG_GA,"GA_extensions\n");
|
||||||
@ -807,7 +877,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
|
|||||||
|
|
||||||
case GA_options:
|
case GA_options:
|
||||||
printf1(TAG_GA,"CTAP_options\n");
|
printf1(TAG_GA,"CTAP_options\n");
|
||||||
ret = parse_options(&map, &GA->rk, &GA->uv);
|
ret = parse_options(&map, &GA->rk, &GA->uv, &GA->up);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
break;
|
break;
|
||||||
case GA_pinAuth:
|
case GA_pinAuth:
|
||||||
@ -1033,10 +1103,11 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
|
|||||||
{
|
{
|
||||||
ret = cbor_value_calculate_string_length(&map, &sz);
|
ret = cbor_value_calculate_string_length(&map, &sz);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
if (sz > NEW_PIN_ENC_MAX_SIZE)
|
if (sz > NEW_PIN_ENC_MAX_SIZE || sz < NEW_PIN_ENC_MIN_SIZE)
|
||||||
{
|
{
|
||||||
return CTAP1_ERR_OTHER;
|
return CTAP2_ERR_PIN_POLICY_VIOLATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
CP->newPinEncSize = sz;
|
CP->newPinEncSize = sz;
|
||||||
sz = NEW_PIN_ENC_MAX_SIZE;
|
sz = NEW_PIN_ENC_MAX_SIZE;
|
||||||
ret = cbor_value_copy_byte_string(&map, CP->newPinEnc, &sz, NULL);
|
ret = cbor_value_copy_byte_string(&map, CP->newPinEnc, &sz, NULL);
|
||||||
@ -1078,5 +1149,3 @@ uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val);
|
|||||||
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len);
|
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len);
|
||||||
uint8_t parse_rp_id(struct rpId * rp, CborValue * val);
|
uint8_t parse_rp_id(struct rpId * rp, CborValue * val);
|
||||||
uint8_t parse_rp(struct rpId * rp, CborValue * val);
|
uint8_t parse_rp(struct rpId * rp, CborValue * val);
|
||||||
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv);
|
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv, uint8_t * up);
|
||||||
|
|
||||||
uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it);
|
uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it);
|
||||||
uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv);
|
uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv);
|
||||||
|
214
fido2/ctaphid.c
214
fido2/ctaphid.c
@ -43,6 +43,8 @@ typedef enum
|
|||||||
EMPTY = 0,
|
EMPTY = 0,
|
||||||
BUFFERING,
|
BUFFERING,
|
||||||
BUFFERED,
|
BUFFERED,
|
||||||
|
HID_ERROR,
|
||||||
|
HID_IGNORE,
|
||||||
} CTAP_BUFFER_STATE;
|
} CTAP_BUFFER_STATE;
|
||||||
|
|
||||||
|
|
||||||
@ -221,7 +223,6 @@ static int buffer_packet(CTAPHID_PACKET * pkt)
|
|||||||
|
|
||||||
static void buffer_reset()
|
static void buffer_reset()
|
||||||
{
|
{
|
||||||
|
|
||||||
ctap_buffer_bcnt = 0;
|
ctap_buffer_bcnt = 0;
|
||||||
ctap_buffer_offset = 0;
|
ctap_buffer_offset = 0;
|
||||||
ctap_packet_seq = 0;
|
ctap_packet_seq = 0;
|
||||||
@ -341,7 +342,7 @@ static void send_init_response(uint32_t oldcid, uint32_t newcid, uint8_t * nonce
|
|||||||
|
|
||||||
memmove(init_resp.nonce, nonce, 8);
|
memmove(init_resp.nonce, nonce, 8);
|
||||||
init_resp.cid = newcid;
|
init_resp.cid = newcid;
|
||||||
init_resp.protocol_version = 0;//?
|
init_resp.protocol_version = CTAPHID_PROTOCOL_VERSION;
|
||||||
init_resp.version_major = 0;//?
|
init_resp.version_major = 0;//?
|
||||||
init_resp.version_minor = 0;//?
|
init_resp.version_minor = 0;//?
|
||||||
init_resp.build_version = 0;//?
|
init_resp.build_version = 0;//?
|
||||||
@ -361,14 +362,32 @@ void ctaphid_check_timeouts()
|
|||||||
{
|
{
|
||||||
printf1(TAG_HID, "TIMEOUT CID: %08x\n", CIDS[i].cid);
|
printf1(TAG_HID, "TIMEOUT CID: %08x\n", CIDS[i].cid);
|
||||||
ctaphid_send_error(CIDS[i].cid, CTAP1_ERR_TIMEOUT);
|
ctaphid_send_error(CIDS[i].cid, CTAP1_ERR_TIMEOUT);
|
||||||
memset(CIDS + i, 0, sizeof(struct CID));
|
CIDS[i].busy = 0;
|
||||||
|
if (CIDS[i].cid == buffer_cid())
|
||||||
|
{
|
||||||
|
buffer_reset();
|
||||||
|
}
|
||||||
|
// memset(CIDS + i, 0, sizeof(struct CID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ctaphid_update_status(int8_t status)
|
||||||
|
{
|
||||||
|
CTAPHID_WRITE_BUFFER wb;
|
||||||
|
printf1(TAG_HID, "Send device update %d!\n",status);
|
||||||
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
|
||||||
void ctaphid_handle_packet(uint8_t * pkt_raw)
|
wb.cid = buffer_cid();
|
||||||
|
wb.cmd = CTAPHID_KEEPALIVE;
|
||||||
|
wb.bcnt = 1;
|
||||||
|
|
||||||
|
ctaphid_write(&wb, &status, 1);
|
||||||
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ctaphid_buffer_packet(uint8_t * pkt_raw, uint8_t * cmd, uint32_t * cid, int * len)
|
||||||
{
|
{
|
||||||
CTAPHID_PACKET * pkt = (CTAPHID_PACKET *)(pkt_raw);
|
CTAPHID_PACKET * pkt = (CTAPHID_PACKET *)(pkt_raw);
|
||||||
|
|
||||||
@ -378,29 +397,25 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
if (!is_cont_pkt(pkt)) printf1(TAG_HID, " length: %d\n", ctaphid_packet_len(pkt));
|
if (!is_cont_pkt(pkt)) printf1(TAG_HID, " length: %d\n", ctaphid_packet_len(pkt));
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t status;
|
|
||||||
uint32_t oldcid;
|
uint32_t oldcid;
|
||||||
uint32_t newcid;
|
uint32_t newcid;
|
||||||
static CTAPHID_WRITE_BUFFER wb;
|
|
||||||
uint32_t active_cid;
|
|
||||||
uint32_t t1,t2;
|
|
||||||
|
|
||||||
CTAP_RESPONSE ctap_resp;
|
|
||||||
|
|
||||||
|
*cid = pkt->cid;
|
||||||
|
|
||||||
if (is_init_pkt(pkt))
|
if (is_init_pkt(pkt))
|
||||||
{
|
{
|
||||||
if (ctaphid_packet_len(pkt) != 8)
|
if (ctaphid_packet_len(pkt) != 8)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR, "Error,invalid length field for init packet\n");
|
printf2(TAG_ERR, "Error,invalid length field for init packet\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
*cmd = CTAP1_ERR_INVALID_LENGTH;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
if (pkt->cid == 0)
|
if (pkt->cid == 0)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Error, invalid cid 0\n");
|
printf2(TAG_ERR,"Error, invalid cid 0\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_CHANNEL);
|
*cmd = CTAP1_ERR_INVALID_CHANNEL;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctaphid_init();
|
ctaphid_init();
|
||||||
@ -426,22 +441,30 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR, "Error, not enough memory for new CID. return BUSY.\n");
|
printf2(TAG_ERR, "Error, not enough memory for new CID. return BUSY.\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
*cmd = CTAP1_ERR_CHANNEL_BUSY;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
send_init_response(oldcid, newcid, pkt->pkt.init.payload);
|
send_init_response(oldcid, newcid, pkt->pkt.init.payload);
|
||||||
cid_del(newcid);
|
cid_del(newcid);
|
||||||
|
|
||||||
return;
|
return HID_IGNORE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check if matches existing CID
|
|
||||||
if (pkt->cid == CTAPHID_BROADCAST_CID)
|
if (pkt->cid == CTAPHID_BROADCAST_CID)
|
||||||
{
|
{
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_CHANNEL);
|
*cmd = CTAP1_ERR_INVALID_CHANNEL;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! cid_exists(pkt->cid) && ! is_cont_pkt(pkt))
|
||||||
|
{
|
||||||
|
if (buffer_status() == EMPTY)
|
||||||
|
{
|
||||||
|
add_cid(pkt->cid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cid_exists(pkt->cid))
|
if (cid_exists(pkt->cid))
|
||||||
{
|
{
|
||||||
if (buffer_status() == BUFFERING)
|
if (buffer_status() == BUFFERING)
|
||||||
@ -450,14 +473,22 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
{
|
{
|
||||||
printf2(TAG_ERR,"INVALID_SEQ\n");
|
printf2(TAG_ERR,"INVALID_SEQ\n");
|
||||||
printf2(TAG_ERR,"Have %d/%d bytes\n", ctap_buffer_offset, ctap_buffer_bcnt);
|
printf2(TAG_ERR,"Have %d/%d bytes\n", ctap_buffer_offset, ctap_buffer_bcnt);
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_SEQ);
|
*cmd = CTAP1_ERR_INVALID_SEQ;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
else if (pkt->cid != buffer_cid())
|
else if (pkt->cid != buffer_cid())
|
||||||
|
{
|
||||||
|
if (! is_cont_pkt(pkt))
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"BUSY with %08x\n", buffer_cid());
|
printf2(TAG_ERR,"BUSY with %08x\n", buffer_cid());
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
*cmd = CTAP1_ERR_CHANNEL_BUSY;
|
||||||
return;
|
return HID_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"ignoring random cont packet from %04x\n",pkt->cid);
|
||||||
|
return HID_IGNORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! is_cont_pkt(pkt))
|
if (! is_cont_pkt(pkt))
|
||||||
@ -465,23 +496,24 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
|
|
||||||
if (ctaphid_packet_len(pkt) > CTAPHID_BUFFER_SIZE)
|
if (ctaphid_packet_len(pkt) > CTAPHID_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
*cmd = CTAP1_ERR_INVALID_LENGTH;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (buffer_status() == EMPTY || pkt->cid != buffer_cid())
|
if (buffer_status() == EMPTY || pkt->cid != buffer_cid())
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"ignoring random cont packet\n");
|
printf2(TAG_ERR,"ignoring random cont packet from %04x\n",pkt->cid);
|
||||||
return;
|
return HID_IGNORE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer_packet(pkt) == SEQUENCE_ERROR)
|
if (buffer_packet(pkt) == SEQUENCE_ERROR)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Buffering sequence error\n");
|
printf2(TAG_ERR,"Buffering sequence error\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_SEQ);
|
*cmd = CTAP1_ERR_INVALID_SEQ;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
ret = cid_refresh(pkt->cid);
|
ret = cid_refresh(pkt->cid);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@ -489,35 +521,66 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
printf2(TAG_ERR,"Error, refresh cid failed\n");
|
printf2(TAG_ERR,"Error, refresh cid failed\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
active_cid = pkt->cid;
|
|
||||||
}
|
}
|
||||||
else if (is_cont_pkt(pkt))
|
else if (is_cont_pkt(pkt))
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"ignoring unwarranted cont packet\n");
|
printf2(TAG_ERR,"ignoring unwarranted cont packet\n");
|
||||||
|
|
||||||
// Ignore
|
// Ignore
|
||||||
return;
|
return HID_IGNORE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"BUSY\n");
|
printf2(TAG_ERR,"BUSY\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
*cmd = CTAP1_ERR_CHANNEL_BUSY;
|
||||||
return;
|
return HID_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*len = buffer_len();
|
||||||
|
*cmd = buffer_cmd();
|
||||||
|
return buffer_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||||
switch(buffer_status())
|
|
||||||
{
|
{
|
||||||
case BUFFERING:
|
uint8_t cmd;
|
||||||
printf1(TAG_HID,"BUFFERING\n");
|
uint32_t cid;
|
||||||
active_cid_timestamp = millis();
|
int len;
|
||||||
break;
|
int status;
|
||||||
|
|
||||||
case EMPTY:
|
static uint8_t is_busy = 0;
|
||||||
printf1(TAG_HID,"empty buffer!\n");
|
static CTAPHID_WRITE_BUFFER wb;
|
||||||
case BUFFERED:
|
CTAP_RESPONSE ctap_resp;
|
||||||
switch(buffer_cmd())
|
|
||||||
|
uint32_t t1,t2;
|
||||||
|
|
||||||
|
int bufstatus = ctaphid_buffer_packet(pkt_raw, &cmd, &cid, &len);
|
||||||
|
|
||||||
|
if (bufstatus == HID_IGNORE)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufstatus == HID_ERROR)
|
||||||
|
{
|
||||||
|
cid_del(cid);
|
||||||
|
if (cmd == CTAP1_ERR_INVALID_SEQ)
|
||||||
|
{
|
||||||
|
buffer_reset();
|
||||||
|
}
|
||||||
|
ctaphid_send_error(cid, cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufstatus == BUFFERING)
|
||||||
|
{
|
||||||
|
active_cid_timestamp = millis();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch(cmd)
|
||||||
{
|
{
|
||||||
|
|
||||||
case CTAPHID_INIT:
|
case CTAPHID_INIT:
|
||||||
@ -529,11 +592,11 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
printf1(TAG_HID,"CTAPHID_PING\n");
|
printf1(TAG_HID,"CTAPHID_PING\n");
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
ctaphid_write_buffer_init(&wb);
|
||||||
wb.cid = active_cid;
|
wb.cid = cid;
|
||||||
wb.cmd = CTAPHID_PING;
|
wb.cmd = CTAPHID_PING;
|
||||||
wb.bcnt = buffer_len();
|
wb.bcnt = len;
|
||||||
t1 = millis();
|
t1 = millis();
|
||||||
ctaphid_write(&wb, ctap_buffer, buffer_len());
|
ctaphid_write(&wb, ctap_buffer, len);
|
||||||
ctaphid_write(&wb, NULL,0);
|
ctaphid_write(&wb, NULL,0);
|
||||||
t2 = millis();
|
t2 = millis();
|
||||||
printf1(TAG_TIME,"PING writeback: %d ms\n",(uint32_t)(t2-t1));
|
printf1(TAG_TIME,"PING writeback: %d ms\n",(uint32_t)(t2-t1));
|
||||||
@ -545,7 +608,7 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
ctaphid_write_buffer_init(&wb);
|
||||||
|
|
||||||
wb.cid = active_cid;
|
wb.cid = cid;
|
||||||
wb.cmd = CTAPHID_WINK;
|
wb.cmd = CTAPHID_WINK;
|
||||||
|
|
||||||
ctaphid_write(&wb,NULL,0);
|
ctaphid_write(&wb,NULL,0);
|
||||||
@ -555,18 +618,25 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
#ifndef DISABLE_CTAPHID_CBOR
|
#ifndef DISABLE_CTAPHID_CBOR
|
||||||
case CTAPHID_CBOR:
|
case CTAPHID_CBOR:
|
||||||
printf1(TAG_HID,"CTAPHID_CBOR\n");
|
printf1(TAG_HID,"CTAPHID_CBOR\n");
|
||||||
if (buffer_len() == 0)
|
|
||||||
|
if (len == 0)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Error,invalid 0 length field for cbor packet\n");
|
printf2(TAG_ERR,"Error,invalid 0 length field for cbor packet\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
ctaphid_send_error(cid, CTAP1_ERR_INVALID_LENGTH);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (is_busy)
|
||||||
|
{
|
||||||
|
printf1(TAG_HID,"Channel busy for CBOR\n");
|
||||||
|
ctaphid_send_error(cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
is_busy = 1;
|
||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
status = ctap_request(ctap_buffer, buffer_len(), &ctap_resp);
|
status = ctap_request(ctap_buffer, len, &ctap_resp);
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
ctaphid_write_buffer_init(&wb);
|
||||||
wb.cid = active_cid;
|
wb.cid = cid;
|
||||||
wb.cmd = CTAPHID_CBOR;
|
wb.cmd = CTAPHID_CBOR;
|
||||||
wb.bcnt = (ctap_resp.length+1);
|
wb.bcnt = (ctap_resp.length+1);
|
||||||
|
|
||||||
@ -577,45 +647,51 @@ void ctaphid_handle_packet(uint8_t * pkt_raw)
|
|||||||
ctaphid_write(&wb, NULL, 0);
|
ctaphid_write(&wb, NULL, 0);
|
||||||
t2 = millis();
|
t2 = millis();
|
||||||
printf1(TAG_TIME,"CBOR writeback: %d ms\n",(uint32_t)(t2-t1));
|
printf1(TAG_TIME,"CBOR writeback: %d ms\n",(uint32_t)(t2-t1));
|
||||||
|
is_busy = 0;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case CTAPHID_MSG:
|
case CTAPHID_MSG:
|
||||||
|
|
||||||
printf1(TAG_HID,"CTAPHID_MSG\n");
|
printf1(TAG_HID,"CTAPHID_MSG\n");
|
||||||
if (buffer_len() == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"Error,invalid 0 length field for MSG/U2F packet\n");
|
printf2(TAG_ERR,"Error,invalid 0 length field for MSG/U2F packet\n");
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
ctaphid_send_error(cid, CTAP1_ERR_INVALID_LENGTH);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (is_busy)
|
||||||
|
{
|
||||||
|
printf1(TAG_HID,"Channel busy for MSG\n");
|
||||||
|
ctaphid_send_error(cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
is_busy = 1;
|
||||||
ctap_response_init(&ctap_resp);
|
ctap_response_init(&ctap_resp);
|
||||||
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
||||||
|
|
||||||
ctaphid_write_buffer_init(&wb);
|
ctaphid_write_buffer_init(&wb);
|
||||||
wb.cid = active_cid;
|
wb.cid = cid;
|
||||||
wb.cmd = CTAPHID_MSG;
|
wb.cmd = CTAPHID_MSG;
|
||||||
wb.bcnt = (ctap_resp.length);
|
wb.bcnt = (ctap_resp.length);
|
||||||
|
|
||||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||||
ctaphid_write(&wb, NULL, 0);
|
ctaphid_write(&wb, NULL, 0);
|
||||||
|
is_busy = 0;
|
||||||
|
break;
|
||||||
|
case CTAPHID_CANCEL:
|
||||||
|
printf1(TAG_HID,"CTAPHID_CANCEL\n");
|
||||||
|
is_busy = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_COMMAND);
|
ctaphid_send_error(cid, CTAP1_ERR_INVALID_COMMAND);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cid_del(buffer_cid());
|
cid_del(cid);
|
||||||
buffer_reset();
|
buffer_reset();
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf2(TAG_ERR,"invalid buffer state; abort\n");
|
|
||||||
exit(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf1(TAG_HID,"\n");
|
printf1(TAG_HID,"\n");
|
||||||
|
if (!is_busy) return cmd;
|
||||||
|
else return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#define CTAPHID_CBOR (TYPE_INIT | 0x10)
|
#define CTAPHID_CBOR (TYPE_INIT | 0x10)
|
||||||
#define CTAPHID_CANCEL (TYPE_INIT | 0x11)
|
#define CTAPHID_CANCEL (TYPE_INIT | 0x11)
|
||||||
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
||||||
|
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b)
|
||||||
|
|
||||||
#define ERR_INVALID_CMD 0x01
|
#define ERR_INVALID_CMD 0x01
|
||||||
#define ERR_INVALID_PAR 0x02
|
#define ERR_INVALID_PAR 0x02
|
||||||
@ -43,6 +44,11 @@
|
|||||||
#define ERR_MSG_TIMEOUT 0x05
|
#define ERR_MSG_TIMEOUT 0x05
|
||||||
#define ERR_CHANNEL_BUSY 0x06
|
#define ERR_CHANNEL_BUSY 0x06
|
||||||
|
|
||||||
|
#define CTAPHID_PROTOCOL_VERSION 2
|
||||||
|
|
||||||
|
#define CTAPHID_STATUS_IDLE 0
|
||||||
|
#define CTAPHID_STATUS_PROCESSING 1
|
||||||
|
#define CTAPHID_STATUS_UPNEEDED 2
|
||||||
|
|
||||||
#define CTAPHID_INIT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-7)
|
#define CTAPHID_INIT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-7)
|
||||||
#define CTAPHID_CONT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-5)
|
#define CTAPHID_CONT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-5)
|
||||||
@ -91,10 +97,12 @@ typedef struct
|
|||||||
|
|
||||||
void ctaphid_init();
|
void ctaphid_init();
|
||||||
|
|
||||||
void ctaphid_handle_packet(uint8_t * pkt_raw);
|
uint8_t ctaphid_handle_packet(uint8_t * pkt_raw);
|
||||||
|
|
||||||
void ctaphid_check_timeouts();
|
void ctaphid_check_timeouts();
|
||||||
|
|
||||||
|
void ctaphid_update_status(int8_t status);
|
||||||
|
|
||||||
|
|
||||||
#define ctaphid_packet_len(pkt) ((uint16_t)((pkt)->pkt.init.bcnth << 8) | ((pkt)->pkt.init.bcntl))
|
#define ctaphid_packet_len(pkt) ((uint16_t)((pkt)->pkt.init.bcnth << 8) | ((pkt)->pkt.init.bcntl))
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ void device_init();
|
|||||||
|
|
||||||
uint32_t millis();
|
uint32_t millis();
|
||||||
|
|
||||||
|
void delay(uint32_t ms);
|
||||||
|
|
||||||
// HID message size in bytes
|
// HID message size in bytes
|
||||||
#define HID_MESSAGE_SIZE 64
|
#define HID_MESSAGE_SIZE 64
|
||||||
|
|
||||||
@ -53,9 +55,15 @@ int authenticator_is_backup_initialized();
|
|||||||
|
|
||||||
void authenticator_write_state(AuthenticatorState *, int backup);
|
void authenticator_write_state(AuthenticatorState *, int backup);
|
||||||
|
|
||||||
|
// Called each main loop. Doesn't need to do anything.
|
||||||
|
void device_manage();
|
||||||
|
|
||||||
|
// sets status that's uses for sending status updates ~100ms.
|
||||||
|
// A timer should be set up to call `ctaphid_update_status`
|
||||||
|
void device_set_status(int status);
|
||||||
|
|
||||||
// Test for user presence
|
// Test for user presence
|
||||||
// Return 1 for user is present, 0 user not present
|
// Return 1 for user is present, 0 user not present, -1 if cancel is requested.
|
||||||
extern int ctap_user_presence_test();
|
extern int ctap_user_presence_test();
|
||||||
|
|
||||||
// Generate @num bytes of random numbers to @dest
|
// Generate @num bytes of random numbers to @dest
|
||||||
|
39
fido2/main.c
39
fido2/main.c
@ -36,29 +36,25 @@
|
|||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
int count = 0;
|
|
||||||
uint32_t t1 = 0;
|
|
||||||
uint32_t t2 = 0;
|
|
||||||
uint32_t accum = 0;
|
|
||||||
uint32_t dt = 0;
|
|
||||||
uint8_t hidmsg[64];
|
uint8_t hidmsg[64];
|
||||||
|
uint32_t t1 = 0;
|
||||||
|
|
||||||
set_logging_mask(
|
set_logging_mask(
|
||||||
/*0*/
|
/*0*/
|
||||||
TAG_GEN|
|
// TAG_GEN|
|
||||||
/*TAG_MC |*/
|
// TAG_MC |
|
||||||
/*TAG_GA |*/
|
// TAG_GA |
|
||||||
TAG_WALLET |
|
// TAG_WALLET |
|
||||||
TAG_STOR |
|
TAG_STOR |
|
||||||
/*TAG_CP |*/
|
// TAG_CP |
|
||||||
TAG_CTAP|
|
// TAG_CTAP|
|
||||||
// TAG_HID|
|
// TAG_HID|
|
||||||
/*TAG_U2F|*/
|
/*TAG_U2F|*/
|
||||||
/*TAG_PARSE |*/
|
// TAG_PARSE |
|
||||||
// TAG_TIME|
|
// TAG_TIME|
|
||||||
/*TAG_DUMP|*/
|
// TAG_DUMP|
|
||||||
/*TAG_GREEN|*/
|
TAG_GREEN|
|
||||||
/*TAG_RED|*/
|
TAG_RED|
|
||||||
TAG_ERR
|
TAG_ERR
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -85,30 +81,23 @@ int main(int argc, char * argv[])
|
|||||||
t1 = millis();
|
t1 = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_manage();
|
||||||
|
|
||||||
if (usbhid_recv(hidmsg) > 0)
|
if (usbhid_recv(hidmsg) > 0)
|
||||||
{
|
{
|
||||||
printf1(TAG_DUMP,"%d>> ",count++); dump_hex1(TAG_DUMP, hidmsg,sizeof(hidmsg));
|
|
||||||
t2 = millis();
|
|
||||||
ctaphid_handle_packet(hidmsg);
|
ctaphid_handle_packet(hidmsg);
|
||||||
accum += millis() - t2;
|
|
||||||
printf1(TAG_TIME,"accum: %d\n", (uint32_t)accum);
|
|
||||||
printf1(TAG_TIME,"dt: %d\n", t2 - dt);
|
|
||||||
dt = t2;
|
|
||||||
memset(hidmsg, 0, sizeof(hidmsg));
|
memset(hidmsg, 0, sizeof(hidmsg));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*main_loop_delay();*/
|
|
||||||
}
|
}
|
||||||
ctaphid_check_timeouts();
|
ctaphid_check_timeouts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should never get here
|
// Should never get here
|
||||||
usbhid_close();
|
usbhid_close();
|
||||||
printf("done\n");
|
printf1(TAG_GREEN, "done\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,8 +39,9 @@ typedef struct
|
|||||||
// Pin information
|
// Pin information
|
||||||
uint8_t is_initialized;
|
uint8_t is_initialized;
|
||||||
uint8_t is_pin_set;
|
uint8_t is_pin_set;
|
||||||
uint8_t pin_code[NEW_PIN_ENC_MAX_SIZE];
|
uint8_t pin_code[NEW_PIN_ENC_MIN_SIZE];
|
||||||
uint8_t remaining_tries;
|
int pin_code_length;
|
||||||
|
int8_t remaining_tries;
|
||||||
|
|
||||||
uint16_t key_lens[MAX_KEYS];
|
uint16_t key_lens[MAX_KEYS];
|
||||||
uint8_t key_space[KEY_SPACE_BYTES];
|
uint8_t key_space[KEY_SPACE_BYTES];
|
||||||
|
@ -124,7 +124,7 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
// Should never get here
|
// Should never get here
|
||||||
usbhid_close();
|
usbhid_close();
|
||||||
printf("done\n");
|
printf1(TAG_GREEN, "done\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ nav:
|
|||||||
- FIDO2 Implementation: fido2-impl.md
|
- FIDO2 Implementation: fido2-impl.md
|
||||||
- Signed update process: signed-updates.md
|
- Signed update process: signed-updates.md
|
||||||
- Building: building.md
|
- Building: building.md
|
||||||
|
- Code documentation: code-overview.md
|
||||||
- Contributing Code: contributing.md
|
- Contributing Code: contributing.md
|
||||||
- Contributing Docs: documenting.md
|
- Contributing Docs: documenting.md
|
||||||
- What the udev?!: udev.md
|
- What the udev?!: udev.md
|
||||||
|
2
pc/app.h
2
pc/app.h
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#define DEBUG_LEVEL 1
|
#define DEBUG_LEVEL 1
|
||||||
|
|
||||||
|
#define ENABLE_U2F
|
||||||
|
|
||||||
//#define BRIDGE_TO_WALLET
|
//#define BRIDGE_TO_WALLET
|
||||||
|
|
||||||
void printing_init();
|
void printing_init();
|
||||||
|
26
pc/device.c
26
pc/device.c
@ -8,6 +8,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "cbor.h"
|
#include "cbor.h"
|
||||||
@ -136,13 +137,20 @@ void usbhid_close()
|
|||||||
udp_close(serverfd);
|
udp_close(serverfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void int_handler(int i)
|
||||||
|
{
|
||||||
|
usbhid_close();
|
||||||
|
printf("SIGINT... exiting.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
void device_init()
|
void device_init()
|
||||||
{
|
{
|
||||||
|
signal(SIGINT, int_handler);
|
||||||
|
|
||||||
usbhid_init();
|
usbhid_init();
|
||||||
|
|
||||||
authenticator_initialize();
|
authenticator_initialize();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -181,7 +189,6 @@ int ctap_user_verification(uint8_t arg)
|
|||||||
uint32_t ctap_atomic_count(int sel)
|
uint32_t ctap_atomic_count(int sel)
|
||||||
{
|
{
|
||||||
static uint32_t counter1 = 25;
|
static uint32_t counter1 = 25;
|
||||||
static uint32_t counter2 = 25;
|
|
||||||
/*return 713;*/
|
/*return 713;*/
|
||||||
if (sel == 0)
|
if (sel == 0)
|
||||||
{
|
{
|
||||||
@ -197,15 +204,21 @@ uint32_t ctap_atomic_count(int sel)
|
|||||||
|
|
||||||
int ctap_generate_rng(uint8_t * dst, size_t num)
|
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
FILE * urand = fopen("/dev/urandom","r");
|
FILE * urand = fopen("/dev/urandom","r");
|
||||||
if (urand == NULL)
|
if (urand == NULL)
|
||||||
{
|
{
|
||||||
perror("fopen");
|
perror("fopen");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fread(dst, 1, num, urand);
|
ret = fread(dst, 1, num, urand);
|
||||||
fclose(urand);
|
fclose(urand);
|
||||||
|
|
||||||
|
if (ret != num)
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
/*memset(dst,0xaa,num);*/
|
/*memset(dst,0xaa,num);*/
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -305,7 +318,6 @@ int authenticator_is_backup_initialized()
|
|||||||
AuthenticatorState * state = (AuthenticatorState*) header;
|
AuthenticatorState * state = (AuthenticatorState*) header;
|
||||||
FILE * f;
|
FILE * f;
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t * mem;
|
|
||||||
|
|
||||||
printf("state file exists\n");
|
printf("state file exists\n");
|
||||||
f = fopen(backup_file, "rb");
|
f = fopen(backup_file, "rb");
|
||||||
@ -398,7 +410,7 @@ void authenticator_initialize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void manage_device()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,16 +1,32 @@
|
|||||||
CC=arm-none-eabi-gcc
|
CC=arm-none-eabi-gcc
|
||||||
CP=arm-none-eabi-objcopy
|
CP=arm-none-eabi-objcopy
|
||||||
SZ=arm-none-eabi-size
|
SZ=arm-none-eabi-size
|
||||||
|
AR=arm-none-eabi-ar
|
||||||
|
|
||||||
|
# ST related
|
||||||
SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
SRC = src/main.c src/init.c src/redirect.c src/flash.c src/rng.c src/led.c src/device.c
|
||||||
SRC += src/fifo.c
|
SRC += src/fifo.c src/crypto.c src/attestation.c
|
||||||
SRC += ../../fido2/util.c
|
|
||||||
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
|
||||||
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c)
|
SRC += $(wildcard lib/*.c) $(wildcard lib/usbd/*.c)
|
||||||
|
|
||||||
|
# FIDO2 lib
|
||||||
|
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.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
|
||||||
|
|
||||||
|
# Crypto libs
|
||||||
|
SRC += ../../crypto/sha256/sha256.c ../../crypto/micro-ecc/uECC.c ../../crypto/tiny-AES-c/aes.c
|
||||||
|
|
||||||
|
|
||||||
OBJ1=$(SRC:.c=.o)
|
OBJ1=$(SRC:.c=.o)
|
||||||
OBJ=$(OBJ1:.s=.o)
|
OBJ=$(OBJ1:.s=.o)
|
||||||
INC=-Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/
|
|
||||||
|
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../../fido2/extensions
|
||||||
|
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
|
||||||
|
INC += -I../../crypto/tiny-AES-c
|
||||||
|
|
||||||
|
SEARCH=-L../../tinycbor/lib
|
||||||
|
|
||||||
LDSCRIPT=stm32l432xx.ld
|
LDSCRIPT=stm32l432xx.ld
|
||||||
|
|
||||||
CFLAGS= $(INC)
|
CFLAGS= $(INC)
|
||||||
@ -23,8 +39,13 @@ HW=-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
|
|||||||
# Solo
|
# Solo
|
||||||
CHIP=STM32L442xx
|
CHIP=STM32L442xx
|
||||||
|
|
||||||
CFLAGS=$(INC) -c -D$(CHIP) -DUSE_FULL_LL_DRIVER -Os -Wall -fdata-sections -ffunction-sections
|
DEFINES = -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER
|
||||||
LDFLAGS=$(HW) -specs=nano.specs -specs=nosys.specs -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,--gc-sections -u _printf_float
|
# DEFINES += -DTEST_SOLO_STM32 -DTEST -DTEST_FIFO=1
|
||||||
|
|
||||||
|
CFLAGS=$(INC) -c $(DEFINES) -Wall -fdata-sections -ffunction-sections $(HW)
|
||||||
|
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -u _printf_float -lnosys
|
||||||
|
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -ltinycbor
|
||||||
|
|
||||||
|
|
||||||
.PRECIOUS: %.o
|
.PRECIOUS: %.o
|
||||||
|
|
||||||
@ -32,11 +53,13 @@ all: $(TARGET).elf
|
|||||||
$(SZ) $^
|
$(SZ) $^
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $^ $(HW) $(CFLAGS) -o $@
|
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
|
||||||
|
|
||||||
|
../../crypto/micro-ecc/uECC.o: ../../crypto/micro-ecc/uECC.c
|
||||||
|
$(CC) $^ $(HW) -O3 $(CFLAGS) -o $@
|
||||||
|
|
||||||
%.o: %.s
|
%.o: %.s
|
||||||
$(CC) $^ $(HW) $(CFLAGS) -o $@
|
$(CC) $^ $(HW) -Os $(CFLAGS) -o $@
|
||||||
|
|
||||||
%.elf: $(OBJ)
|
%.elf: $(OBJ)
|
||||||
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
$(CC) $^ $(HW) $(LDFLAGS) -o $@
|
||||||
@ -48,16 +71,14 @@ clean:
|
|||||||
rm -f *.o src/*.o src/*.elf *.elf *.hex $(OBJ)
|
rm -f *.o src/*.o src/*.elf *.elf *.hex $(OBJ)
|
||||||
|
|
||||||
flash: $(TARGET).hex
|
flash: $(TARGET).hex
|
||||||
|
STM32_Programmer_CLI -c port=SWD -halt -e all --readunprotect
|
||||||
STM32_Programmer_CLI -c port=SWD -halt -d $(TARGET).hex -rst
|
STM32_Programmer_CLI -c port=SWD -halt -d $(TARGET).hex -rst
|
||||||
sleep 0.5
|
|
||||||
python dfuse-tool/dfuse-tool.py --leave
|
|
||||||
|
|
||||||
test:
|
detach:
|
||||||
STM32_Programmer_CLI -c port=SWD -halt -d ../../../cube_stm32l442/build/cube_stm32l442.hex -rst
|
STM32_Programmer_CLI -c port=usb1 -ob nBOOT0=1
|
||||||
sleep 0.5
|
|
||||||
python dfuse-tool/dfuse-tool.py --leave
|
|
||||||
|
|
||||||
test2:
|
cbor:
|
||||||
STM32_Programmer_CLI -c port=SWD -halt -d ../../../stmusb2/build/stmusb2.hex -rst
|
cd ../../tinycbor/ && make clean
|
||||||
sleep 0.5
|
cd ../../tinycbor/ && make CC="$(CC)" AR=$(AR) \
|
||||||
python dfuse-tool/dfuse-tool.py --leave
|
LDFLAGS="$(LDFLAGS_LIB)" \
|
||||||
|
CFLAGS="$(CFLAGS)"
|
||||||
|
@ -1,707 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file usbd_hid.c
|
|
||||||
* @author MCD Application Team
|
|
||||||
* @brief This file provides the HID core functions.
|
|
||||||
*
|
|
||||||
* @verbatim
|
|
||||||
*
|
|
||||||
* ===================================================================
|
|
||||||
* HID Class Description
|
|
||||||
* ===================================================================
|
|
||||||
* This module manages the HID class V1.11 following the "Device Class Definition
|
|
||||||
* for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
|
|
||||||
* This driver implements the following aspects of the specification:
|
|
||||||
* - The Boot Interface Subclass
|
|
||||||
* - The Mouse protocol
|
|
||||||
* - Usage Page : Generic Desktop
|
|
||||||
* - Usage : Joystick
|
|
||||||
* - Collection : Application
|
|
||||||
*
|
|
||||||
* @note In HS mode and when the DMA is used, all variables and data structures
|
|
||||||
* dealing with the DMA during the transaction process should be 32-bit aligned.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @endverbatim
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted, provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistribution of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
|
||||||
* contributors to this software may be used to endorse or promote products
|
|
||||||
* derived from this software without specific written permission.
|
|
||||||
* 4. This software, including modifications and/or derivative works of this
|
|
||||||
* software, must execute solely and exclusively on microcontroller or
|
|
||||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
|
||||||
* 5. Redistribution and use of this software other than as permitted under
|
|
||||||
* this license is void and will automatically terminate your rights under
|
|
||||||
* this license.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
|
||||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
|
||||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* BSPDependencies
|
|
||||||
- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
|
|
||||||
- "stm32xxxxx_{eval}{discovery}_io.c"
|
|
||||||
EndBSPDependencies */
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "usbd_hid.h"
|
|
||||||
#include "usbd_ctlreq.h"
|
|
||||||
|
|
||||||
|
|
||||||
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID
|
|
||||||
* @brief usbd core module
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_TypesDefinitions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Defines
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Macros
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_FunctionPrototypes
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetFSCfgDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetHSCfgDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetOtherSpeedCfgDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Variables
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
USBD_ClassTypeDef USBD_HID =
|
|
||||||
{
|
|
||||||
USBD_HID_Init,
|
|
||||||
USBD_HID_DeInit,
|
|
||||||
USBD_HID_Setup,
|
|
||||||
NULL, /*EP0_TxSent*/
|
|
||||||
NULL, /*EP0_RxReady*/
|
|
||||||
USBD_HID_DataIn, /*DataIn*/
|
|
||||||
NULL, /*DataOut*/
|
|
||||||
NULL, /*SOF */
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
USBD_HID_GetHSCfgDesc,
|
|
||||||
USBD_HID_GetFSCfgDesc,
|
|
||||||
USBD_HID_GetOtherSpeedCfgDesc,
|
|
||||||
USBD_HID_GetDeviceQualifierDesc,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB HID device FS Configuration Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
|
|
||||||
{
|
|
||||||
0x09, /* bLength: Configuration Descriptor size */
|
|
||||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
||||||
USB_HID_CONFIG_DESC_SIZ,
|
|
||||||
/* wTotalLength: Bytes returned */
|
|
||||||
0x00,
|
|
||||||
0x01, /*bNumInterfaces: 1 interface*/
|
|
||||||
0x01, /*bConfigurationValue: Configuration value*/
|
|
||||||
0x00, /*iConfiguration: Index of string descriptor describing
|
|
||||||
the configuration*/
|
|
||||||
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
|
|
||||||
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
|
|
||||||
|
|
||||||
/************** Descriptor of Joystick Mouse interface ****************/
|
|
||||||
/* 09 */
|
|
||||||
0x09, /*bLength: Interface Descriptor size*/
|
|
||||||
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
|
||||||
0x00, /*bInterfaceNumber: Number of Interface*/
|
|
||||||
0x00, /*bAlternateSetting: Alternate setting*/
|
|
||||||
0x01, /*bNumEndpoints*/
|
|
||||||
0x03, /*bInterfaceClass: HID*/
|
|
||||||
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
|
||||||
0x02, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
|
||||||
0, /*iInterface: Index of string descriptor*/
|
|
||||||
/******************** Descriptor of Joystick Mouse HID ********************/
|
|
||||||
/* 18 */
|
|
||||||
0x09, /*bLength: HID Descriptor size*/
|
|
||||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
|
||||||
0x11, /*bcdHID: HID Class Spec release number*/
|
|
||||||
0x01,
|
|
||||||
0x00, /*bCountryCode: Hardware target country*/
|
|
||||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
|
||||||
0x22, /*bDescriptorType*/
|
|
||||||
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
|
|
||||||
0x00,
|
|
||||||
/******************** Descriptor of Mouse endpoint ********************/
|
|
||||||
/* 27 */
|
|
||||||
0x07, /*bLength: Endpoint Descriptor size*/
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
|
||||||
|
|
||||||
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
|
|
||||||
0x03, /*bmAttributes: Interrupt endpoint*/
|
|
||||||
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
|
|
||||||
0x00,
|
|
||||||
HID_FS_BINTERVAL, /*bInterval: Polling Interval */
|
|
||||||
/* 34 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB HID device HS Configuration Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_CfgHSDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
|
|
||||||
{
|
|
||||||
0x09, /* bLength: Configuration Descriptor size */
|
|
||||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
||||||
USB_HID_CONFIG_DESC_SIZ,
|
|
||||||
/* wTotalLength: Bytes returned */
|
|
||||||
0x00,
|
|
||||||
0x01, /*bNumInterfaces: 1 interface*/
|
|
||||||
0x01, /*bConfigurationValue: Configuration value*/
|
|
||||||
0x00, /*iConfiguration: Index of string descriptor describing
|
|
||||||
the configuration*/
|
|
||||||
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
|
|
||||||
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
|
|
||||||
|
|
||||||
/************** Descriptor of Joystick Mouse interface ****************/
|
|
||||||
/* 09 */
|
|
||||||
0x09, /*bLength: Interface Descriptor size*/
|
|
||||||
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
|
||||||
0x00, /*bInterfaceNumber: Number of Interface*/
|
|
||||||
0x00, /*bAlternateSetting: Alternate setting*/
|
|
||||||
0x01, /*bNumEndpoints*/
|
|
||||||
0x03, /*bInterfaceClass: HID*/
|
|
||||||
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
|
||||||
0x02, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
|
||||||
0, /*iInterface: Index of string descriptor*/
|
|
||||||
/******************** Descriptor of Joystick Mouse HID ********************/
|
|
||||||
/* 18 */
|
|
||||||
0x09, /*bLength: HID Descriptor size*/
|
|
||||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
|
||||||
0x11, /*bcdHID: HID Class Spec release number*/
|
|
||||||
0x01,
|
|
||||||
0x00, /*bCountryCode: Hardware target country*/
|
|
||||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
|
||||||
0x22, /*bDescriptorType*/
|
|
||||||
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
|
|
||||||
0x00,
|
|
||||||
/******************** Descriptor of Mouse endpoint ********************/
|
|
||||||
/* 27 */
|
|
||||||
0x07, /*bLength: Endpoint Descriptor size*/
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
|
||||||
|
|
||||||
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
|
|
||||||
0x03, /*bmAttributes: Interrupt endpoint*/
|
|
||||||
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
|
|
||||||
0x00,
|
|
||||||
HID_HS_BINTERVAL, /*bInterval: Polling Interval */
|
|
||||||
/* 34 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB HID device Other Speed Configuration Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_OtherSpeedCfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
|
|
||||||
{
|
|
||||||
0x09, /* bLength: Configuration Descriptor size */
|
|
||||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
||||||
USB_HID_CONFIG_DESC_SIZ,
|
|
||||||
/* wTotalLength: Bytes returned */
|
|
||||||
0x00,
|
|
||||||
0x01, /*bNumInterfaces: 1 interface*/
|
|
||||||
0x01, /*bConfigurationValue: Configuration value*/
|
|
||||||
0x00, /*iConfiguration: Index of string descriptor describing
|
|
||||||
the configuration*/
|
|
||||||
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
|
|
||||||
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
|
|
||||||
|
|
||||||
/************** Descriptor of Joystick Mouse interface ****************/
|
|
||||||
/* 09 */
|
|
||||||
0x09, /*bLength: Interface Descriptor size*/
|
|
||||||
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
|
||||||
0x00, /*bInterfaceNumber: Number of Interface*/
|
|
||||||
0x00, /*bAlternateSetting: Alternate setting*/
|
|
||||||
0x01, /*bNumEndpoints*/
|
|
||||||
0x03, /*bInterfaceClass: HID*/
|
|
||||||
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
|
||||||
0x02, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
|
||||||
0, /*iInterface: Index of string descriptor*/
|
|
||||||
/******************** Descriptor of Joystick Mouse HID ********************/
|
|
||||||
/* 18 */
|
|
||||||
0x09, /*bLength: HID Descriptor size*/
|
|
||||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
|
||||||
0x11, /*bcdHID: HID Class Spec release number*/
|
|
||||||
0x01,
|
|
||||||
0x00, /*bCountryCode: Hardware target country*/
|
|
||||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
|
||||||
0x22, /*bDescriptorType*/
|
|
||||||
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
|
|
||||||
0x00,
|
|
||||||
/******************** Descriptor of Mouse endpoint ********************/
|
|
||||||
/* 27 */
|
|
||||||
0x07, /*bLength: Endpoint Descriptor size*/
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
|
||||||
|
|
||||||
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
|
|
||||||
0x03, /*bmAttributes: Interrupt endpoint*/
|
|
||||||
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
|
|
||||||
0x00,
|
|
||||||
HID_FS_BINTERVAL, /*bInterval: Polling Interval */
|
|
||||||
/* 34 */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* USB HID device Configuration Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END =
|
|
||||||
{
|
|
||||||
/* 18 */
|
|
||||||
0x09, /*bLength: HID Descriptor size*/
|
|
||||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
|
||||||
0x11, /*bcdHID: HID Class Spec release number*/
|
|
||||||
0x01,
|
|
||||||
0x00, /*bCountryCode: Hardware target country*/
|
|
||||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
|
||||||
0x22, /*bDescriptorType*/
|
|
||||||
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
|
|
||||||
0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB Standard Device Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
||||||
{
|
|
||||||
USB_LEN_DEV_QUALIFIER_DESC,
|
|
||||||
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x40,
|
|
||||||
0x01,
|
|
||||||
0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
|
|
||||||
{
|
|
||||||
0x05, 0x01,
|
|
||||||
0x09, 0x02,
|
|
||||||
0xA1, 0x01,
|
|
||||||
0x09, 0x01,
|
|
||||||
|
|
||||||
0xA1, 0x00,
|
|
||||||
0x05, 0x09,
|
|
||||||
0x19, 0x01,
|
|
||||||
0x29, 0x03,
|
|
||||||
|
|
||||||
0x15, 0x00,
|
|
||||||
0x25, 0x01,
|
|
||||||
0x95, 0x03,
|
|
||||||
0x75, 0x01,
|
|
||||||
|
|
||||||
0x81, 0x02,
|
|
||||||
0x95, 0x01,
|
|
||||||
0x75, 0x05,
|
|
||||||
0x81, 0x01,
|
|
||||||
|
|
||||||
0x05, 0x01,
|
|
||||||
0x09, 0x30,
|
|
||||||
0x09, 0x31,
|
|
||||||
0x09, 0x38,
|
|
||||||
|
|
||||||
0x15, 0x81,
|
|
||||||
0x25, 0x7F,
|
|
||||||
0x75, 0x08,
|
|
||||||
0x95, 0x03,
|
|
||||||
|
|
||||||
0x81, 0x06,
|
|
||||||
0xC0, 0x09,
|
|
||||||
0x3c, 0x05,
|
|
||||||
0xff, 0x09,
|
|
||||||
|
|
||||||
0x01, 0x15,
|
|
||||||
0x00, 0x25,
|
|
||||||
0x01, 0x75,
|
|
||||||
0x01, 0x95,
|
|
||||||
|
|
||||||
0x02, 0xb1,
|
|
||||||
0x22, 0x75,
|
|
||||||
0x06, 0x95,
|
|
||||||
0x01, 0xb1,
|
|
||||||
|
|
||||||
0x01, 0xc0
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Functions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_Init
|
|
||||||
* Initialize the HID interface
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param cfgidx: Configuration index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
/* Open EP IN */
|
|
||||||
USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE);
|
|
||||||
pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 1U;
|
|
||||||
|
|
||||||
pdev->pClassData = USBD_malloc(sizeof (USBD_HID_HandleTypeDef));
|
|
||||||
|
|
||||||
if (pdev->pClassData == NULL)
|
|
||||||
{
|
|
||||||
return USBD_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_Init
|
|
||||||
* DeInitialize the HID layer
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param cfgidx: Configuration index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
/* Close HID EPs */
|
|
||||||
USBD_LL_CloseEP(pdev, HID_EPIN_ADDR);
|
|
||||||
pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 0U;
|
|
||||||
|
|
||||||
/* FRee allocated memory */
|
|
||||||
if(pdev->pClassData != NULL)
|
|
||||||
{
|
|
||||||
USBD_free(pdev->pClassData);
|
|
||||||
pdev->pClassData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_Setup
|
|
||||||
* Handle the HID specific requests
|
|
||||||
* @param pdev: instance
|
|
||||||
* @param req: usb requests
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req)
|
|
||||||
{
|
|
||||||
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*) pdev->pClassData;
|
|
||||||
uint16_t len = 0U;
|
|
||||||
uint8_t *pbuf = NULL;
|
|
||||||
uint16_t status_info = 0U;
|
|
||||||
USBD_StatusTypeDef ret = USBD_OK;
|
|
||||||
|
|
||||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
||||||
{
|
|
||||||
case USB_REQ_TYPE_CLASS :
|
|
||||||
switch (req->bRequest)
|
|
||||||
{
|
|
||||||
case HID_REQ_SET_PROTOCOL:
|
|
||||||
hhid->Protocol = (uint8_t)(req->wValue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HID_REQ_GET_PROTOCOL:
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->Protocol, 1U);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HID_REQ_SET_IDLE:
|
|
||||||
hhid->IdleState = (uint8_t)(req->wValue >> 8);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HID_REQ_GET_IDLE:
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->IdleState, 1U);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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_DESCRIPTOR:
|
|
||||||
if(req->wValue >> 8 == HID_REPORT_DESC)
|
|
||||||
{
|
|
||||||
len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength);
|
|
||||||
pbuf = HID_MOUSE_ReportDesc;
|
|
||||||
}
|
|
||||||
else if(req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
|
|
||||||
{
|
|
||||||
pbuf = USBD_HID_Desc;
|
|
||||||
len = MIN(USB_HID_DESC_SIZ, req->wLength);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
USBD_CtlSendData (pdev, pbuf, len);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_GET_INTERFACE :
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->AltSetting, 1U);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_SET_INTERFACE :
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
hhid->AltSetting = (uint8_t)(req->wValue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_SendReport
|
|
||||||
* Send HID Report
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param buff: pointer to report
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t *report,
|
|
||||||
uint16_t len)
|
|
||||||
{
|
|
||||||
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;
|
|
||||||
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED )
|
|
||||||
{
|
|
||||||
if(hhid->state == HID_IDLE)
|
|
||||||
{
|
|
||||||
hhid->state = HID_BUSY;
|
|
||||||
USBD_LL_Transmit (pdev,
|
|
||||||
HID_EPIN_ADDR,
|
|
||||||
report,
|
|
||||||
len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetPollingInterval
|
|
||||||
* return polling interval from endpoint descriptor
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @retval polling interval
|
|
||||||
*/
|
|
||||||
uint32_t USBD_HID_GetPollingInterval (USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
uint32_t polling_interval = 0U;
|
|
||||||
|
|
||||||
/* HIGH-speed endpoints */
|
|
||||||
if(pdev->dev_speed == USBD_SPEED_HIGH)
|
|
||||||
{
|
|
||||||
/* Sets the data transfer polling interval for high speed transfers.
|
|
||||||
Values between 1..16 are allowed. Values correspond to interval
|
|
||||||
of 2 ^ (bInterval-1). This option (8 ms, corresponds to HID_HS_BINTERVAL */
|
|
||||||
polling_interval = (((1U <<(HID_HS_BINTERVAL - 1U))) / 8U);
|
|
||||||
}
|
|
||||||
else /* LOW and FULL-speed endpoints */
|
|
||||||
{
|
|
||||||
/* Sets the data transfer polling interval for low and full
|
|
||||||
speed transfers */
|
|
||||||
polling_interval = HID_FS_BINTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((uint32_t)(polling_interval));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetCfgFSDesc
|
|
||||||
* return FS configuration descriptor
|
|
||||||
* @param speed : current device speed
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetFSCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_HID_CfgFSDesc);
|
|
||||||
return USBD_HID_CfgFSDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetCfgHSDesc
|
|
||||||
* return HS configuration descriptor
|
|
||||||
* @param speed : current device speed
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetHSCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_HID_CfgHSDesc);
|
|
||||||
return USBD_HID_CfgHSDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetOtherSpeedCfgDesc
|
|
||||||
* return other speed configuration descriptor
|
|
||||||
* @param speed : current device speed
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetOtherSpeedCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_HID_OtherSpeedCfgDesc);
|
|
||||||
return USBD_HID_OtherSpeedCfgDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_DataIn
|
|
||||||
* handle data IN Stage
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param epnum: endpoint index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t epnum)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Ensure that the FIFO is empty before a new transfer, this condition could
|
|
||||||
be caused by a new transfer before the end of the previous transfer */
|
|
||||||
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief DeviceQualifierDescriptor
|
|
||||||
* return Device Qualifier descriptor
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
*length = sizeof (USBD_HID_DeviceQualifierDesc);
|
|
||||||
return USBD_HID_DeviceQualifierDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
@ -1,170 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file usbd_hid.h
|
|
||||||
* @author MCD Application Team
|
|
||||||
* @brief Header file for the usbd_hid_core.c file.
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted, provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistribution of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
|
||||||
* contributors to this software may be used to endorse or promote products
|
|
||||||
* derived from this software without specific written permission.
|
|
||||||
* 4. This software, including modifications and/or derivative works of this
|
|
||||||
* software, must execute solely and exclusively on microcontroller or
|
|
||||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
|
||||||
* 5. Redistribution and use of this software other than as permitted under
|
|
||||||
* this license is void and will automatically terminate your rights under
|
|
||||||
* this license.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
|
||||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
|
||||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
|
||||||
#ifndef __USB_HID_H
|
|
||||||
#define __USB_HID_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "usbd_ioreq.h"
|
|
||||||
|
|
||||||
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID
|
|
||||||
* @brief This file is the Header file for usbd_hid.c
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Exported_Defines
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
#define HID_EPIN_ADDR 0x81U
|
|
||||||
#define HID_EPIN_SIZE 0x04U
|
|
||||||
|
|
||||||
#define USB_HID_CONFIG_DESC_SIZ 34U
|
|
||||||
#define USB_HID_DESC_SIZ 9U
|
|
||||||
#define HID_MOUSE_REPORT_DESC_SIZE 74U
|
|
||||||
|
|
||||||
#define HID_DESCRIPTOR_TYPE 0x21U
|
|
||||||
#define HID_REPORT_DESC 0x22U
|
|
||||||
|
|
||||||
#ifndef HID_HS_BINTERVAL
|
|
||||||
#define HID_HS_BINTERVAL 0x07U
|
|
||||||
#endif /* HID_HS_BINTERVAL */
|
|
||||||
|
|
||||||
#ifndef HID_FS_BINTERVAL
|
|
||||||
#define HID_FS_BINTERVAL 0x0AU
|
|
||||||
#endif /* HID_FS_BINTERVAL */
|
|
||||||
|
|
||||||
#define HID_REQ_SET_PROTOCOL 0x0BU
|
|
||||||
#define HID_REQ_GET_PROTOCOL 0x03U
|
|
||||||
|
|
||||||
#define HID_REQ_SET_IDLE 0x0AU
|
|
||||||
#define HID_REQ_GET_IDLE 0x02U
|
|
||||||
|
|
||||||
#define HID_REQ_SET_REPORT 0x09U
|
|
||||||
#define HID_REQ_GET_REPORT 0x01U
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_CORE_Exported_TypesDefinitions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
HID_IDLE = 0,
|
|
||||||
HID_BUSY,
|
|
||||||
}
|
|
||||||
HID_StateTypeDef;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t Protocol;
|
|
||||||
uint32_t IdleState;
|
|
||||||
uint32_t AltSetting;
|
|
||||||
HID_StateTypeDef state;
|
|
||||||
}
|
|
||||||
USBD_HID_HandleTypeDef;
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_CORE_Exported_Macros
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_CORE_Exported_Variables
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern USBD_ClassTypeDef USBD_HID;
|
|
||||||
#define USBD_HID_CLASS &USBD_HID
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USB_CORE_Exported_Functions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t *report,
|
|
||||||
uint16_t len);
|
|
||||||
|
|
||||||
uint32_t USBD_HID_GetPollingInterval (USBD_HandleTypeDef *pdev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __USB_HID_H */
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
@ -64,23 +64,19 @@ PCD_HandleTypeDef hpcd;
|
|||||||
*/
|
*/
|
||||||
void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
|
void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
|
||||||
{
|
{
|
||||||
|
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN);
|
||||||
|
|
||||||
|
if(hpcd->Init.low_power_enable == 1)
|
||||||
|
{
|
||||||
|
/* Enable EXTI Line 17 for USB wakeup */
|
||||||
|
__HAL_USB_WAKEUP_EXTI_ENABLE_IT();
|
||||||
|
}
|
||||||
|
|
||||||
/*LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);*/
|
/* Set USB FS Interrupt priority */
|
||||||
// SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN);
|
NVIC_SetPriority(USB_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x0f, 0));
|
||||||
//
|
|
||||||
// if(hpcd->Init.low_power_enable == 1)
|
/* Enable USB FS Interrupt */
|
||||||
// {
|
NVIC_EnableIRQ(USB_IRQn);
|
||||||
// /* Enable EXTI Line 17 for USB wakeup */
|
|
||||||
// __HAL_USB_WAKEUP_EXTI_ENABLE_IT();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /*[> Set USB FS Interrupt priority <]*/
|
|
||||||
// /*HAL_NVIC_SetPriority(USB_IRQn, 0x0F, 0);*/
|
|
||||||
// NVIC_SetPriority(USB_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x0f, 0));
|
|
||||||
//
|
|
||||||
// /*[> Enable USB FS Interrupt <]*/
|
|
||||||
// NVIC_EnableIRQ(USB_IRQn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,35 +219,38 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
|
|||||||
USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
|
USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
LL Driver Interface (USB Device Library --> PCD)
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the Low Level portion of the Device driver.
|
* @brief Initializes the low level portion of the device driver.
|
||||||
* @param pdev: Device handle
|
* @param pdev: Device handle
|
||||||
* @retval USBD Status
|
* @retval USBD status
|
||||||
*/
|
*/
|
||||||
|
extern void _Error_Handler(char *file, int line);
|
||||||
USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
|
USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
/* Set LL Driver parameters */
|
/* Enable USB power on Pwrctrl CR2 register. */
|
||||||
hpcd.Instance = USB;
|
SET_BIT(PWR->CR2, PWR_CR2_USV);
|
||||||
hpcd.Init.dev_endpoints = 8;
|
/* Link the driver to the stack. */
|
||||||
hpcd.Init.ep0_mps = 0x40;
|
|
||||||
hpcd.Init.phy_itface = PCD_PHY_EMBEDDED;
|
|
||||||
hpcd.Init.speed = PCD_SPEED_FULL;
|
|
||||||
hpcd.Init.low_power_enable = 1;
|
|
||||||
/* Link The driver to the stack */
|
|
||||||
hpcd.pData = pdev;
|
hpcd.pData = pdev;
|
||||||
pdev->pData = &hpcd;
|
pdev->pData = &hpcd;
|
||||||
|
|
||||||
/* Initialize LL Driver */
|
hpcd.Instance = USB;
|
||||||
HAL_PCD_Init(&hpcd);
|
hpcd.Init.dev_endpoints = 8;
|
||||||
|
hpcd.Init.speed = PCD_SPEED_FULL;
|
||||||
HAL_PCDEx_PMAConfig(&hpcd , 0x00 , PCD_SNG_BUF, 0x18);
|
hpcd.Init.ep0_mps = DEP0CTL_MPS_64;
|
||||||
HAL_PCDEx_PMAConfig(&hpcd , 0x80 , PCD_SNG_BUF, 0x58);
|
hpcd.Init.phy_itface = PCD_PHY_EMBEDDED;
|
||||||
HAL_PCDEx_PMAConfig(&hpcd , 0x81 , PCD_SNG_BUF, 0x100);
|
hpcd.Init.Sof_enable = DISABLE;
|
||||||
|
hpcd.Init.low_power_enable = DISABLE;
|
||||||
|
hpcd.Init.lpm_enable = DISABLE;
|
||||||
|
hpcd.Init.battery_charging_enable = DISABLE;
|
||||||
|
if (HAL_PCD_Init(&hpcd) != HAL_OK)
|
||||||
|
{
|
||||||
|
_Error_Handler(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
|
||||||
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
|
||||||
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x98);
|
||||||
|
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xd8);
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +95,9 @@ static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length);
|
|||||||
|
|
||||||
static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
||||||
|
|
||||||
|
static uint8_t USBD_HID_DataOut (USBD_HandleTypeDef *pdev,
|
||||||
|
uint8_t epnum);
|
||||||
|
|
||||||
|
|
||||||
USBD_ClassTypeDef USBD_HID =
|
USBD_ClassTypeDef USBD_HID =
|
||||||
{
|
{
|
||||||
@ -104,7 +107,7 @@ USBD_ClassTypeDef USBD_HID =
|
|||||||
NULL, /*EP0_TxSent*/
|
NULL, /*EP0_TxSent*/
|
||||||
NULL, /*EP0_RxReady*/
|
NULL, /*EP0_RxReady*/
|
||||||
USBD_HID_DataIn, /*DataIn*/
|
USBD_HID_DataIn, /*DataIn*/
|
||||||
NULL, /*DataOut*/
|
USBD_HID_DataOut, /*DataOut*/
|
||||||
NULL, /*SOF */
|
NULL, /*SOF */
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -223,7 +226,6 @@ __ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_FIDO_REPORT_DESC_SIZE] __
|
|||||||
0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)
|
0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)
|
||||||
0x91, 0x02, // OUTPUT (Data,Var,Abs)
|
0x91, 0x02, // OUTPUT (Data,Var,Abs)
|
||||||
|
|
||||||
|
|
||||||
0xc0,// END_COLLECTION
|
0xc0,// END_COLLECTION
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -233,12 +235,46 @@ static uint8_t hidmsg_buf[64];
|
|||||||
void usb_hid_recieve_callback(uint8_t ep)
|
void usb_hid_recieve_callback(uint8_t ep)
|
||||||
{
|
{
|
||||||
fifo_hidmsg_add(hidmsg_buf);
|
fifo_hidmsg_add(hidmsg_buf);
|
||||||
|
memset(hidmsg_buf,0,64);
|
||||||
USBD_LL_PrepareReceive(&Solo_USBD_Device,
|
USBD_LL_PrepareReceive(&Solo_USBD_Device,
|
||||||
HID_ENDPOINT,
|
HID_ENDPOINT,
|
||||||
hidmsg_buf,
|
hidmsg_buf,
|
||||||
HID_PACKET_SIZE);
|
HID_PACKET_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_pma()
|
||||||
|
{
|
||||||
|
|
||||||
|
register uint32_t _wRegBase = (uint32_t)USB;
|
||||||
|
_wRegBase += (uint32_t)(USB)->BTABLE + 0x400;
|
||||||
|
|
||||||
|
uint16_t * pma_ptr = (uint16_t *)_wRegBase;
|
||||||
|
uint16_t val;
|
||||||
|
uint32_t offset = (uint32_t)(USB)->BTABLE;
|
||||||
|
|
||||||
|
printf("btable: %02lx\r\n",offset);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
uint16_t addr_tx = pma_ptr[i * 4 + 0];
|
||||||
|
uint16_t cnt_tx = pma_ptr[i * 4 + 1];
|
||||||
|
uint16_t addr_rx = pma_ptr[i * 4 + 2];
|
||||||
|
uint16_t cnt_rx = pma_ptr[i * 4 + 3];
|
||||||
|
|
||||||
|
printf("EP%d addr_tx == %02x, count_tx == %02x\r\n", i, addr_tx,cnt_tx );
|
||||||
|
printf("EP%d addr_rx == %02x, count_rx == %02x\r\n", i, addr_rx,cnt_rx );
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ep1_tx = pma_ptr[1 * 4 + 0];
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
val = pma_ptr[ep1_tx + i];
|
||||||
|
printf("%04x ",val);
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USBD_HID_Init
|
* @brief USBD_HID_Init
|
||||||
* Initialize the HID interface
|
* Initialize the HID interface
|
||||||
@ -252,17 +288,12 @@ static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|||||||
/* Open EP IN */
|
/* Open EP IN */
|
||||||
USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE);
|
USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE);
|
||||||
USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE);
|
USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE);
|
||||||
static uint8_t mem[4];
|
static uint8_t mem[sizeof (USBD_HID_HandleTypeDef)];
|
||||||
pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 1U;
|
pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 1U;
|
||||||
pdev->ep_out[HID_EPOUT_ADDR & 0xFU].is_used = 1U;
|
pdev->ep_out[HID_EPOUT_ADDR & 0xFU].is_used = 1U;
|
||||||
|
|
||||||
pdev->pClassData = mem;
|
pdev->pClassData = mem;
|
||||||
|
|
||||||
if (pdev->pClassData == NULL)
|
|
||||||
{
|
|
||||||
return USBD_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
||||||
|
|
||||||
|
|
||||||
@ -411,60 +442,8 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_SendReport
|
|
||||||
* Send HID Report
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param buff: pointer to report
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t *report,
|
|
||||||
uint16_t len)
|
|
||||||
{
|
|
||||||
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;
|
|
||||||
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED )
|
|
||||||
{
|
|
||||||
if(hhid->state == HID_IDLE)
|
|
||||||
{
|
|
||||||
hhid->state = HID_BUSY;
|
|
||||||
USBD_LL_Transmit (pdev,
|
|
||||||
HID_EPIN_ADDR,
|
|
||||||
report,
|
|
||||||
len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetPollingInterval
|
|
||||||
* return polling interval from endpoint descriptor
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @retval polling interval
|
|
||||||
*/
|
|
||||||
uint32_t USBD_HID_GetPollingInterval (USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
uint32_t polling_interval = 0U;
|
|
||||||
|
|
||||||
/* HIGH-speed endpoints */
|
|
||||||
if(pdev->dev_speed == USBD_SPEED_HIGH)
|
|
||||||
{
|
|
||||||
/* Sets the data transfer polling interval for high speed transfers.
|
|
||||||
Values between 1..16 are allowed. Values correspond to interval
|
|
||||||
of 2 ^ (bInterval-1). This option (8 ms, corresponds to HID_HS_BINTERVAL */
|
|
||||||
polling_interval = (((1U <<(HID_BINTERVAL - 1U))) / 8U);
|
|
||||||
}
|
|
||||||
else /* LOW and FULL-speed endpoints */
|
|
||||||
{
|
|
||||||
/* Sets the data transfer polling interval for low and full
|
|
||||||
speed transfers */
|
|
||||||
polling_interval = HID_BINTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((uint32_t)(polling_interval));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USBD_HID_GetCfgFSDesc
|
* @brief USBD_HID_GetCfgFSDesc
|
||||||
@ -495,6 +474,14 @@ static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev,
|
|||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t USBD_HID_DataOut (USBD_HandleTypeDef *pdev,
|
||||||
|
uint8_t epnum)
|
||||||
|
{
|
||||||
|
/* Ensure that the FIFO is empty before a new transfer, this condition could
|
||||||
|
be caused by a new transfer before the end of the previous transfer */
|
||||||
|
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
||||||
|
return USBD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DeviceQualifierDescriptor
|
* @brief DeviceQualifierDescriptor
|
@ -66,7 +66,7 @@
|
|||||||
#define HID_DESCRIPTOR_TYPE 0x21U
|
#define HID_DESCRIPTOR_TYPE 0x21U
|
||||||
#define HID_REPORT_DESC 0x22U
|
#define HID_REPORT_DESC 0x22U
|
||||||
|
|
||||||
#define HID_BINTERVAL 10
|
#define HID_BINTERVAL 5
|
||||||
|
|
||||||
#define HID_REQ_SET_PROTOCOL 0x0BU
|
#define HID_REQ_SET_PROTOCOL 0x0BU
|
||||||
#define HID_REQ_GET_PROTOCOL 0x03U
|
#define HID_REQ_GET_PROTOCOL 0x03U
|
@ -1,816 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file usbd_hid.c
|
|
||||||
* @author MCD Application Team
|
|
||||||
* @brief This file provides the HID core functions.
|
|
||||||
*
|
|
||||||
* @verbatim
|
|
||||||
*
|
|
||||||
* ===================================================================
|
|
||||||
* HID Class Description
|
|
||||||
* ===================================================================
|
|
||||||
* This module manages the HID class V1.11 following the "Device Class Definition
|
|
||||||
* for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
|
|
||||||
* This driver implements the following aspects of the specification:
|
|
||||||
* - The Boot Interface Subclass
|
|
||||||
* - The Mouse protocol
|
|
||||||
* - Usage Page : Generic Desktop
|
|
||||||
* - Usage : Joystick
|
|
||||||
* - Collection : Application
|
|
||||||
*
|
|
||||||
* @note In HS mode and when the DMA is used, all variables and data structures
|
|
||||||
* dealing with the DMA during the transaction process should be 32-bit aligned.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @endverbatim
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted, provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistribution of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
|
||||||
* contributors to this software may be used to endorse or promote products
|
|
||||||
* derived from this software without specific written permission.
|
|
||||||
* 4. This software, including modifications and/or derivative works of this
|
|
||||||
* software, must execute solely and exclusively on microcontroller or
|
|
||||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
|
||||||
* 5. Redistribution and use of this software other than as permitted under
|
|
||||||
* this license is void and will automatically terminate your rights under
|
|
||||||
* this license.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
|
||||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
|
||||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* BSPDependencies
|
|
||||||
- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
|
|
||||||
- "stm32xxxxx_{eval}{discovery}_io.c"
|
|
||||||
EndBSPDependencies */
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "usbd_hid.h"
|
|
||||||
#include "usbd_ctlreq.h"
|
|
||||||
|
|
||||||
|
|
||||||
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID
|
|
||||||
* @brief usbd core module
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_TypesDefinitions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Defines
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Macros
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_FunctionPrototypes
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetFSCfgDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetHSCfgDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetOtherSpeedCfgDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Variables
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
USBD_ClassTypeDef USBD_HID =
|
|
||||||
{
|
|
||||||
USBD_HID_Init,
|
|
||||||
USBD_HID_DeInit,
|
|
||||||
USBD_HID_Setup,
|
|
||||||
NULL, /*EP0_TxSent*/
|
|
||||||
NULL, /*EP0_RxReady*/
|
|
||||||
USBD_HID_DataIn, /*DataIn*/
|
|
||||||
USBD_HID_DataOut, /*DataOut*/
|
|
||||||
NULL, /*SOF */
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
USBD_HID_GetHSCfgDesc,
|
|
||||||
USBD_HID_GetFSCfgDesc,
|
|
||||||
USBD_HID_GetOtherSpeedCfgDesc,
|
|
||||||
USBD_HID_GetDeviceQualifierDesc,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define USBD_HID_CfgHSDesc USBD_HID_OtherSpeedCfgDesc
|
|
||||||
#define USBD_HID_CfgFSDesc USBD_HID_OtherSpeedCfgDesc
|
|
||||||
|
|
||||||
/* USB HID device FS Configuration Descriptor */
|
|
||||||
/*__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =*/
|
|
||||||
/*{*/
|
|
||||||
/*0x09, [> bLength: Configuration Descriptor size <]*/
|
|
||||||
/*USB_DESC_TYPE_CONFIGURATION, [> bDescriptorType: Configuration <]*/
|
|
||||||
/*USB_HID_CONFIG_DESC_SIZ,*/
|
|
||||||
/*[> wTotalLength: Bytes returned <]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*0x01, [>bNumInterfaces: 1 interface<]*/
|
|
||||||
/*0x01, [>bConfigurationValue: Configuration value<]*/
|
|
||||||
/*0x00, //iConfiguration: Index of string descriptor describing*/
|
|
||||||
/*//the configuration*/
|
|
||||||
/*0xE0, [>bmAttributes: bus powered and Support Remote Wake-up <]*/
|
|
||||||
/*0x32, [>MaxPower 100 mA: this current is used for detecting Vbus<]*/
|
|
||||||
|
|
||||||
/*[>************* Descriptor of Joystick Mouse interface ***************<]*/
|
|
||||||
/*[> 09 <]*/
|
|
||||||
/*0x09, [>bLength: Interface Descriptor size<]*/
|
|
||||||
/*USB_DESC_TYPE_INTERFACE,[>bDescriptorType: Interface descriptor type<]*/
|
|
||||||
/*0x00, [>bInterfaceNumber: Number of Interface<]*/
|
|
||||||
/*0x00, [>bAlternateSetting: Alternate setting<]*/
|
|
||||||
/*0x01, [>bNumEndpoints<]*/
|
|
||||||
/*0x03, [>bInterfaceClass: HID<]*/
|
|
||||||
/*0x01, [>bInterfaceSubClass : 1=BOOT, 0=no boot<]*/
|
|
||||||
/*0x02, [>nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse<]*/
|
|
||||||
/*0, [>iInterface: Index of string descriptor<]*/
|
|
||||||
/*[>******************* Descriptor of Joystick Mouse HID *******************<]*/
|
|
||||||
/*[> 18 <]*/
|
|
||||||
/*0x09, [>bLength: HID Descriptor size<]*/
|
|
||||||
/*HID_DESCRIPTOR_TYPE, [>bDescriptorType: HID<]*/
|
|
||||||
/*0x11, [>bcdHID: HID Class Spec release number<]*/
|
|
||||||
/*0x01,*/
|
|
||||||
/*0x00, [>bCountryCode: Hardware target country<]*/
|
|
||||||
/*0x01, [>bNumDescriptors: Number of HID class descriptors to follow<]*/
|
|
||||||
/*0x22, [>bDescriptorType<]*/
|
|
||||||
/*HID_MOUSE_REPORT_DESC_SIZE,[>wItemLength: Total length of Report descriptor<]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*[>******************* Descriptor of Mouse endpoint *******************<]*/
|
|
||||||
/*[> 27 <]*/
|
|
||||||
/*0x07, [>bLength: Endpoint Descriptor size<]*/
|
|
||||||
/*USB_DESC_TYPE_ENDPOINT, [>bDescriptorType:<]*/
|
|
||||||
|
|
||||||
/*HID_EPIN_ADDR, [>bEndpointAddress: Endpoint Address (IN)<]*/
|
|
||||||
/*0x03, [>bmAttributes: Interrupt endpoint<]*/
|
|
||||||
/*HID_EPIN_SIZE, [>wMaxPacketSize: 4 Byte max <]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*HID_FS_BINTERVAL, [>bInterval: Polling Interval <]*/
|
|
||||||
/*[> 34 <]*/
|
|
||||||
/*};*/
|
|
||||||
/* USB HID device HS Configuration Descriptor */
|
|
||||||
/*__ALIGN_BEGIN static uint8_t USBD_HID_CfgHSDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =*/
|
|
||||||
/*{*/
|
|
||||||
/*0x09, [> bLength: Configuration Descriptor size <]*/
|
|
||||||
/*USB_DESC_TYPE_CONFIGURATION, [> bDescriptorType: Configuration <]*/
|
|
||||||
/*USB_HID_CONFIG_DESC_SIZ,*/
|
|
||||||
/*[> wTotalLength: Bytes returned <]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*0x01, [>bNumInterfaces: 1 interface<]*/
|
|
||||||
/*0x01, [>bConfigurationValue: Configuration value<]*/
|
|
||||||
/*0x00, //iConfiguration: Index of string descriptor describing*/
|
|
||||||
/*the configuration**/
|
|
||||||
/*0xE0, [>bmAttributes: bus powered and Support Remote Wake-up <]*/
|
|
||||||
/*0x32, [>MaxPower 100 mA: this current is used for detecting Vbus<]*/
|
|
||||||
|
|
||||||
/*[>************* Descriptor of Joystick Mouse interface ***************<]*/
|
|
||||||
/*[> 09 <]*/
|
|
||||||
/*0x09, [>bLength: Interface Descriptor size<]*/
|
|
||||||
/*USB_DESC_TYPE_INTERFACE,[>bDescriptorType: Interface descriptor type<]*/
|
|
||||||
/*0x00, [>bInterfaceNumber: Number of Interface<]*/
|
|
||||||
/*0x00, [>bAlternateSetting: Alternate setting<]*/
|
|
||||||
/*0x01, [>bNumEndpoints<]*/
|
|
||||||
/*0x03, [>bInterfaceClass: HID<]*/
|
|
||||||
/*0x01, [>bInterfaceSubClass : 1=BOOT, 0=no boot<]*/
|
|
||||||
/*0x02, [>nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse<]*/
|
|
||||||
/*0, [>iInterface: Index of string descriptor<]*/
|
|
||||||
/*[>******************* Descriptor of Joystick Mouse HID *******************<]*/
|
|
||||||
/*[> 18 <]*/
|
|
||||||
/*0x09, [>bLength: HID Descriptor size<]*/
|
|
||||||
/*HID_DESCRIPTOR_TYPE, [>bDescriptorType: HID<]*/
|
|
||||||
/*0x11, [>bcdHID: HID Class Spec release number<]*/
|
|
||||||
/*0x01,*/
|
|
||||||
/*0x00, [>bCountryCode: Hardware target country<]*/
|
|
||||||
/*0x01, [>bNumDescriptors: Number of HID class descriptors to follow<]*/
|
|
||||||
/*0x22, [>bDescriptorType<]*/
|
|
||||||
/*HID_MOUSE_REPORT_DESC_SIZE,[>wItemLength: Total length of Report descriptor<]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*[>******************* Descriptor of Mouse endpoint *******************<]*/
|
|
||||||
/*[> 27 <]*/
|
|
||||||
/*0x07, [>bLength: Endpoint Descriptor size<]*/
|
|
||||||
/*USB_DESC_TYPE_ENDPOINT, [>bDescriptorType:<]*/
|
|
||||||
|
|
||||||
/*HID_EPIN_ADDR, [>bEndpointAddress: Endpoint Address (IN)<]*/
|
|
||||||
/*0x03, [>bmAttributes: Interrupt endpoint<]*/
|
|
||||||
/*HID_EPIN_SIZE, [>wMaxPacketSize: 4 Byte max <]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*HID_HS_BINTERVAL, [>bInterval: Polling Interval <]*/
|
|
||||||
/*[> 34 <]*/
|
|
||||||
/*};*/
|
|
||||||
|
|
||||||
/* USB HID device Other Speed Configuration Descriptor */
|
|
||||||
/*__ALIGN_BEGIN static uint8_t USBD_HID_OtherSpeedCfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =*/
|
|
||||||
/*{*/
|
|
||||||
/*0x09, [> bLength: Configuration Descriptor size <]*/
|
|
||||||
/*USB_DESC_TYPE_CONFIGURATION, [> bDescriptorType: Configuration <]*/
|
|
||||||
/*USB_HID_CONFIG_DESC_SIZ,*/
|
|
||||||
/*[> wTotalLength: Bytes returned <]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*0x01, [>bNumInterfaces: 1 interface<]*/
|
|
||||||
/*0x01, [>bConfigurationValue: Configuration value<]*/
|
|
||||||
/*0x00, //iConfiguration: Index of string descriptor describing*/
|
|
||||||
/*//the configuration*/
|
|
||||||
/*0xE0, [>bmAttributes: bus powered and Support Remote Wake-up <]*/
|
|
||||||
/*0x32, [>MaxPower 100 mA: this current is used for detecting Vbus<]*/
|
|
||||||
|
|
||||||
/*[>************* Descriptor of Joystick Mouse interface ***************<]*/
|
|
||||||
/*[> 09 <]*/
|
|
||||||
/*0x09, [>bLength: Interface Descriptor size<]*/
|
|
||||||
/*USB_DESC_TYPE_INTERFACE,[>bDescriptorType: Interface descriptor type<]*/
|
|
||||||
/*0x00, [>bInterfaceNumber: Number of Interface<]*/
|
|
||||||
/*0x00, [>bAlternateSetting: Alternate setting<]*/
|
|
||||||
/*0x01, [>bNumEndpoints<]*/
|
|
||||||
/*0x03, [>bInterfaceClass: HID<]*/
|
|
||||||
/*0x01, [>bInterfaceSubClass : 1=BOOT, 0=no boot<]*/
|
|
||||||
/*0x02, [>nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse<]*/
|
|
||||||
/*0, [>iInterface: Index of string descriptor<]*/
|
|
||||||
/*[>******************* Descriptor of Joystick Mouse HID *******************<]*/
|
|
||||||
/*[> 18 <]*/
|
|
||||||
/*0x09, [>bLength: HID Descriptor size<]*/
|
|
||||||
/*HID_DESCRIPTOR_TYPE, [>bDescriptorType: HID<]*/
|
|
||||||
/*0x11, [>bcdHID: HID Class Spec release number<]*/
|
|
||||||
/*0x01,*/
|
|
||||||
/*0x00, [>bCountryCode: Hardware target country<]*/
|
|
||||||
/*0x01, [>bNumDescriptors: Number of HID class descriptors to follow<]*/
|
|
||||||
/*0x22, [>bDescriptorType<]*/
|
|
||||||
/*HID_MOUSE_REPORT_DESC_SIZE,[>wItemLength: Total length of Report descriptor<]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*[>******************* Descriptor of Mouse endpoint *******************<]*/
|
|
||||||
/*[> 27 <]*/
|
|
||||||
/*0x07, [>bLength: Endpoint Descriptor size<]*/
|
|
||||||
/*USB_DESC_TYPE_ENDPOINT, [>bDescriptorType:<]*/
|
|
||||||
|
|
||||||
/*HID_EPIN_ADDR, [>bEndpointAddress: Endpoint Address (IN)<]*/
|
|
||||||
/*0x03, [>bmAttributes: Interrupt endpoint<]*/
|
|
||||||
/*HID_EPIN_SIZE, [>wMaxPacketSize: 4 Byte max <]*/
|
|
||||||
/*0x00,*/
|
|
||||||
/*HID_FS_BINTERVAL, [>bInterval: Polling Interval <]*/
|
|
||||||
/*[> 34 <]*/
|
|
||||||
/*};*/
|
|
||||||
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_OtherSpeedCfgDesc[] __ALIGN_END =
|
|
||||||
{
|
|
||||||
0x09, // bLength
|
|
||||||
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
||||||
0x29,// wTotalLength(LSB)
|
|
||||||
0x00,// wTotalLength(MSB)
|
|
||||||
1,// bNumInterfaces
|
|
||||||
1,// bConfigurationValue
|
|
||||||
0,// iConfiguration
|
|
||||||
0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
|
|
||||||
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
|
|
||||||
|
|
||||||
|
|
||||||
//Interface 0 Descriptor
|
|
||||||
0x09, /*bLength: Interface Descriptor size*/
|
|
||||||
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
|
||||||
0,// bInterfaceNumber
|
|
||||||
0,// bAlternateSetting
|
|
||||||
2,// bNumEndpoints
|
|
||||||
3,// bInterfaceClass: HID (Human Interface Device)
|
|
||||||
0,// bInterfaceSubClass
|
|
||||||
0,// bInterfaceProtocol
|
|
||||||
0,// iInterface
|
|
||||||
|
|
||||||
//HID Descriptor
|
|
||||||
0x09, /*bLength: HID Descriptor size*/
|
|
||||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
|
||||||
0x11,// bcdHID (LSB)
|
|
||||||
0x01,// bcdHID (MSB)
|
|
||||||
0,// bCountryCode
|
|
||||||
1,// bNumDescriptors
|
|
||||||
0x22, /*bDescriptorType, HID report type*/
|
|
||||||
( 34 ), // wDescriptorLength(LSB)
|
|
||||||
( 34 )>>8, // wDescriptorLength(MSB)
|
|
||||||
|
|
||||||
//Endpoint 2 IN Descriptor
|
|
||||||
7,// bLength
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
|
||||||
HID_EPIN_ADDR,// bEndpointAddress input
|
|
||||||
0x03,// bAttrib interrupt type
|
|
||||||
HID_PACKET_SIZE,// wMaxPacketSize (LSB)
|
|
||||||
0x00,// wMaxPacketSize (MSB)
|
|
||||||
HID_FS_BINTERVAL,// bInterval
|
|
||||||
|
|
||||||
//Endpoint 3 OUT Descriptor
|
|
||||||
7,// bLength
|
|
||||||
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
|
||||||
HID_EPOUT_ADDR,// bEndpointAddress output
|
|
||||||
0x03,// bAttrib, interrupt type
|
|
||||||
HID_PACKET_SIZE,// wMaxPacketSize (LSB)
|
|
||||||
0x00,// wMaxPacketSize (MSB)
|
|
||||||
HID_FS_BINTERVAL, /*bInterval: Polling Interval */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* USB HID device Configuration Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END =
|
|
||||||
{
|
|
||||||
/* 18 */
|
|
||||||
0x09, /*bLength: HID Descriptor size*/
|
|
||||||
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
|
|
||||||
0x11, /*bcdHID: HID Class Spec release number*/
|
|
||||||
0x01,
|
|
||||||
0x00, /*bCountryCode: Hardware target country*/
|
|
||||||
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
|
|
||||||
0x22, /*bDescriptorType*/
|
|
||||||
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
|
|
||||||
0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB Standard Device Descriptor */
|
|
||||||
__ALIGN_BEGIN static uint8_t USBD_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
||||||
{
|
|
||||||
USB_LEN_DEV_QUALIFIER_DESC,
|
|
||||||
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x00,
|
|
||||||
0x40,
|
|
||||||
0x01,
|
|
||||||
0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =*/
|
|
||||||
/*{*/
|
|
||||||
/*0x05, 0x01,*/
|
|
||||||
/*0x09, 0x02,*/
|
|
||||||
/*0xA1, 0x01,*/
|
|
||||||
/*0x09, 0x01,*/
|
|
||||||
|
|
||||||
/*0xA1, 0x00,*/
|
|
||||||
/*0x05, 0x09,*/
|
|
||||||
/*0x19, 0x01,*/
|
|
||||||
/*0x29, 0x03,*/
|
|
||||||
|
|
||||||
/*0x15, 0x00,*/
|
|
||||||
/*0x25, 0x01,*/
|
|
||||||
/*0x95, 0x03,*/
|
|
||||||
/*0x75, 0x01,*/
|
|
||||||
|
|
||||||
/*0x81, 0x02,*/
|
|
||||||
/*0x95, 0x01,*/
|
|
||||||
/*0x75, 0x05,*/
|
|
||||||
/*0x81, 0x01,*/
|
|
||||||
|
|
||||||
/*0x05, 0x01,*/
|
|
||||||
/*0x09, 0x30,*/
|
|
||||||
/*0x09, 0x31,*/
|
|
||||||
/*0x09, 0x38,*/
|
|
||||||
|
|
||||||
/*0x15, 0x81,*/
|
|
||||||
/*0x25, 0x7F,*/
|
|
||||||
/*0x75, 0x08,*/
|
|
||||||
/*0x95, 0x03,*/
|
|
||||||
|
|
||||||
/*0x81, 0x06,*/
|
|
||||||
/*0xC0, 0x09,*/
|
|
||||||
/*0x3c, 0x05,*/
|
|
||||||
/*0xff, 0x09,*/
|
|
||||||
|
|
||||||
/*0x01, 0x15,*/
|
|
||||||
/*0x00, 0x25,*/
|
|
||||||
/*0x01, 0x75,*/
|
|
||||||
/*0x01, 0x95,*/
|
|
||||||
|
|
||||||
/*0x02, 0xb1,*/
|
|
||||||
/*0x22, 0x75,*/
|
|
||||||
/*0x06, 0x95,*/
|
|
||||||
/*0x01, 0xb1,*/
|
|
||||||
|
|
||||||
/*0x01, 0xc0*/
|
|
||||||
/*};*/
|
|
||||||
|
|
||||||
/*__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =*/
|
|
||||||
/*{*/
|
|
||||||
|
|
||||||
/*0x06, 0xd0, 0xf1,// USAGE_PAGE (FIDO Alliance)*/
|
|
||||||
/*0x09, 0x01,// USAGE (Keyboard)*/
|
|
||||||
/*0xa1, 0x01,// COLLECTION (Application)*/
|
|
||||||
|
|
||||||
/*0x09, 0x20, // USAGE (Input Report Data)*/
|
|
||||||
/*0x15, 0x00, // LOGICAL_MINIMUM (0)*/
|
|
||||||
/*0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)*/
|
|
||||||
/*0x75, 0x08, // REPORT_SIZE (8)*/
|
|
||||||
/*0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)*/
|
|
||||||
/*0x81, 0x02, // INPUT (Data,Var,Abs)*/
|
|
||||||
/*0x09, 0x21, // USAGE(Output Report Data)*/
|
|
||||||
/*0x15, 0x00, // LOGICAL_MINIMUM (0)*/
|
|
||||||
/*0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)*/
|
|
||||||
/*0x75, 0x08, // REPORT_SIZE (8)*/
|
|
||||||
/*0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)*/
|
|
||||||
/*0x91, 0x02, // OUTPUT (Data,Var,Abs)*/
|
|
||||||
|
|
||||||
|
|
||||||
/*0xc0,// END_COLLECTION*/
|
|
||||||
|
|
||||||
/*};*/
|
|
||||||
|
|
||||||
#define _DEBUG() printf("%d\r\n", __LINE__)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Private_Functions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_Init
|
|
||||||
* Initialize the HID interface
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param cfgidx: Configuration index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
/* Open EP IN */
|
|
||||||
_DEBUG();
|
|
||||||
USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE);
|
|
||||||
USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE);
|
|
||||||
pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 1U;
|
|
||||||
|
|
||||||
pdev->pClassData = USBD_malloc(sizeof (USBD_HID_HandleTypeDef));
|
|
||||||
|
|
||||||
if (pdev->pClassData == NULL)
|
|
||||||
{
|
|
||||||
return USBD_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_Init
|
|
||||||
* DeInitialize the HID layer
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param cfgidx: Configuration index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t cfgidx)
|
|
||||||
{
|
|
||||||
_DEBUG();
|
|
||||||
/* Close HID EPs */
|
|
||||||
USBD_LL_CloseEP(pdev, HID_EPIN_ADDR);
|
|
||||||
pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 0U;
|
|
||||||
|
|
||||||
/* FRee allocated memory */
|
|
||||||
if(pdev->pClassData != NULL)
|
|
||||||
{
|
|
||||||
USBD_free(pdev->pClassData);
|
|
||||||
pdev->pClassData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_Setup
|
|
||||||
* Handle the HID specific requests
|
|
||||||
* @param pdev: instance
|
|
||||||
* @param req: usb requests
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|
||||||
USBD_SetupReqTypedef *req)
|
|
||||||
{
|
|
||||||
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*) pdev->pClassData;
|
|
||||||
uint16_t len = 0U;
|
|
||||||
uint8_t *pbuf = NULL;
|
|
||||||
uint16_t status_info = 0U;
|
|
||||||
USBD_StatusTypeDef ret = USBD_OK;
|
|
||||||
|
|
||||||
_DEBUG();
|
|
||||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
||||||
{
|
|
||||||
case USB_REQ_TYPE_CLASS :
|
|
||||||
switch (req->bRequest)
|
|
||||||
{
|
|
||||||
case HID_REQ_SET_PROTOCOL:
|
|
||||||
hhid->Protocol = (uint8_t)(req->wValue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HID_REQ_GET_PROTOCOL:
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->Protocol, 1U);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HID_REQ_SET_IDLE:
|
|
||||||
hhid->IdleState = (uint8_t)(req->wValue >> 8);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HID_REQ_GET_IDLE:
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->IdleState, 1U);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
printf("HID setup error %d\r\n", __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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_DESCRIPTOR:
|
|
||||||
if(req->wValue >> 8 == HID_REPORT_DESC)
|
|
||||||
{
|
|
||||||
len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength);
|
|
||||||
pbuf = HID_MOUSE_ReportDesc;
|
|
||||||
}
|
|
||||||
else if(req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
|
|
||||||
{
|
|
||||||
pbuf = USBD_HID_Desc;
|
|
||||||
len = MIN(USB_HID_DESC_SIZ, req->wLength);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
USBD_CtlSendData (pdev, pbuf, len);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_GET_INTERFACE :
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->AltSetting, 1U);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_SET_INTERFACE :
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
||||||
{
|
|
||||||
hhid->AltSetting = (uint8_t)(req->wValue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
printf("HID setup error %d\r\n", __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USBD_CtlError (pdev, req);
|
|
||||||
ret = USBD_FAIL;
|
|
||||||
printf("HID setup error %d\r\n", __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_SendReport
|
|
||||||
* Send HID Report
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param buff: pointer to report
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t *report,
|
|
||||||
uint16_t len)
|
|
||||||
{
|
|
||||||
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;
|
|
||||||
|
|
||||||
_DEBUG();
|
|
||||||
if (pdev->dev_state == USBD_STATE_CONFIGURED )
|
|
||||||
{
|
|
||||||
if(hhid->state == HID_IDLE)
|
|
||||||
{
|
|
||||||
hhid->state = HID_BUSY;
|
|
||||||
USBD_LL_Transmit (pdev,
|
|
||||||
HID_EPIN_ADDR,
|
|
||||||
report,
|
|
||||||
len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetPollingInterval
|
|
||||||
* return polling interval from endpoint descriptor
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @retval polling interval
|
|
||||||
*/
|
|
||||||
uint32_t USBD_HID_GetPollingInterval (USBD_HandleTypeDef *pdev)
|
|
||||||
{
|
|
||||||
uint32_t polling_interval = 0U;
|
|
||||||
|
|
||||||
_DEBUG();
|
|
||||||
/* HIGH-speed endpoints */
|
|
||||||
if(pdev->dev_speed == USBD_SPEED_HIGH)
|
|
||||||
{
|
|
||||||
/* Sets the data transfer polling interval for high speed transfers.
|
|
||||||
Values between 1..16 are allowed. Values correspond to interval
|
|
||||||
of 2 ^ (bInterval-1). This option (8 ms, corresponds to HID_HS_BINTERVAL */
|
|
||||||
polling_interval = (((1U <<(HID_HS_BINTERVAL - 1U))) / 8U);
|
|
||||||
}
|
|
||||||
else /* LOW and FULL-speed endpoints */
|
|
||||||
{
|
|
||||||
/* Sets the data transfer polling interval for low and full
|
|
||||||
speed transfers */
|
|
||||||
polling_interval = HID_FS_BINTERVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((uint32_t)(polling_interval));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetCfgFSDesc
|
|
||||||
* return FS configuration descriptor
|
|
||||||
* @param speed : current device speed
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetFSCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
_DEBUG();
|
|
||||||
*length = sizeof (USBD_HID_CfgFSDesc);
|
|
||||||
return USBD_HID_CfgFSDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetCfgHSDesc
|
|
||||||
* return HS configuration descriptor
|
|
||||||
* @param speed : current device speed
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetHSCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
_DEBUG();
|
|
||||||
*length = sizeof (USBD_HID_CfgHSDesc);
|
|
||||||
return USBD_HID_CfgHSDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_GetOtherSpeedCfgDesc
|
|
||||||
* return other speed configuration descriptor
|
|
||||||
* @param speed : current device speed
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetOtherSpeedCfgDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
_DEBUG();
|
|
||||||
*length = sizeof (USBD_HID_OtherSpeedCfgDesc);
|
|
||||||
return USBD_HID_OtherSpeedCfgDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief USBD_HID_DataIn
|
|
||||||
* handle data IN Stage
|
|
||||||
* @param pdev: device instance
|
|
||||||
* @param epnum: endpoint index
|
|
||||||
* @retval status
|
|
||||||
*/
|
|
||||||
static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t epnum)
|
|
||||||
{
|
|
||||||
_DEBUG();
|
|
||||||
|
|
||||||
/* Ensure that the FIFO is empty before a new transfer, this condition could
|
|
||||||
be caused by a new transfer before the end of the previous transfer */
|
|
||||||
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t USBD_HID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
||||||
{
|
|
||||||
|
|
||||||
_DEBUG();
|
|
||||||
/* Ensure that the FIFO is empty before a new transfer, this condition could
|
|
||||||
be caused by a new transfer before the end of the previous transfer */
|
|
||||||
((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
|
|
||||||
return USBD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief DeviceQualifierDescriptor
|
|
||||||
* return Device Qualifier descriptor
|
|
||||||
* @param length : pointer data length
|
|
||||||
* @retval pointer to descriptor buffer
|
|
||||||
*/
|
|
||||||
static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length)
|
|
||||||
{
|
|
||||||
_DEBUG();
|
|
||||||
*length = sizeof (USBD_HID_DeviceQualifierDesc);
|
|
||||||
return USBD_HID_DeviceQualifierDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
@ -1,176 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file usbd_hid.h
|
|
||||||
* @author MCD Application Team
|
|
||||||
* @brief Header file for the usbd_hid_core.c file.
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted, provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistribution of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
|
||||||
* contributors to this software may be used to endorse or promote products
|
|
||||||
* derived from this software without specific written permission.
|
|
||||||
* 4. This software, including modifications and/or derivative works of this
|
|
||||||
* software, must execute solely and exclusively on microcontroller or
|
|
||||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
|
||||||
* 5. Redistribution and use of this software other than as permitted under
|
|
||||||
* this license is void and will automatically terminate your rights under
|
|
||||||
* this license.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
|
||||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
|
||||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
|
||||||
#ifndef __USB_HID_H
|
|
||||||
#define __USB_HID_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "usbd_ioreq.h"
|
|
||||||
|
|
||||||
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID
|
|
||||||
* @brief This file is the Header file for usbd_hid.c
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_HID_Exported_Defines
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
#define HID_PACKET_SIZE (64)
|
|
||||||
|
|
||||||
#define HID_EPIN_ADDR 0x81U
|
|
||||||
#define HID_EPIN_SIZE HID_PACKET_SIZE
|
|
||||||
|
|
||||||
#define HID_EPOUT_ADDR 0x01U
|
|
||||||
#define HID_EPOUT_SIZE HID_PACKET_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
//#define USB_HID_CONFIG_DESC_SIZ 34U
|
|
||||||
#define USB_HID_DESC_SIZ 9U
|
|
||||||
#define HID_MOUSE_REPORT_DESC_SIZE 34U
|
|
||||||
|
|
||||||
#define HID_DESCRIPTOR_TYPE 0x21U
|
|
||||||
#define HID_REPORT_DESC 0x22U
|
|
||||||
|
|
||||||
#ifndef HID_HS_BINTERVAL
|
|
||||||
#define HID_HS_BINTERVAL 0x07U
|
|
||||||
#endif /* HID_HS_BINTERVAL */
|
|
||||||
|
|
||||||
#ifndef HID_FS_BINTERVAL
|
|
||||||
#define HID_FS_BINTERVAL 0x0AU
|
|
||||||
#endif /* HID_FS_BINTERVAL */
|
|
||||||
|
|
||||||
#define HID_REQ_SET_PROTOCOL 0x0BU
|
|
||||||
#define HID_REQ_GET_PROTOCOL 0x03U
|
|
||||||
|
|
||||||
#define HID_REQ_SET_IDLE 0x0AU
|
|
||||||
#define HID_REQ_GET_IDLE 0x02U
|
|
||||||
|
|
||||||
#define HID_REQ_SET_REPORT 0x09U
|
|
||||||
#define HID_REQ_GET_REPORT 0x01U
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_CORE_Exported_TypesDefinitions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
HID_IDLE = 0,
|
|
||||||
HID_BUSY,
|
|
||||||
}
|
|
||||||
HID_StateTypeDef;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t Protocol;
|
|
||||||
uint32_t IdleState;
|
|
||||||
uint32_t AltSetting;
|
|
||||||
HID_StateTypeDef state;
|
|
||||||
}
|
|
||||||
USBD_HID_HandleTypeDef;
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @defgroup USBD_CORE_Exported_Macros
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USBD_CORE_Exported_Variables
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern USBD_ClassTypeDef USBD_HID;
|
|
||||||
#define USBD_HID_CLASS &USBD_HID
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup USB_CORE_Exported_Functions
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev,
|
|
||||||
uint8_t *report,
|
|
||||||
uint16_t len);
|
|
||||||
|
|
||||||
uint32_t USBD_HID_GetPollingInterval (USBD_HandleTypeDef *pdev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __USB_HID_H */
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
@ -4,9 +4,33 @@
|
|||||||
|
|
||||||
#define DEBUG_UART USART1
|
#define DEBUG_UART USART1
|
||||||
|
|
||||||
|
#define DEBUG_LEVEL 1
|
||||||
|
|
||||||
|
#define NON_BLOCK_PRINTING 0
|
||||||
|
|
||||||
|
//#define USING_DEV_BOARD
|
||||||
|
|
||||||
|
//#define ENABLE_U2F_EXTENSIONS
|
||||||
|
|
||||||
|
#define ENABLE_U2F
|
||||||
|
|
||||||
|
//#define DISABLE_CTAPHID_PING
|
||||||
|
//#define DISABLE_CTAPHID_WINK
|
||||||
|
//#define DISABLE_CTAPHID_CBOR
|
||||||
|
|
||||||
|
void printing_init();
|
||||||
void hw_init(void);
|
void hw_init(void);
|
||||||
|
|
||||||
|
//#define TEST
|
||||||
|
//#define TEST_POWER
|
||||||
|
|
||||||
|
#define LED_INIT_VALUE 0x001000
|
||||||
|
|
||||||
|
// Button
|
||||||
|
#define SOLO_BUTTON_PORT GPIOA
|
||||||
|
#define SOLO_BUTTON_PIN LL_GPIO_PIN_0
|
||||||
|
|
||||||
|
#define SKIP_BUTTON_CHECK_WITH_DELAY 1
|
||||||
|
#define SKIP_BUTTON_CHECK_FAST 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
39
targets/stm32l442/src/attestation.c
Normal file
39
targets/stm32l442/src/attestation.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
// For testing/development only
|
||||||
|
|
||||||
|
const uint8_t attestation_cert_der[] =
|
||||||
|
"\x30\x82\x01\xfb\x30\x82\x01\xa1\xa0\x03\x02\x01\x02\x02\x01\x00\x30\x0a\x06\x08"
|
||||||
|
"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
|
||||||
|
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e"
|
||||||
|
"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38"
|
||||||
|
"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32"
|
||||||
|
"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
|
||||||
|
"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x0f\x30\x0d"
|
||||||
|
"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55"
|
||||||
|
"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20"
|
||||||
|
"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72"
|
||||||
|
"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04"
|
||||||
|
"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07"
|
||||||
|
"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00"
|
||||||
|
"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf"
|
||||||
|
"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83"
|
||||||
|
"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca"
|
||||||
|
"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d"
|
||||||
|
"\xa1\x30\xa4\x2e\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31"
|
||||||
|
"\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e\x06\x03\x55\x04"
|
||||||
|
"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94"
|
||||||
|
"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04"
|
||||||
|
"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
|
||||||
|
"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e"
|
||||||
|
"\x7e\x74\x64\x1b\xa3\x7b\xf7\xe6\xd3\xaf\x79\x28\xdb\xdc\xa5\x88\x02\x21\x00\xcd"
|
||||||
|
"\x06\xf1\xe3\xab\x16\x21\x8e\xd8\xc0\x14\xaf\x09\x4f\x5b\x73\xef\x5e\x9e\x4b\xe7"
|
||||||
|
"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7";
|
||||||
|
|
||||||
|
|
||||||
|
const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t attestation_key[] = "\xcd\x67\xaa\x31\x0d\x09\x1e\xd1\x6e\x7e\x98\x92\xaa\x07\x0e\x19\x94\xfc\xd7\x14\xae\x7c\x40\x8f\xb9\x46\xb7\x2e\x5f\xe7\x5d\x30";
|
||||||
|
const uint16_t attestation_key_size = sizeof(attestation_key)-1;
|
331
targets/stm32l442/src/crypto.c
Normal file
331
targets/stm32l442/src/crypto.c
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
* Wrapper for crypto implementation on device
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
#ifdef USE_SOFTWARE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include "sha256.h"
|
||||||
|
#include "uECC.h"
|
||||||
|
#include "aes.h"
|
||||||
|
#include "ctap.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "app.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MBEDTLS_ECP_DP_NONE = 0,
|
||||||
|
MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */
|
||||||
|
MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
|
||||||
|
} mbedtls_ecp_group_id;
|
||||||
|
|
||||||
|
|
||||||
|
static SHA256_CTX sha256_ctx;
|
||||||
|
static const struct uECC_Curve_t * _es256_curve = NULL;
|
||||||
|
static const uint8_t * _signing_key = NULL;
|
||||||
|
static int _key_len = 0;
|
||||||
|
|
||||||
|
// Secrets for testing only
|
||||||
|
static uint8_t master_secret[64];
|
||||||
|
static uint8_t transport_secret[32];
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_sha256_init()
|
||||||
|
{
|
||||||
|
sha256_init(&sha256_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_load_master_secret(uint8_t * key)
|
||||||
|
{
|
||||||
|
#if KEY_SPACE_BYTES < 96
|
||||||
|
#error "need more key bytes"
|
||||||
|
#endif
|
||||||
|
memmove(master_secret, key, 64);
|
||||||
|
memmove(transport_secret, key+64, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_reset_master_secret()
|
||||||
|
{
|
||||||
|
memset(master_secret, 0, 64);
|
||||||
|
memset(transport_secret, 0, 32);
|
||||||
|
ctap_generate_rng(master_secret, 64);
|
||||||
|
ctap_generate_rng(transport_secret, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_sha256_update(uint8_t * data, size_t len)
|
||||||
|
{
|
||||||
|
sha256_update(&sha256_ctx, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_sha256_update_secret()
|
||||||
|
{
|
||||||
|
sha256_update(&sha256_ctx, master_secret, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_sha256_final(uint8_t * hash)
|
||||||
|
{
|
||||||
|
sha256_final(&sha256_ctx, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||||
|
{
|
||||||
|
uint8_t buf[64];
|
||||||
|
int i;
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
if (key == CRYPTO_MASTER_KEY)
|
||||||
|
{
|
||||||
|
key = master_secret;
|
||||||
|
klen = sizeof(master_secret)/2;
|
||||||
|
}
|
||||||
|
else if (key == CRYPTO_TRANSPORT_KEY)
|
||||||
|
{
|
||||||
|
key = transport_secret;
|
||||||
|
klen = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(klen > 64)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(buf, key, klen);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(buf); i++)
|
||||||
|
{
|
||||||
|
buf[i] = buf[i] ^ 0x36;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(buf, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
||||||
|
{
|
||||||
|
uint8_t buf[64];
|
||||||
|
int i;
|
||||||
|
crypto_sha256_final(hmac);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
if (key == CRYPTO_MASTER_KEY)
|
||||||
|
{
|
||||||
|
key = master_secret;
|
||||||
|
klen = sizeof(master_secret)/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(klen > 64)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR, "Error, key size must be <= 64\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memmove(buf, key, klen);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(buf); i++)
|
||||||
|
{
|
||||||
|
buf[i] = buf[i] ^ 0x5c;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(buf, 64);
|
||||||
|
crypto_sha256_update(hmac, 32);
|
||||||
|
crypto_sha256_final(hmac);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_ecc256_init()
|
||||||
|
{
|
||||||
|
uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
|
||||||
|
_es256_curve = uECC_secp256r1();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_ecc256_load_attestation_key()
|
||||||
|
{
|
||||||
|
_signing_key = attestation_key;
|
||||||
|
_key_len = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
||||||
|
{
|
||||||
|
if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR, "error, uECC failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2)
|
||||||
|
{
|
||||||
|
static uint8_t privkey[32];
|
||||||
|
generate_private_key(data,len,data2,len2,privkey);
|
||||||
|
_signing_key = privkey;
|
||||||
|
_key_len = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID)
|
||||||
|
{
|
||||||
|
|
||||||
|
const struct uECC_Curve_t * curve = NULL;
|
||||||
|
|
||||||
|
switch(MBEDTLS_ECP_ID)
|
||||||
|
{
|
||||||
|
case MBEDTLS_ECP_DP_SECP192R1:
|
||||||
|
curve = uECC_secp192r1();
|
||||||
|
if (_key_len != 24) goto fail;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ECP_DP_SECP224R1:
|
||||||
|
curve = uECC_secp224r1();
|
||||||
|
if (_key_len != 28) goto fail;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ECP_DP_SECP256R1:
|
||||||
|
curve = uECC_secp256r1();
|
||||||
|
if (_key_len != 32) goto fail;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ECP_DP_SECP256K1:
|
||||||
|
curve = uECC_secp256k1();
|
||||||
|
if (_key_len != 32) goto fail;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf2(TAG_ERR, "error, invalid ECDSA alg specifier\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( uECC_sign(_signing_key, data, len, sig, curve) == 0)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR, "error, uECC failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
printf2(TAG_ERR, "error, invalid key length\n");
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey)
|
||||||
|
{
|
||||||
|
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
|
||||||
|
crypto_sha256_update(data, len);
|
||||||
|
crypto_sha256_update(data2, len2);
|
||||||
|
crypto_sha256_update(master_secret, 32); // TODO AES
|
||||||
|
crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
|
||||||
|
|
||||||
|
crypto_aes256_init(master_secret + 32, NULL);
|
||||||
|
crypto_aes256_encrypt(privkey, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);*/
|
||||||
|
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y)
|
||||||
|
{
|
||||||
|
uint8_t privkey[32];
|
||||||
|
uint8_t pubkey[64];
|
||||||
|
|
||||||
|
generate_private_key(data,len,NULL,0,privkey);
|
||||||
|
|
||||||
|
memset(pubkey,0,sizeof(pubkey));
|
||||||
|
uECC_compute_public_key(privkey, pubkey, _es256_curve);
|
||||||
|
memmove(x,pubkey,32);
|
||||||
|
memmove(y,pubkey+32,32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_load_external_key(uint8_t * key, int len)
|
||||||
|
{
|
||||||
|
_signing_key = key;
|
||||||
|
_key_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
|
||||||
|
{
|
||||||
|
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR, "Error, uECC_make_key failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret)
|
||||||
|
{
|
||||||
|
if (uECC_shared_secret(pubkey, privkey, shared_secret, _es256_curve) != 1)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR, "Error, uECC_shared_secret failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx aes_ctx;
|
||||||
|
void crypto_aes256_init(uint8_t * key, uint8_t * nonce)
|
||||||
|
{
|
||||||
|
if (key == CRYPTO_TRANSPORT_KEY)
|
||||||
|
{
|
||||||
|
AES_init_ctx(&aes_ctx, transport_secret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AES_init_ctx(&aes_ctx, key);
|
||||||
|
}
|
||||||
|
if (nonce == NULL)
|
||||||
|
{
|
||||||
|
memset(aes_ctx.Iv, 0, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove(aes_ctx.Iv, nonce, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent round key recomputation
|
||||||
|
void crypto_aes256_reset_iv(uint8_t * nonce)
|
||||||
|
{
|
||||||
|
if (nonce == NULL)
|
||||||
|
{
|
||||||
|
memset(aes_ctx.Iv, 0, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove(aes_ctx.Iv, nonce, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_aes256_decrypt(uint8_t * buf, int length)
|
||||||
|
{
|
||||||
|
AES_CBC_decrypt_buffer(&aes_ctx, buf, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_aes256_encrypt(uint8_t * buf, int length)
|
||||||
|
{
|
||||||
|
AES_CBC_encrypt_buffer(&aes_ctx, buf, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "No crypto implementation defined"
|
||||||
|
#endif
|
@ -1,25 +1,415 @@
|
|||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "usbd_def.h"
|
#include "usbd_def.h"
|
||||||
|
#include "stm32l4xx.h"
|
||||||
|
#include "stm32l4xx_ll_gpio.h"
|
||||||
|
#include "stm32l4xx_ll_tim.h"
|
||||||
|
#include "stm32l4xx_ll_usart.h"
|
||||||
|
#include "usbd_hid.h"
|
||||||
|
|
||||||
uint32_t __65_seconds = 0;
|
#include "app.h"
|
||||||
|
#include "flash.h"
|
||||||
|
#include "rng.h"
|
||||||
|
#include "led.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "ctaphid.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define PAGE_SIZE 2048
|
||||||
|
#define PAGES 128
|
||||||
|
// Pages 119-127 are data
|
||||||
|
#define COUNTER2_PAGE (PAGES - 4)
|
||||||
|
#define COUNTER1_PAGE (PAGES - 3)
|
||||||
|
#define STATE2_PAGE (PAGES - 2)
|
||||||
|
#define STATE1_PAGE (PAGES - 1)
|
||||||
|
|
||||||
|
|
||||||
|
#define APPLICATION_START_PAGE (0)
|
||||||
|
#define APPLICATION_START_ADDR flash_addr(APPLICATION_START_PAGE)
|
||||||
|
|
||||||
|
#define APPLICATION_END_PAGE ((PAGES - 9)) // 119 is NOT included in application
|
||||||
|
#define APPLICATION_END_ADDR (flash_addr(APPLICATION_END_PAGE)-4) // NOT included in application
|
||||||
|
|
||||||
|
#define AUTH_WORD_ADDR (flash_addr(APPLICATION_END_PAGE)-4)
|
||||||
|
|
||||||
|
uint32_t __90_ms = CTAPHID_STATUS_IDLE;
|
||||||
|
uint32_t __device_status = 0;
|
||||||
|
uint32_t __last_update = 0;
|
||||||
|
extern PCD_HandleTypeDef hpcd;
|
||||||
|
|
||||||
|
#define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
|
||||||
|
|
||||||
|
// Timer6 overflow handler. happens every ~90ms.
|
||||||
void TIM6_DAC_IRQHandler()
|
void TIM6_DAC_IRQHandler()
|
||||||
{
|
{
|
||||||
// timer is only 16 bits, so roll it over here
|
// timer is only 16 bits, so roll it over here
|
||||||
TIM6->SR = 0;
|
TIM6->SR = 0;
|
||||||
__65_seconds += 1;
|
__90_ms += 1;
|
||||||
|
if ((millis() - __last_update) > 8)
|
||||||
|
{
|
||||||
|
if (__device_status != CTAPHID_STATUS_IDLE)
|
||||||
|
{
|
||||||
|
ctaphid_update_status(__device_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern PCD_HandleTypeDef hpcd;
|
|
||||||
// Global USB interrupt handler
|
// Global USB interrupt handler
|
||||||
void USB_IRQHandler(void)
|
void USB_IRQHandler(void)
|
||||||
{
|
{
|
||||||
HAL_PCD_IRQHandler(&hpcd);
|
HAL_PCD_IRQHandler(&hpcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t millis()
|
||||||
|
{
|
||||||
|
return (((uint32_t)TIM6->CNT) + (__90_ms * 90));
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_set_status(int status)
|
||||||
|
{
|
||||||
|
__disable_irq();
|
||||||
|
__last_update = millis();
|
||||||
|
__enable_irq();
|
||||||
|
|
||||||
|
if (status != CTAPHID_STATUS_IDLE && __device_status != status)
|
||||||
|
{
|
||||||
|
ctaphid_update_status(status);
|
||||||
|
}
|
||||||
|
__device_status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void delay(uint32_t ms)
|
void delay(uint32_t ms)
|
||||||
{
|
{
|
||||||
uint32_t time = millis();
|
uint32_t time = millis();
|
||||||
while ((millis() - time) < ms)
|
while ((millis() - time) < ms)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void device_init()
|
||||||
|
{
|
||||||
|
hw_init();
|
||||||
|
LL_GPIO_SetPinMode(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_MODE_INPUT);
|
||||||
|
LL_GPIO_SetPinPull(SOLO_BUTTON_PORT,SOLO_BUTTON_PIN,LL_GPIO_PULL_UP);
|
||||||
|
flash_option_bytes_init(0);
|
||||||
|
|
||||||
|
printf1(TAG_GEN,"hello solo\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhid_init()
|
||||||
|
{
|
||||||
|
printf1(TAG_GEN,"hello solo\r\n");
|
||||||
|
}
|
||||||
|
int usbhid_recv(uint8_t * msg)
|
||||||
|
{
|
||||||
|
if (fifo_hidmsg_size())
|
||||||
|
{
|
||||||
|
fifo_hidmsg_take(msg);
|
||||||
|
printf1(TAG_DUMP,">> ");
|
||||||
|
dump_hex1(TAG_DUMP,msg, HID_PACKET_SIZE);
|
||||||
|
return HID_PACKET_SIZE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhid_send(uint8_t * msg)
|
||||||
|
{
|
||||||
|
printf1(TAG_DUMP,"<< ");
|
||||||
|
dump_hex1(TAG_DUMP, msg, HID_PACKET_SIZE);
|
||||||
|
while (PCD_GET_EP_TX_STATUS(USB, HID_EPIN_ADDR & 0x0f) == USB_EP_TX_VALID)
|
||||||
|
;
|
||||||
|
USBD_LL_Transmit(&Solo_USBD_Device, HID_EPIN_ADDR, msg, HID_PACKET_SIZE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctaphid_write_block(uint8_t * data)
|
||||||
|
{
|
||||||
|
usbhid_send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void usbhid_close()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_loop_delay()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void heartbeat()
|
||||||
|
{
|
||||||
|
static int state = 0;
|
||||||
|
static uint32_t val = (LED_INIT_VALUE >> 8) & 0xff;
|
||||||
|
int but = IS_BUTTON_PRESSED();
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
val--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val > 30 || val < 1)
|
||||||
|
{
|
||||||
|
state = !state;
|
||||||
|
}
|
||||||
|
if (but) led_rgb(val * 2);
|
||||||
|
else
|
||||||
|
led_rgb((val << 16) | (val*2 << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticator_read_state(AuthenticatorState * a)
|
||||||
|
{
|
||||||
|
uint32_t * ptr = (uint32_t *)flash_addr(STATE1_PAGE);
|
||||||
|
memmove(a,ptr,sizeof(AuthenticatorState));
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticator_read_backup_state(AuthenticatorState * a)
|
||||||
|
{
|
||||||
|
uint32_t * ptr = (uint32_t *)flash_addr(STATE2_PAGE);
|
||||||
|
memmove(a,ptr,sizeof(AuthenticatorState));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return 1 yes backup is init'd, else 0
|
||||||
|
int authenticator_is_backup_initialized()
|
||||||
|
{
|
||||||
|
uint8_t header[16];
|
||||||
|
uint32_t * ptr = (uint32_t *)flash_addr(STATE2_PAGE);
|
||||||
|
memmove(header,ptr,16);
|
||||||
|
AuthenticatorState * state = (AuthenticatorState*)header;
|
||||||
|
return state->is_initialized == INITIALIZED_MARKER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticator_write_state(AuthenticatorState * a, int backup)
|
||||||
|
{
|
||||||
|
if (! backup)
|
||||||
|
{
|
||||||
|
flash_erase_page(STATE1_PAGE);
|
||||||
|
|
||||||
|
flash_write(flash_addr(STATE1_PAGE), (uint8_t*)a, sizeof(AuthenticatorState));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flash_erase_page(STATE2_PAGE);
|
||||||
|
|
||||||
|
flash_write(flash_addr(STATE2_PAGE), (uint8_t*)a, sizeof(AuthenticatorState));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ctap_atomic_count(int sel)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
uint32_t * ptr = (uint32_t *)flash_addr(COUNTER1_PAGE);
|
||||||
|
uint32_t erases = *(uint32_t *)flash_addr(COUNTER2_PAGE);
|
||||||
|
static uint32_t sc = 0;
|
||||||
|
if (erases == 0xffffffff)
|
||||||
|
{
|
||||||
|
erases = 1;
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lastc = 0;
|
||||||
|
|
||||||
|
if (sel != 0)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"counter2 not imple\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (offset = 0; offset < PAGE_SIZE/4; offset += 2) // wear-level the flash
|
||||||
|
{
|
||||||
|
if (ptr[offset] != 0xffffffff)
|
||||||
|
{
|
||||||
|
if (ptr[offset] < lastc)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"Error, count went down!\r\n");
|
||||||
|
}
|
||||||
|
lastc = ptr[offset];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lastc) // Happens on initialization as well.
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"warning, power interrupted during previous count. Restoring. lastc==%lu, erases=%lu, offset=%d\r\n", lastc,erases,offset);
|
||||||
|
// there are 32 counts per page
|
||||||
|
lastc = erases * 256 + 1;
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
flash_write(flash_addr(COUNTER1_PAGE), (uint8_t*)&lastc, 4);
|
||||||
|
|
||||||
|
erases++;
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||||
|
return lastc;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastc++;
|
||||||
|
|
||||||
|
if (lastc/256 > erases)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"warning, power interrupted, erases mark, restoring. lastc==%lu, erases=%lu\r\n", lastc,erases);
|
||||||
|
erases = lastc/256;
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == PAGE_SIZE/4)
|
||||||
|
{
|
||||||
|
if (lastc/256 > erases)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"warning, power interrupted, erases mark, restoring lastc==%lu, erases=%lu\r\n", lastc,erases);
|
||||||
|
}
|
||||||
|
erases = lastc/256 + 1;
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
flash_write(flash_addr(COUNTER2_PAGE), (uint8_t*)&erases, 4);
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
flash_write(flash_addr(COUNTER1_PAGE) + offset * 4, (uint8_t*)&lastc, 4);
|
||||||
|
|
||||||
|
if (lastc == sc)
|
||||||
|
{
|
||||||
|
printf1(TAG_RED,"no count detected: lastc==%lu, erases=%lu, offset=%d\r\n", lastc,erases,offset);
|
||||||
|
while(1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc = lastc;
|
||||||
|
|
||||||
|
return lastc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void device_manage()
|
||||||
|
{
|
||||||
|
#if NON_BLOCK_PRINTING
|
||||||
|
int i = 10;
|
||||||
|
uint8_t c;
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
if (fifo_debug_size())
|
||||||
|
{
|
||||||
|
fifo_debug_take(&c);
|
||||||
|
while (! LL_USART_IsActiveFlag_TXE(DEBUG_UART))
|
||||||
|
;
|
||||||
|
LL_USART_TransmitData8(DEBUG_UART,c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_packets()
|
||||||
|
{
|
||||||
|
static uint8_t hidmsg[HID_PACKET_SIZE];
|
||||||
|
memset(hidmsg,0, sizeof(hidmsg));
|
||||||
|
if (usbhid_recv(hidmsg) > 0)
|
||||||
|
{
|
||||||
|
if ( ctaphid_handle_packet(hidmsg) == CTAPHID_CANCEL)
|
||||||
|
{
|
||||||
|
printf1(TAG_GREEN, "CANCEL!\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctap_user_presence_test()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
#if SKIP_BUTTON_CHECK_WITH_DELAY
|
||||||
|
int i=500;
|
||||||
|
while(i--)
|
||||||
|
{
|
||||||
|
delay(1);
|
||||||
|
ret = handle_packets();
|
||||||
|
if (ret) return ret;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
#elif SKIP_BUTTON_CHECK_FAST
|
||||||
|
delay(2);
|
||||||
|
ret = handle_packets();
|
||||||
|
if (ret) return ret;
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
|
uint32_t t1 = millis();
|
||||||
|
led_rgb(0xff3520);
|
||||||
|
|
||||||
|
while (IS_BUTTON_PRESSED())
|
||||||
|
{
|
||||||
|
if (t1 + 5000 < millis())
|
||||||
|
{
|
||||||
|
printf1(TAG_GEN,"Button not pressed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ret = handle_packets();
|
||||||
|
if (ret) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
t1 = millis();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (t1 + 5000 < millis())
|
||||||
|
{
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
delay(1);
|
||||||
|
ret = handle_packets();
|
||||||
|
if (ret) return ret;
|
||||||
|
}
|
||||||
|
while (! IS_BUTTON_PRESSED());
|
||||||
|
|
||||||
|
led_rgb(0x001040);
|
||||||
|
|
||||||
|
delay(50);
|
||||||
|
|
||||||
|
done:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||||
|
{
|
||||||
|
rng_get_bytes(dst, num);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ctap_user_verification(uint8_t arg)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _Error_Handler(char *file, int line)
|
||||||
|
{
|
||||||
|
printf2(TAG_ERR,"Error: %s: %d\r\n", file, line);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef _DEVICE_H_
|
|
||||||
#define _DEVICE_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "stm32l4xx_ll_tim.h"
|
|
||||||
|
|
||||||
void delay(uint32_t ms);
|
|
||||||
|
|
||||||
#define millis() (((uint32_t)TIM6->CNT) | (__65_seconds<<16))
|
|
||||||
extern uint32_t __65_seconds;
|
|
||||||
|
|
||||||
#endif
|
|
@ -4,9 +4,9 @@
|
|||||||
#include "fifo.h"
|
#include "fifo.h"
|
||||||
|
|
||||||
|
|
||||||
|
FIFO_CREATE(debug,4096,1)
|
||||||
|
|
||||||
|
FIFO_CREATE(hidmsg,100,64)
|
||||||
FIFO_CREATE(hidmsg,100,100)
|
|
||||||
|
|
||||||
#if TEST_FIFO
|
#if TEST_FIFO
|
||||||
FIFO_CREATE(test,10,100)
|
FIFO_CREATE(test,10,100)
|
||||||
@ -24,23 +24,25 @@ void fifo_test()
|
|||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||||
ret = fifo_test_add(data[i]);
|
ret = fifo_test_add(data[i]);
|
||||||
printf("%d\r\n",i);
|
printf("%d\r\n",i);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_add fail\r\n");
|
printf("fifo_test_add fail\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||||
ret = fifo_test_take(verif[i]);
|
ret = fifo_test_take(verif[i]);
|
||||||
printf("%d\r\n",i );
|
printf("%d\r\n",i );
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_take fail\r\n");
|
printf("fifo_test_take fail\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(verif[i], data[i], 100) != 0)
|
if (memcmp(verif[i], data[i], 100) != 0)
|
||||||
@ -48,17 +50,18 @@ void fifo_test()
|
|||||||
printf("fifo_test_take result fail\r\n");
|
printf("fifo_test_take result fail\r\n");
|
||||||
dump_hex(data[i],100);
|
dump_hex(data[i],100);
|
||||||
dump_hex(verif[i],100);
|
dump_hex(verif[i],100);
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||||
ret = fifo_test_add(data[i]);
|
ret = fifo_test_add(data[i]);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_add 2 fail\r\n");
|
printf("fifo_test_add 2 fail\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,22 +69,25 @@ void fifo_test()
|
|||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_add should have failed\r\n");
|
printf("fifo_test_add should have failed\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
printf("rhead: %d, whead: %d\r\n", fifo_test_rhead(), fifo_test_whead());
|
||||||
ret = fifo_test_take(verif[i]);
|
ret = fifo_test_take(verif[i]);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_take fail\r\n");
|
printf("fifo_test_take fail\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(verif[i], data[i], 100) != 0)
|
if (memcmp(verif[i], data[i], 100) != 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_take result fail\r\n");
|
printf("fifo_test_take result fail\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,12 +95,12 @@ void fifo_test()
|
|||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
printf("fifo_test_take should have failed\r\n");
|
printf("fifo_test_take should have failed\r\n");
|
||||||
goto end;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("test pass!\r\n");
|
printf("test pass!\r\n");
|
||||||
|
return ;
|
||||||
end:
|
fail:
|
||||||
while(1)
|
while(1)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
|
||||||
|
#ifndef TEST_FIFO
|
||||||
#define TEST_FIFO 0
|
#define TEST_FIFO 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FIFO_CREATE(NAME,LENGTH,BYTES)\
|
#define FIFO_CREATE(NAME,LENGTH,BYTES)\
|
||||||
int __##NAME##_WRITE_PTR = 0;\
|
int __##NAME##_WRITE_PTR = 0;\
|
||||||
@ -13,7 +15,7 @@ static uint8_t __##NAME##_WRITE_BUF[BYTES * LENGTH];\
|
|||||||
\
|
\
|
||||||
int fifo_##NAME##_add(uint8_t * c)\
|
int fifo_##NAME##_add(uint8_t * c)\
|
||||||
{\
|
{\
|
||||||
if (__##NAME##_WRITE_PTR != __##NAME##_READ_PTR || !__##NAME##_SIZE)\
|
if (__##NAME##_SIZE < LENGTH)\
|
||||||
{\
|
{\
|
||||||
memmove(__##NAME##_WRITE_BUF + __##NAME##_WRITE_PTR * BYTES, c, BYTES);\
|
memmove(__##NAME##_WRITE_BUF + __##NAME##_WRITE_PTR * BYTES, c, BYTES);\
|
||||||
__##NAME##_WRITE_PTR ++;\
|
__##NAME##_WRITE_PTR ++;\
|
||||||
@ -28,7 +30,7 @@ int fifo_##NAME##_add(uint8_t * c)\
|
|||||||
int fifo_##NAME##_take(uint8_t * c)\
|
int fifo_##NAME##_take(uint8_t * c)\
|
||||||
{\
|
{\
|
||||||
memmove(c, __##NAME##_WRITE_BUF + __##NAME##_READ_PTR * BYTES, BYTES);\
|
memmove(c, __##NAME##_WRITE_BUF + __##NAME##_READ_PTR * BYTES, BYTES);\
|
||||||
if (__##NAME##_READ_PTR != __##NAME##_WRITE_PTR || __##NAME##_SIZE)\
|
if ( __##NAME##_SIZE > 0)\
|
||||||
{\
|
{\
|
||||||
__##NAME##_READ_PTR ++;\
|
__##NAME##_READ_PTR ++;\
|
||||||
if (__##NAME##_READ_PTR >= LENGTH)\
|
if (__##NAME##_READ_PTR >= LENGTH)\
|
||||||
@ -43,15 +45,27 @@ uint32_t fifo_##NAME##_size()\
|
|||||||
{\
|
{\
|
||||||
return (__##NAME##_SIZE);\
|
return (__##NAME##_SIZE);\
|
||||||
}\
|
}\
|
||||||
|
uint32_t fifo_##NAME##_rhead()\
|
||||||
|
{\
|
||||||
|
return (__##NAME##_READ_PTR);\
|
||||||
|
}\
|
||||||
|
uint32_t fifo_##NAME##_whead()\
|
||||||
|
{\
|
||||||
|
return (__##NAME##_WRITE_PTR);\
|
||||||
|
}\
|
||||||
|
|
||||||
#define FIFO_CREATE_H(NAME,LENGTH,BYTES)\
|
#define FIFO_CREATE_H(NAME)\
|
||||||
int fifo_##NAME##_add(uint8_t * c);\
|
int fifo_##NAME##_add(uint8_t * c);\
|
||||||
int fifo_##NAME##_take(uint8_t * c);\
|
int fifo_##NAME##_take(uint8_t * c);\
|
||||||
uint32_t fifo_##NAME##_size();\
|
uint32_t fifo_##NAME##_size();\
|
||||||
|
uint32_t fifo_##NAME##_rhead();\
|
||||||
|
uint32_t fifo_##NAME##_whead();\
|
||||||
|
|
||||||
FIFO_CREATE_H(hidmsg,10,64)
|
FIFO_CREATE_H(hidmsg)
|
||||||
|
|
||||||
FIFO_CREATE_H(test,100,100)
|
FIFO_CREATE_H(debug)
|
||||||
|
|
||||||
|
FIFO_CREATE_H(test)
|
||||||
|
|
||||||
void fifo_test();
|
void fifo_test();
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
static void flash_unlock()
|
static void flash_unlock()
|
||||||
{
|
{
|
||||||
@ -14,12 +16,59 @@ static void flash_unlock()
|
|||||||
FLASH->KEYR = 0xCDEF89AB;
|
FLASH->KEYR = 0xCDEF89AB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Locks flash and turns off DFU
|
||||||
|
void flash_option_bytes_init(int boot_from_dfu)
|
||||||
|
{
|
||||||
|
#if DEBUG_LEVEL
|
||||||
|
uint32_t val = 0xfffff8aa;
|
||||||
|
#else
|
||||||
|
uint32_t val = 0xfffff8b9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (boot_from_dfu)
|
||||||
|
{
|
||||||
|
val &= ~(1<<27); // nBOOT0 = 0 (boot from system rom)
|
||||||
|
}
|
||||||
|
val &= ~(1<<26); // nSWBOOT0 = 0 (boot from nBoot0)
|
||||||
|
val &= ~(1<<25); // SRAM2_RST = 1 (erase sram on reset)
|
||||||
|
val &= ~(1<<24); // SRAM2_PE = 1 (parity check en)
|
||||||
|
|
||||||
|
if (FLASH->OPTR == val)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
while (FLASH->SR & (1<<16))
|
||||||
|
;
|
||||||
|
flash_unlock();
|
||||||
|
if (FLASH->CR & (1<<30))
|
||||||
|
{
|
||||||
|
FLASH->OPTKEYR = 0x08192A3B;
|
||||||
|
FLASH->OPTKEYR = 0x4C5D6E7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH->OPTR =val;
|
||||||
|
FLASH->CR |= (1<<17);
|
||||||
|
|
||||||
|
while (FLASH->SR & (1<<16))
|
||||||
|
;
|
||||||
|
|
||||||
|
flash_lock();
|
||||||
|
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
void flash_erase_page(uint8_t page)
|
void flash_erase_page(uint8_t page)
|
||||||
{
|
{
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
|
|
||||||
// Wait if flash is busy
|
// Wait if flash is busy
|
||||||
while (FLASH->SR & (1<<16))
|
while (FLASH->SR & (1<<16))
|
||||||
;
|
;
|
||||||
|
flash_unlock();
|
||||||
|
|
||||||
FLASH->SR = FLASH->SR;
|
FLASH->SR = FLASH->SR;
|
||||||
|
|
||||||
// enable flash erase and select page
|
// enable flash erase and select page
|
||||||
@ -33,7 +82,7 @@ void flash_erase_page(uint8_t page)
|
|||||||
|
|
||||||
if(FLASH->SR & (1<<1))
|
if(FLASH->SR & (1<<1))
|
||||||
{
|
{
|
||||||
printf("erase NOT successful %lx\r\n", FLASH->SR);
|
printf2(TAG_ERR,"erase NOT successful %lx\r\n", FLASH->SR);
|
||||||
}
|
}
|
||||||
|
|
||||||
FLASH->CR &= ~(0x7);
|
FLASH->CR &= ~(0x7);
|
||||||
@ -58,7 +107,7 @@ void flash_write_dword(uint32_t addr, uint64_t data)
|
|||||||
|
|
||||||
if(FLASH->SR & (1<<1))
|
if(FLASH->SR & (1<<1))
|
||||||
{
|
{
|
||||||
printf("program NOT successful %lx\r\n", FLASH->SR);
|
printf2(TAG_ERR,"program NOT successful %lx\r\n", FLASH->SR);
|
||||||
}
|
}
|
||||||
|
|
||||||
FLASH->SR = (1<<0);
|
FLASH->SR = (1<<0);
|
||||||
@ -70,9 +119,12 @@ void flash_write(uint32_t addr, uint8_t * data, size_t sz)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t buf[8];
|
uint8_t buf[8];
|
||||||
|
while (FLASH->SR & (1<<16))
|
||||||
|
;
|
||||||
|
flash_unlock();
|
||||||
|
|
||||||
// dword align
|
// dword align
|
||||||
addr &= ~(0x7);
|
addr &= ~(0x07);
|
||||||
|
|
||||||
for(i = 0; i < sz; i+=8)
|
for(i = 0; i < sz; i+=8)
|
||||||
{
|
{
|
||||||
@ -89,5 +141,5 @@ void flash_write(uint32_t addr, uint8_t * data, size_t sz)
|
|||||||
|
|
||||||
void flash_lock()
|
void flash_lock()
|
||||||
{
|
{
|
||||||
FLASH->CR |= (1<<31);
|
FLASH->CR |= (1U<<31);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
void flash_erase_page(uint8_t page);
|
void flash_erase_page(uint8_t page);
|
||||||
void flash_write_dword(uint32_t addr, uint64_t data);
|
void flash_write_dword(uint32_t addr, uint64_t data);
|
||||||
void flash_write(uint32_t addr, uint8_t * data, size_t sz);
|
void flash_write(uint32_t addr, uint8_t * data, size_t sz);
|
||||||
|
void flash_option_bytes_init(int boot_from_dfu);
|
||||||
|
|
||||||
#define FLASH_PAGE_SIZE 2048
|
#define FLASH_PAGE_SIZE 2048
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "usbd_core.h"
|
#include "usbd_core.h"
|
||||||
#include "usbd_desc.h"
|
#include "usbd_desc.h"
|
||||||
#include "usbd_hid.h"
|
#include "usbd_hid.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
|
|
||||||
@ -336,10 +337,10 @@ static void MX_TIM6_Init(void)
|
|||||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
|
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
|
||||||
|
|
||||||
// 48 MHz sys clock --> 6 MHz timer clock
|
// 48 MHz sys clock --> 6 MHz timer clock
|
||||||
// 6 MHz / 6000 == 1000 Hz
|
// 48 MHz / 48000 == 1000 Hz
|
||||||
TIM_InitStruct.Prescaler = 48000;
|
TIM_InitStruct.Prescaler = 48000;
|
||||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||||
TIM_InitStruct.Autoreload = 0xffff;
|
TIM_InitStruct.Autoreload = 90;
|
||||||
LL_TIM_Init(TIM6, &TIM_InitStruct);
|
LL_TIM_Init(TIM6, &TIM_InitStruct);
|
||||||
|
|
||||||
LL_TIM_DisableARRPreload(TIM6);
|
LL_TIM_DisableARRPreload(TIM6);
|
||||||
@ -355,6 +356,35 @@ static void MX_TIM6_Init(void)
|
|||||||
LL_TIM_EnableCounter(TIM6);
|
LL_TIM_EnableCounter(TIM6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TIM7 init function */
|
||||||
|
// static void MX_TIM7_Init(void)
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
// LL_TIM_InitTypeDef TIM_InitStruct;
|
||||||
|
//
|
||||||
|
// /* Peripheral clock enable */
|
||||||
|
// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
|
||||||
|
//
|
||||||
|
// // 48 MHz sys clock --> 6 MHz timer clock
|
||||||
|
// // 6 MHz / 6000 == 1000 Hz
|
||||||
|
// TIM_InitStruct.Prescaler = 48000;
|
||||||
|
// TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||||
|
// TIM_InitStruct.Autoreload = 0xffff;
|
||||||
|
// LL_TIM_Init(TIM6, &TIM_InitStruct);
|
||||||
|
//
|
||||||
|
// LL_TIM_DisableARRPreload(TIM7);
|
||||||
|
//
|
||||||
|
// LL_TIM_SetTriggerOutput(TIM7, LL_TIM_TRGO_RESET);
|
||||||
|
//
|
||||||
|
// LL_TIM_DisableMasterSlaveMode(TIM7);
|
||||||
|
//
|
||||||
|
// // enable interrupt
|
||||||
|
// TIM7->DIER |= 1;
|
||||||
|
//
|
||||||
|
// // Start immediately
|
||||||
|
// LL_TIM_EnableCounter(TIM7);
|
||||||
|
// }
|
||||||
|
|
||||||
/* RNG init function */
|
/* RNG init function */
|
||||||
static void MX_RNG_Init(void)
|
static void MX_RNG_Init(void)
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
void led_rgb(uint32_t hex)
|
void led_rgb(uint32_t hex)
|
||||||
{
|
{
|
||||||
@ -46,9 +47,9 @@ void led_test_colors()
|
|||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("%d: %lu\r\n", j++, millis());
|
printf1(TAG_GREEN, "%d: %lu\r\n", j++, millis());
|
||||||
|
|
||||||
printf("white pulse\r\n");
|
printf1(TAG_GREEN,"white pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -56,7 +57,7 @@ void led_test_colors()
|
|||||||
led_rgb(i | (i << 8) | (i << 16));
|
led_rgb(i | (i << 8) | (i << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("blue pulse\r\n");
|
printf1(TAG_GREEN,"blue pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -64,7 +65,7 @@ void led_test_colors()
|
|||||||
led_rgb(i);
|
led_rgb(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("green pulse\r\n");
|
printf1(TAG_GREEN,"green pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -72,7 +73,7 @@ void led_test_colors()
|
|||||||
led_rgb(i<<8);
|
led_rgb(i<<8);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("red pulse\r\n");
|
printf1(TAG_GREEN,"red pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -80,7 +81,7 @@ void led_test_colors()
|
|||||||
led_rgb(i<<16);
|
led_rgb(i<<16);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("purple pulse\r\n");
|
printf1(TAG_GREEN,"purple pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -88,7 +89,7 @@ void led_test_colors()
|
|||||||
led_rgb((i<<16) | i);
|
led_rgb((i<<16) | i);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("orange pulse\r\n");
|
printf1(TAG_GREEN,"orange pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -96,7 +97,7 @@ void led_test_colors()
|
|||||||
led_rgb((i<<16) | (i<<8));
|
led_rgb((i<<16) | (i<<8));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("yellow pulse\r\n");
|
printf1(TAG_GREEN,"yellow pulse\r\n");
|
||||||
time = millis();
|
time = millis();
|
||||||
while((millis() - time) < 5000)
|
while((millis() - time) < 5000)
|
||||||
{
|
{
|
||||||
@ -105,5 +106,3 @@ void led_test_colors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,8 +27,126 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "fifo.h"
|
#include "fifo.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#ifdef TEST_SOLO_STM32
|
||||||
#define Error_Handler() _Error_Handler(__FILE__,__LINE__)
|
#define Error_Handler() _Error_Handler(__FILE__,__LINE__)
|
||||||
|
#define PAGE_SIZE 2048
|
||||||
|
#define PAGES 128
|
||||||
|
// Pages 119-127 are data
|
||||||
|
#define COUNTER2_PAGE (PAGES - 4)
|
||||||
|
#define COUNTER1_PAGE (PAGES - 3)
|
||||||
|
#define STATE2_PAGE (PAGES - 2)
|
||||||
|
#define STATE1_PAGE (PAGES - 1)
|
||||||
|
|
||||||
|
void test_atomic_counter()
|
||||||
|
{
|
||||||
|
// flash_erase_page(COUNTER1_PAGE);
|
||||||
|
// flash_erase_page(COUNTER2_PAGE);
|
||||||
|
int i;
|
||||||
|
uint32_t c0 = ctap_atomic_count(0);
|
||||||
|
for (i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
uint32_t c1 = ctap_atomic_count(0);
|
||||||
|
if (c1 <= (c0 ))
|
||||||
|
{
|
||||||
|
printf("error, count failed %lu <= %lu\r\n",c1,c0);
|
||||||
|
while(1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
printf("%lu\r\n", c1);
|
||||||
|
c0 = c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("test faults\r\n");
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER2_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
printf("%lu\r\n", ctap_atomic_count(0));
|
||||||
|
|
||||||
|
flash_erase_page(COUNTER1_PAGE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
@ -40,7 +158,24 @@ int main(void)
|
|||||||
uint8_t hidbuf[HID_PACKET_SIZE];
|
uint8_t hidbuf[HID_PACKET_SIZE];
|
||||||
|
|
||||||
hw_init();
|
hw_init();
|
||||||
|
set_logging_mask(
|
||||||
|
/*0*/
|
||||||
|
// TAG_GEN|
|
||||||
|
TAG_MC |
|
||||||
|
TAG_GA |
|
||||||
|
// TAG_WALLET |
|
||||||
|
TAG_STOR |
|
||||||
|
TAG_CP |
|
||||||
|
TAG_CTAP|
|
||||||
|
// TAG_HID|
|
||||||
|
/*TAG_U2F|*/
|
||||||
|
TAG_PARSE |
|
||||||
|
//TAG_TIME|
|
||||||
|
// TAG_DUMP|
|
||||||
|
TAG_GREEN|
|
||||||
|
TAG_RED|
|
||||||
|
TAG_ERR
|
||||||
|
);
|
||||||
printf("hello solo\r\n");
|
printf("hello solo\r\n");
|
||||||
|
|
||||||
// Test flash
|
// Test flash
|
||||||
@ -49,6 +184,24 @@ int main(void)
|
|||||||
memmove(buf,(uint8_t*)flash_addr(60),sizeof(str));
|
memmove(buf,(uint8_t*)flash_addr(60),sizeof(str));
|
||||||
printf("flash: \"%s\"\r\n", buf);
|
printf("flash: \"%s\"\r\n", buf);
|
||||||
|
|
||||||
|
// test_atomic_counter();
|
||||||
|
|
||||||
|
|
||||||
|
// Note that 4 byte aligned addresses won't get written correctly.
|
||||||
|
flash_erase_page(60);
|
||||||
|
uint32_t count = 0;
|
||||||
|
flash_write(flash_addr(60) + 0,(uint8_t*)&count,4);
|
||||||
|
count += 1;
|
||||||
|
flash_write(flash_addr(60) + 4,(uint8_t*)&count,4);
|
||||||
|
count += 1;
|
||||||
|
flash_write(flash_addr(60) + 8,(uint8_t*)&count,4);
|
||||||
|
count += 1;
|
||||||
|
flash_write(flash_addr(60) + 12,(uint8_t*)&count,4);
|
||||||
|
count += 1;
|
||||||
|
flash_write(flash_addr(60) + 16,(uint8_t*)&count,4);
|
||||||
|
dump_hex((uint8_t *)flash_addr(60), 20);
|
||||||
|
|
||||||
|
|
||||||
// test timer
|
// test timer
|
||||||
uint32_t t1 = millis();
|
uint32_t t1 = millis();
|
||||||
delay(100);
|
delay(100);
|
||||||
@ -62,7 +215,7 @@ int main(void)
|
|||||||
|
|
||||||
/*// Test PWM + weighting of RGB*/
|
/*// Test PWM + weighting of RGB*/
|
||||||
/*led_test_colors();*/
|
/*led_test_colors();*/
|
||||||
|
fifo_test();
|
||||||
|
|
||||||
|
|
||||||
uint32_t t0 = millis();
|
uint32_t t0 = millis();
|
||||||
@ -90,14 +243,9 @@ int main(void)
|
|||||||
fifo_hidmsg_take(hidbuf);
|
fifo_hidmsg_take(hidbuf);
|
||||||
dump_hex(hidbuf, HID_PACKET_SIZE);
|
dump_hex(hidbuf, HID_PACKET_SIZE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _Error_Handler(char *file, int line)
|
|
||||||
{
|
|
||||||
printf("Error: %s: %d\r\n", file, line);
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -1,40 +1,23 @@
|
|||||||
#include "stm32l4xx_ll_usart.h"
|
#include "stm32l4xx_ll_usart.h"
|
||||||
|
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
|
||||||
int WRITE_PTR = 0;
|
#if DEBUG_LEVEL>0
|
||||||
int READ_PTR = 0;
|
|
||||||
#define BUF_SIZE 20000
|
|
||||||
static uint8_t WRITE_BUF[BUF_SIZE];
|
|
||||||
|
|
||||||
void add2buf(uint8_t c)
|
|
||||||
{
|
|
||||||
WRITE_BUF[WRITE_PTR++] = c;
|
|
||||||
if (WRITE_PTR >= BUF_SIZE)
|
|
||||||
WRITE_PTR = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t takebuf()
|
|
||||||
{
|
|
||||||
uint8_t c;
|
|
||||||
c = WRITE_BUF[READ_PTR++];
|
|
||||||
if (READ_PTR >= BUF_SIZE)
|
|
||||||
READ_PTR = 0;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bufavail()
|
|
||||||
{
|
|
||||||
return (READ_PTR < WRITE_PTR);
|
|
||||||
}
|
|
||||||
void _putchar(char c)
|
void _putchar(char c)
|
||||||
{
|
{
|
||||||
// add2buf(c);
|
#if NON_BLOCK_PRINTING
|
||||||
|
fifo_debug_add(&c);
|
||||||
|
#else
|
||||||
while (! LL_USART_IsActiveFlag_TXE(DEBUG_UART))
|
while (! LL_USART_IsActiveFlag_TXE(DEBUG_UART))
|
||||||
;
|
;
|
||||||
LL_USART_TransmitData8(DEBUG_UART,c);
|
LL_USART_TransmitData8(DEBUG_UART,c);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _write (int fd, const void *buf, long int len)
|
int _write (int fd, const void *buf, long int len)
|
||||||
{
|
{
|
||||||
uint8_t * data = (uint8_t *) buf;
|
uint8_t * data = (uint8_t *) buf;
|
||||||
@ -43,4 +26,6 @@ int _write (int fd, const void *buf, long int len)
|
|||||||
_putchar(*data++);
|
_putchar(*data++);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "stm32l4xx_ll_rng.h"
|
#include "stm32l4xx_ll_rng.h"
|
||||||
|
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
int __errno = 0;
|
int __errno = 0;
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ void rng_get_bytes(uint8_t * dst, size_t sz)
|
|||||||
|
|
||||||
if (RNG->SR & 0x66)
|
if (RNG->SR & 0x66)
|
||||||
{
|
{
|
||||||
printf("Error RNG: %02lx\r\n", RNG->SR);
|
printf2(TAG_ERR,"Error RNG: %02lx\r\n", RNG->SR);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
|
|||||||
/* Specify the memory areas */
|
/* Specify the memory areas */
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
|
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 238K /* Leave out 18 Kb for data */
|
||||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
|
||||||
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
SRAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
@ -199,5 +199,3 @@ SECTIONS
|
|||||||
|
|
||||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ class Tester():
|
|||||||
self.origin = 'https://examplo.org'
|
self.origin = 'https://examplo.org'
|
||||||
|
|
||||||
def find_device(self,):
|
def find_device(self,):
|
||||||
|
print (list(CtapHidDevice.list_devices()))
|
||||||
dev = next(CtapHidDevice.list_devices(), None)
|
dev = next(CtapHidDevice.list_devices(), None)
|
||||||
if not dev:
|
if not dev:
|
||||||
raise RuntimeError('No FIDO device found')
|
raise RuntimeError('No FIDO device found')
|
||||||
@ -118,7 +119,6 @@ class Tester():
|
|||||||
|
|
||||||
def test_long_ping(self):
|
def test_long_ping(self):
|
||||||
amt = 1000
|
amt = 1000
|
||||||
while 1 :
|
|
||||||
pingdata = os.urandom(amt)
|
pingdata = os.urandom(amt)
|
||||||
try:
|
try:
|
||||||
t1 = time.time() * 1000
|
t1 = time.time() * 1000
|
||||||
@ -140,12 +140,13 @@ class Tester():
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
def test_hid(self,):
|
def test_hid(self,check_timeouts = False):
|
||||||
#print('Test idle')
|
if check_timeouts:
|
||||||
#try:
|
print('Test idle')
|
||||||
#cmd,resp = self.recv_raw()
|
try:
|
||||||
#except socket.timeout:
|
cmd,resp = self.recv_raw()
|
||||||
#print('Pass: Idle')
|
except socket.timeout:
|
||||||
|
print('Pass: Idle')
|
||||||
|
|
||||||
print('Test init')
|
print('Test init')
|
||||||
r = self.send_data(CTAPHID.INIT, '\x11\x11\x11\x11\x11\x11\x11\x11')
|
r = self.send_data(CTAPHID.INIT, '\x11\x11\x11\x11\x11\x11\x11\x11')
|
||||||
@ -216,18 +217,19 @@ class Tester():
|
|||||||
self.check_error(resp, CtapError.ERR.INVALID_LENGTH)
|
self.check_error(resp, CtapError.ERR.INVALID_LENGTH)
|
||||||
print('PASS: invalid length')
|
print('PASS: invalid length')
|
||||||
|
|
||||||
#r = self.send_data(CTAPHID.PING, '\x44'*200)
|
r = self.send_data(CTAPHID.PING, '\x44'*200)
|
||||||
#print('Sending packets that skip a sequence number.')
|
print('Sending packets that skip a sequence number.')
|
||||||
#self.send_raw('\x81\x04\x90')
|
self.send_raw('\x81\x04\x90')
|
||||||
#self.send_raw('\x00')
|
self.send_raw('\x00')
|
||||||
#self.send_raw('\x01')
|
self.send_raw('\x01')
|
||||||
## skip 2
|
# skip 2
|
||||||
#self.send_raw('\x03')
|
self.send_raw('\x03')
|
||||||
#cmd,resp = self.recv_raw()
|
cmd,resp = self.recv_raw()
|
||||||
#self.check_error(resp, CtapError.ERR.INVALID_SEQ)
|
self.check_error(resp, CtapError.ERR.INVALID_SEQ)
|
||||||
#cmd,resp = self.recv_raw()
|
if check_timeouts:
|
||||||
#assert(cmd == 0xbf) # timeout
|
cmd,resp = self.recv_raw()
|
||||||
#print('PASS: invalid sequence')
|
assert(cmd == 0xbf) # timeout
|
||||||
|
print('PASS: invalid sequence')
|
||||||
|
|
||||||
print('Resync and send ping')
|
print('Resync and send ping')
|
||||||
try:
|
try:
|
||||||
@ -262,13 +264,13 @@ class Tester():
|
|||||||
cmd,r = self.recv_raw() # init response
|
cmd,r = self.recv_raw() # init response
|
||||||
assert(cmd == 0x86)
|
assert(cmd == 0x86)
|
||||||
self.set_cid(oldcid)
|
self.set_cid(oldcid)
|
||||||
|
if check_timeouts:
|
||||||
#print('wait for timeout')
|
#print('wait for timeout')
|
||||||
#cmd,r = self.recv_raw() # timeout response
|
cmd,r = self.recv_raw() # timeout response
|
||||||
#assert(cmd == 0xbf)
|
assert(cmd == 0xbf)
|
||||||
|
|
||||||
print('PASS: resync and timeout')
|
print('PASS: resync and timeout')
|
||||||
|
|
||||||
|
|
||||||
print('Test timeout')
|
print('Test timeout')
|
||||||
self.send_data(CTAPHID.INIT, '\x11\x22\x33\x44\x55\x66\x77\x88')
|
self.send_data(CTAPHID.INIT, '\x11\x22\x33\x44\x55\x66\x77\x88')
|
||||||
t1 = time.time() * 1000
|
t1 = time.time() * 1000
|
||||||
@ -294,13 +296,14 @@ class Tester():
|
|||||||
assert(r[0] == CtapError.ERR.INVALID_SEQ)
|
assert(r[0] == CtapError.ERR.INVALID_SEQ)
|
||||||
print('PASS: Test not cont')
|
print('PASS: Test not cont')
|
||||||
|
|
||||||
|
if check_timeouts:
|
||||||
print('Check random cont ignored')
|
print('Check random cont ignored')
|
||||||
#self.send_data(CTAPHID.INIT, '\x11\x22\x33\x44\x55\x66\x77\x88')
|
self.send_data(CTAPHID.INIT, '\x11\x22\x33\x44\x55\x66\x77\x88')
|
||||||
#self.send_raw('\x01\x10\x00')
|
self.send_raw('\x01\x10\x00')
|
||||||
#try:
|
try:
|
||||||
#cmd,r = self.recv_raw() # timeout response
|
cmd,r = self.recv_raw() # timeout response
|
||||||
#except socket.timeout:
|
except socket.timeout:
|
||||||
#pass
|
pass
|
||||||
print('PASS: random cont')
|
print('PASS: random cont')
|
||||||
|
|
||||||
print('Check busy')
|
print('Check busy')
|
||||||
@ -336,11 +339,13 @@ class Tester():
|
|||||||
self.send_raw('\x81\x00\x63')
|
self.send_raw('\x81\x00\x63')
|
||||||
self.send_raw('\x00')
|
self.send_raw('\x00')
|
||||||
|
|
||||||
|
cmd,r = self.recv_raw() # busy response
|
||||||
|
|
||||||
self.set_cid(cid1) # finish 1st channel ping
|
self.set_cid(cid1) # finish 1st channel ping
|
||||||
self.send_raw('\x00')
|
self.send_raw('\x00')
|
||||||
|
|
||||||
self.set_cid(cid2)
|
self.set_cid(cid2)
|
||||||
cmd,r = self.recv_raw() # busy response
|
|
||||||
assert(cmd == 0xbf)
|
assert(cmd == 0xbf)
|
||||||
assert(r[0] == CtapError.ERR.CHANNEL_BUSY)
|
assert(r[0] == CtapError.ERR.CHANNEL_BUSY)
|
||||||
|
|
||||||
@ -349,12 +354,13 @@ class Tester():
|
|||||||
assert(cmd == 0x81)
|
assert(cmd == 0x81)
|
||||||
assert(len(r) == 0x63)
|
assert(len(r) == 0x63)
|
||||||
|
|
||||||
#cmd,r = self.recv_raw() # timeout
|
if check_timeouts:
|
||||||
#assert(cmd == 0xbf)
|
cmd,r = self.recv_raw() # timeout
|
||||||
#assert(r[0] == CtapError.ERR.TIMEOUT)
|
assert(cmd == 0xbf)
|
||||||
|
assert(r[0] == CtapError.ERR.TIMEOUT)
|
||||||
print('PASS: busy interleaved')
|
print('PASS: busy interleaved')
|
||||||
|
|
||||||
|
if check_timeouts:
|
||||||
print('Test idle, wait for timeout')
|
print('Test idle, wait for timeout')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
try:
|
try:
|
||||||
@ -381,13 +387,13 @@ class Tester():
|
|||||||
def test_u2f(self,):
|
def test_u2f(self,):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_fido2_simple(self):
|
def test_fido2_simple(self, pin_token=None):
|
||||||
creds = []
|
creds = []
|
||||||
exclude_list = []
|
exclude_list = []
|
||||||
rp = {'id': 'examplo.org', 'name': 'ExaRP'}
|
rp = {'id': 'examplo.org', 'name': 'ExaRP'}
|
||||||
user = {'id': b'usee_od', 'name': 'AB User'}
|
user = {'id': b'usee_od', 'name': 'AB User'}
|
||||||
challenge = 'Y2hhbGxlbmdl'
|
challenge = 'Y2hhbGxlbmdl'
|
||||||
PIN = None
|
PIN = pin_token
|
||||||
|
|
||||||
fake_id1 = array.array('B',[randint(0,255) for i in range(0,150)]).tostring()
|
fake_id1 = array.array('B',[randint(0,255) for i in range(0,150)]).tostring()
|
||||||
fake_id2 = array.array('B',[randint(0,255) for i in range(0,73)]).tostring()
|
fake_id2 = array.array('B',[randint(0,255) for i in range(0,73)]).tostring()
|
||||||
@ -482,6 +488,7 @@ class Tester():
|
|||||||
attest.verify(data.hash)
|
attest.verify(data.hash)
|
||||||
cred = attest.auth_data.credential_data
|
cred = attest.auth_data.credential_data
|
||||||
creds.append(cred)
|
creds.append(cred)
|
||||||
|
print(cred)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
if PIN is not None:
|
if PIN is not None:
|
||||||
@ -505,14 +512,18 @@ class Tester():
|
|||||||
real_excl = [{'id': cred.credential_id, 'type': 'public-key'}]
|
real_excl = [{'id': cred.credential_id, 'type': 'public-key'}]
|
||||||
try:
|
try:
|
||||||
attest, data = self.client.make_credential(rp, user, challenge, pin = PIN, exclude_list = exclude_list + real_excl)
|
attest, data = self.client.make_credential(rp, user, challenge, pin = PIN, exclude_list = exclude_list + real_excl)
|
||||||
|
raise RuntimeError('Exclude list did not return expected error')
|
||||||
except CtapError as e:
|
except CtapError as e:
|
||||||
assert(e.code == CtapError.ERR.CREDENTIAL_EXCLUDED)
|
assert(e.code == CtapError.ERR.CREDENTIAL_EXCLUDED)
|
||||||
|
except ClientError as e:
|
||||||
|
assert(e.cause.code == CtapError.ERR.CREDENTIAL_EXCLUDED)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
print('get assertion')
|
for i, x in enumerate(creds):
|
||||||
allow_list = [{'id':creds[0].credential_id, 'type': 'public-key'}]
|
print('get assertion %d' % i)
|
||||||
|
allow_list = [{'id':x.credential_id, 'type': 'public-key'}]
|
||||||
assertions, client_data = self.client.get_assertion(rp['id'], challenge, allow_list, pin = PIN)
|
assertions, client_data = self.client.get_assertion(rp['id'], challenge, allow_list, pin = PIN)
|
||||||
assertions[0].verify(client_data.hash, creds[0].public_key)
|
assertions[0].verify(client_data.hash, x.public_key)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
if PIN is not None:
|
if PIN is not None:
|
||||||
@ -525,11 +536,16 @@ class Tester():
|
|||||||
assert(e.cause.code == CtapError.ERR.PIN_INVALID)
|
assert(e.cause.code == CtapError.ERR.PIN_INVALID)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
|
|
||||||
print('get multiple assertions')
|
print('get multiple assertions')
|
||||||
allow_list = [{'id': x.credential_id, 'type': 'public-key'} for x in creds]
|
allow_list = [{'id': x.credential_id, 'type': 'public-key'} for x in creds]
|
||||||
assertions, client_data = self.client.get_assertion(rp['id'], challenge, allow_list, pin = PIN)
|
assertions, client_data = self.client.get_assertion(rp['id'], challenge, allow_list, pin = PIN)
|
||||||
|
|
||||||
for ass,cred in zip(assertions, creds):
|
for ass,cred in zip(assertions, creds):
|
||||||
|
i += 1
|
||||||
|
|
||||||
ass.verify(client_data.hash, cred.public_key)
|
ass.verify(client_data.hash, cred.public_key)
|
||||||
|
print('%d verified' % i)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
print('Reset device')
|
print('Reset device')
|
||||||
@ -567,6 +583,20 @@ class Tester():
|
|||||||
assert(e.code == CtapError.ERR.PIN_INVALID)
|
assert(e.code == CtapError.ERR.PIN_INVALID)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
|
print('MC using wrong pin')
|
||||||
|
try:
|
||||||
|
self.test_fido2_simple('abcd3');
|
||||||
|
except CtapError as e:
|
||||||
|
assert(e.code == CtapError.ERR.PIN_INVALID)
|
||||||
|
except ClientError as e:
|
||||||
|
assert(e.cause.code == CtapError.ERR.PIN_INVALID)
|
||||||
|
print('PASS')
|
||||||
|
|
||||||
|
print('Reboot device and hit enter')
|
||||||
|
input()
|
||||||
|
self.find_device()
|
||||||
|
self.test_fido2_simple(PIN);
|
||||||
|
|
||||||
print('Re-run make_credential and get_assertion tests with pin code')
|
print('Re-run make_credential and get_assertion tests with pin code')
|
||||||
test(self, PIN)
|
test(self, PIN)
|
||||||
|
|
||||||
@ -577,7 +607,6 @@ class Tester():
|
|||||||
print('Warning, reset failed: ', e)
|
print('Warning, reset failed: ', e)
|
||||||
print('PASS')
|
print('PASS')
|
||||||
|
|
||||||
|
|
||||||
def test_find_brute_force():
|
def test_find_brute_force():
|
||||||
i = 0
|
i = 0
|
||||||
while 1:
|
while 1:
|
||||||
@ -598,7 +627,4 @@ if __name__ == '__main__':
|
|||||||
t.test_fido2()
|
t.test_fido2()
|
||||||
# test_find_brute_force()
|
# test_find_brute_force()
|
||||||
#t.test_fido2_simple()
|
#t.test_fido2_simple()
|
||||||
t.test_fido2_brute_force()
|
#t.test_fido2_brute_force()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
import base64
|
||||||
"""
|
"""
|
||||||
cbytes.py
|
cbytes.py
|
||||||
|
|
||||||
@ -39,4 +40,6 @@ print()
|
|||||||
print('code uint8_t __attest[] = \n%s;' % c_str)
|
print('code uint8_t __attest[] = \n%s;' % c_str)
|
||||||
print('const uint16_t __attest_size = sizeof(__attest)-1;')
|
print('const uint16_t __attest_size = sizeof(__attest)-1;')
|
||||||
|
|
||||||
|
b = base64.b64encode(buf)
|
||||||
|
print('b64: ')
|
||||||
|
print(b)
|
||||||
|
22
tools/gencert/gen_intermediate.sh
Normal file
22
tools/gencert/gen_intermediate.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
keyname=interkey.pem
|
||||||
|
certname=intercert.pem
|
||||||
|
smallcertname=intercert.der
|
||||||
|
curve=prime256v1
|
||||||
|
|
||||||
|
[[ "$#" != 2 ]] && echo "usage: $0 <signing-key> <root-ca>" && exit 1
|
||||||
|
|
||||||
|
# generate EC private key
|
||||||
|
openssl ecparam -genkey -name "$curve" -out "$keyname" -rand seed.txt
|
||||||
|
|
||||||
|
# generate a "signing request"
|
||||||
|
openssl req -new -key "$keyname" -out "$keyname".csr -subj "/C=US/ST=Maryland/O=Solo Keys/OU=Authenticator Attestation/CN=solokeys.com/emailAddress=hello@solokeys.com"
|
||||||
|
|
||||||
|
# sign the request
|
||||||
|
openssl x509 -req -days 18250 -in "$keyname".csr -extfile v3.ext -CA "$2" -CAkey "$1" -set_serial 01 -out "$certname" -sha256
|
||||||
|
|
||||||
|
# convert to smaller size format DER
|
||||||
|
openssl x509 -in $certname -outform der -out $smallcertname
|
||||||
|
|
||||||
|
openssl x509 -in $certname -text -noout
|
@ -6,12 +6,13 @@ smallcertname=cert.der
|
|||||||
curve=prime256v1
|
curve=prime256v1
|
||||||
|
|
||||||
# generate EC private key
|
# generate EC private key
|
||||||
openssl ecparam -genkey -name "$curve" -out "$keyname"
|
openssl ecparam -genkey -name "$curve" -out "$keyname" -rand seed.txt
|
||||||
# generate a "signing request"
|
# generate a "signing request"
|
||||||
openssl req -new -key "$keyname" -out "$keyname".csr
|
openssl req -new -key "$keyname" -out "$keyname".csr -subj "/C=US/ST=Maryland/O=Solo Keys/OU=Root CA/CN=solokeys.com/emailAddress=hello@solokeys.com"
|
||||||
# self sign the request
|
# self sign the request
|
||||||
openssl x509 -req -days 18250 -in "$keyname".csr -signkey "$keyname" -out "$certname"
|
openssl x509 -trustout -req -days 18250 -in "$keyname".csr -signkey "$keyname" -out "$certname" -sha256
|
||||||
|
|
||||||
# convert to smaller size format DER
|
# convert to smaller size format DER
|
||||||
openssl x509 -in $certname -outform der -out $smallcertname
|
openssl x509 -in $certname -outform der -out $smallcertname
|
||||||
|
|
||||||
|
openssl x509 -in $certname -text -noout
|
||||||
|
16
tools/gencert/print_x_y.py
Normal file
16
tools/gencert/print_x_y.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import sys
|
||||||
|
from ecdsa import SigningKey, NIST256p
|
||||||
|
|
||||||
|
sk = SigningKey.from_pem(open(sys.argv[1]).read())
|
||||||
|
|
||||||
|
|
||||||
|
print('Private key in various formats:')
|
||||||
|
print()
|
||||||
|
print([c for c in sk.to_string()])
|
||||||
|
print()
|
||||||
|
print(''.join(['%02x'%c for c in sk.to_string()]))
|
||||||
|
print()
|
||||||
|
print('"\\x' + '\\x'.join(['%02x'%c for c in sk.to_string()]) + '"')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
22
tools/gencert/verify_certs.sh
Normal file
22
tools/gencert/verify_certs.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
# verify that the root CA/keypair and intermediate CA/keypairs are set up correctly.
|
||||||
|
|
||||||
|
[[ "$#" != 4 ]] && echo "usage: $0 <inter-key> <inter-cert> <root-key> <root-cert>" && exit 1
|
||||||
|
|
||||||
|
ikey=$1
|
||||||
|
icert=$2
|
||||||
|
|
||||||
|
rkey=$3
|
||||||
|
rcert=$4
|
||||||
|
|
||||||
|
echo 'challenge $RANDOM' > chal.txt
|
||||||
|
|
||||||
|
# check that they are actual key pairs
|
||||||
|
openssl dgst -sha256 -sign "$ikey" -out sig.txt chal.txt
|
||||||
|
openssl dgst -sha256 -verify <(openssl x509 -in "$icert" -pubkey -noout) -signature sig.txt chal.txt
|
||||||
|
|
||||||
|
openssl dgst -sha256 -sign "$rkey" -out sig.txt chal.txt
|
||||||
|
openssl dgst -sha256 -verify <(openssl x509 -in "$rcert" -pubkey -noout) -signature sig.txt chal.txt
|
||||||
|
|
||||||
|
# Check they are a chain
|
||||||
|
openssl verify -verbose -CAfile "$rcert" "$icert"
|
Loading…
x
Reference in New Issue
Block a user