move things around and add efm8 and efm32 builds
This commit is contained in:
16
fido2/cose_key.h
Normal file
16
fido2/cose_key.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef _COSE_KEY_H
|
||||
#define _COSE_KEY_H
|
||||
|
||||
#define COSE_KEY_LABEL_KTY 1
|
||||
#define COSE_KEY_LABEL_ALG 3
|
||||
#define COSE_KEY_LABEL_CRV -1
|
||||
#define COSE_KEY_LABEL_X -2
|
||||
#define COSE_KEY_LABEL_Y -3
|
||||
|
||||
#define COSE_KEY_KTY_EC2 2
|
||||
#define COSE_KEY_CRV_P256 1
|
||||
|
||||
|
||||
#define COSE_ALG_ES256 -7
|
||||
|
||||
#endif
|
285
fido2/crypto.c
Normal file
285
fido2/crypto.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
|
||||
const uint8_t attestation_cert_der[];
|
||||
const uint16_t attestation_cert_der_size;
|
||||
const uint8_t attestation_key[];
|
||||
const uint16_t attestation_key_size;
|
||||
|
||||
|
||||
|
||||
static SHA256_CTX sha256_ctx;
|
||||
static const struct uECC_Curve_t * _es256_curve = NULL;
|
||||
static const uint8_t * _signing_key = NULL;
|
||||
|
||||
// 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"
|
||||
"\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"
|
||||
"\xff\xee\x8d\x1c\x3b\xfa\x99\x88\x77\x86\x55\x44\xd3\xff\x33\x00";
|
||||
|
||||
|
||||
|
||||
void crypto_sha256_init()
|
||||
{
|
||||
sha256_init(&sha256_ctx);
|
||||
}
|
||||
|
||||
void crypto_reset_master_secret()
|
||||
{
|
||||
ctap_generate_rng(master_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);
|
||||
}
|
||||
|
||||
if(klen > 64)
|
||||
{
|
||||
printf("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);
|
||||
}
|
||||
|
||||
|
||||
if(klen > 64)
|
||||
{
|
||||
printf("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;
|
||||
}
|
||||
|
||||
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
||||
{
|
||||
if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
|
||||
{
|
||||
printf("error, uECC failed\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);
|
||||
crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
|
||||
}
|
||||
|
||||
|
||||
/*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_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;
|
||||
}
|
||||
|
||||
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
|
||||
{
|
||||
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
||||
{
|
||||
printf("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)
|
||||
{
|
||||
printf("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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
#else
|
||||
#error "No crypto implementation defined"
|
||||
#endif
|
||||
|
||||
|
48
fido2/crypto.h
Normal file
48
fido2/crypto.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef _CRYPTO_H
|
||||
#define _CRYPTO_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define USE_SOFTWARE_IMPLEMENTATION
|
||||
|
||||
void crypto_sha256_init();
|
||||
void crypto_sha256_update(uint8_t * data, size_t len);
|
||||
void crypto_sha256_update_secret();
|
||||
void crypto_sha256_final(uint8_t * hash);
|
||||
|
||||
void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac);
|
||||
void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac);
|
||||
|
||||
|
||||
void crypto_ecc256_init();
|
||||
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y);
|
||||
|
||||
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2);
|
||||
void crypto_ecc256_load_attestation_key();
|
||||
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig);
|
||||
|
||||
|
||||
void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, 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);
|
||||
|
||||
// Key must be 32 bytes
|
||||
#define CRYPTO_TRANSPORT_KEY NULL
|
||||
#define CRYPTO_MASTER_KEY NULL
|
||||
|
||||
void crypto_aes256_init(uint8_t * key, uint8_t * nonce);
|
||||
void crypto_aes256_reset_iv(uint8_t * nonce);
|
||||
|
||||
// buf length must be multiple of 16 bytes
|
||||
void crypto_aes256_decrypt(uint8_t * buf, int lenth);
|
||||
void crypto_aes256_encrypt(uint8_t * buf, int lenth);
|
||||
|
||||
void crypto_reset_master_secret();
|
||||
|
||||
|
||||
extern const uint8_t attestation_cert_der[];
|
||||
extern const uint16_t attestation_cert_der_size;
|
||||
|
||||
|
||||
|
||||
#endif
|
1299
fido2/ctap.c
Normal file
1299
fido2/ctap.c
Normal file
File diff suppressed because it is too large
Load Diff
264
fido2/ctap.h
Normal file
264
fido2/ctap.h
Normal file
@@ -0,0 +1,264 @@
|
||||
#ifndef _CTAP_H
|
||||
#define _CTAP_H
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
|
||||
#define CTAP_MAKE_CREDENTIAL 0x01
|
||||
#define CTAP_GET_ASSERTION 0x02
|
||||
#define CTAP_CANCEL 0x03
|
||||
#define CTAP_GET_INFO 0x04
|
||||
#define CTAP_CLIENT_PIN 0x06
|
||||
#define CTAP_RESET 0x07
|
||||
#define GET_NEXT_ASSERTION 0x08
|
||||
#define CTAP_VENDOR_FIRST 0x40
|
||||
#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")
|
||||
|
||||
#define MC_clientDataHash 0x01
|
||||
#define MC_rp 0x02
|
||||
#define MC_user 0x03
|
||||
#define MC_pubKeyCredParams 0x04
|
||||
#define MC_excludeList 0x05
|
||||
#define MC_extensions 0x06
|
||||
#define MC_options 0x07
|
||||
#define MC_pinAuth 0x08
|
||||
#define MC_pinProtocol 0x09
|
||||
|
||||
#define GA_rpId 0x01
|
||||
#define GA_clientDataHash 0x02
|
||||
#define GA_allowList 0x03
|
||||
#define GA_extensions 0x04
|
||||
#define GA_options 0x05
|
||||
#define GA_pinAuth 0x06
|
||||
#define GA_pinProtocol 0x07
|
||||
|
||||
#define CP_pinProtocol 0x01
|
||||
#define CP_subCommand 0x02
|
||||
#define CP_cmdGetRetries 0x01
|
||||
#define CP_cmdGetKeyAgreement 0x02
|
||||
#define CP_cmdSetPin 0x03
|
||||
#define CP_cmdChangePin 0x04
|
||||
#define CP_cmdGetPinToken 0x05
|
||||
#define CP_keyAgreement 0x03
|
||||
#define CP_pinAuth 0x04
|
||||
#define CP_newPinEnc 0x05
|
||||
#define CP_pinHashEnc 0x06
|
||||
#define CP_getKeyAgreement 0x07
|
||||
#define CP_getRetries 0x08
|
||||
|
||||
#define RESP_versions 0x1
|
||||
#define RESP_extensions 0x2
|
||||
#define RESP_aaguid 0x3
|
||||
#define RESP_options 0x4
|
||||
#define RESP_maxMsgSize 0x5
|
||||
#define RESP_pinProtocols 0x6
|
||||
|
||||
#define RESP_fmt 0x01
|
||||
#define RESP_authData 0x02
|
||||
#define RESP_attStmt 0x03
|
||||
|
||||
#define RESP_credential 0x01
|
||||
#define RESP_signature 0x03
|
||||
#define RESP_publicKeyCredentialUserEntity 0x04
|
||||
#define RESP_numberOfCredentials 0x05
|
||||
|
||||
#define RESP_keyAgreement 0x01
|
||||
#define RESP_pinToken 0x02
|
||||
#define RESP_retries 0x03
|
||||
|
||||
#define PARAM_clientDataHash (1 << 0)
|
||||
#define PARAM_rp (1 << 1)
|
||||
#define PARAM_user (1 << 2)
|
||||
#define PARAM_pubKeyCredParams (1 << 3)
|
||||
#define PARAM_excludeList (1 << 4)
|
||||
#define PARAM_extensions (1 << 5)
|
||||
#define PARAM_options (1 << 6)
|
||||
#define PARAM_pinAuth (1 << 7)
|
||||
#define PARAM_pinProtocol (1 << 8)
|
||||
#define PARAM_rpId (1 << 9)
|
||||
#define PARAM_allowList (1 << 10)
|
||||
|
||||
#define MC_requiredMask (0x0f)
|
||||
|
||||
|
||||
#define CLIENT_DATA_HASH_SIZE 32 //sha256 hash
|
||||
#define DOMAIN_NAME_MAX_SIZE 253
|
||||
#define RP_NAME_LIMIT 32 // application limit, name parameter isn't needed.
|
||||
#define USER_ID_MAX_SIZE 64
|
||||
#define USER_NAME_LIMIT 65 // Must be minimum of 64 bytes but can be more.
|
||||
#define CTAP_MAX_MESSAGE_SIZE 1024
|
||||
|
||||
#define CREDENTIAL_TAG_SIZE 16
|
||||
#define CREDENTIAL_NONCE_SIZE 8
|
||||
#define CREDENTIAL_COUNTER_SIZE (4)
|
||||
#define CREDENTIAL_ENC_SIZE 144 // pad to multiple of 16 bytes
|
||||
#define CREDENTIAL_PAD_SIZE (CREDENTIAL_ENC_SIZE - (USER_ID_MAX_SIZE + USER_NAME_LIMIT + CREDENTIAL_COUNTER_SIZE + 1))
|
||||
#define CREDENTIAL_ID_SIZE (CREDENTIAL_TAG_SIZE + CREDENTIAL_NONCE_SIZE + CREDENTIAL_ENC_SIZE)
|
||||
|
||||
#define PUB_KEY_CRED_PUB_KEY 0x01
|
||||
#define PUB_KEY_CRED_UNKNOWN 0x3F
|
||||
|
||||
#define CREDENTIAL_IS_SUPPORTED 1
|
||||
#define CREDENTIAL_NOT_SUPPORTED 0
|
||||
|
||||
#define ALLOW_LIST_MAX_SIZE 20
|
||||
|
||||
#define NEW_PIN_ENC_MAX_SIZE 256 // includes NULL terminator
|
||||
|
||||
#define CTAP_RESPONSE_BUFFER_SIZE 1024
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id[USER_ID_MAX_SIZE];
|
||||
uint8_t id_size;
|
||||
uint8_t name[USER_NAME_LIMIT];
|
||||
}__attribute__((packed)) CTAP_userEntity;
|
||||
|
||||
struct Credential {
|
||||
uint8_t tag[CREDENTIAL_TAG_SIZE];
|
||||
uint8_t nonce[CREDENTIAL_NONCE_SIZE];
|
||||
struct {
|
||||
CTAP_userEntity user;
|
||||
uint32_t count;
|
||||
uint8_t _pad[CREDENTIAL_PAD_SIZE];
|
||||
} __attribute__((packed)) enc;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t aaguid[16];
|
||||
uint8_t credLenH;
|
||||
uint8_t credLenL;
|
||||
struct Credential credential;
|
||||
} __attribute__((packed)) CTAP_attestHeader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rpIdHash[32];
|
||||
uint8_t flags;
|
||||
uint32_t signCount;
|
||||
} __attribute__((packed)) CTAP_authDataHeader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CTAP_authDataHeader head;
|
||||
CTAP_attestHeader attest;
|
||||
} __attribute__((packed)) CTAP_authData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t data[CTAP_RESPONSE_BUFFER_SIZE];
|
||||
uint16_t data_size;
|
||||
uint16_t length;
|
||||
} CTAP_RESPONSE;
|
||||
|
||||
struct rpId
|
||||
{
|
||||
uint8_t id[DOMAIN_NAME_MAX_SIZE + 1]; // extra for NULL termination
|
||||
size_t size;
|
||||
uint8_t name[RP_NAME_LIMIT];
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t paramsParsed;
|
||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||
struct rpId rp;
|
||||
CTAP_userEntity user;
|
||||
|
||||
uint8_t publicKeyCredentialType;
|
||||
int32_t COSEAlgorithmIdentifier;
|
||||
|
||||
CborValue excludeList;
|
||||
size_t excludeListSize;
|
||||
|
||||
uint8_t rk;
|
||||
uint8_t uv;
|
||||
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
int pinProtocol;
|
||||
|
||||
} CTAP_makeCredential;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type;
|
||||
struct Credential credential;
|
||||
} CTAP_credentialDescriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t paramsParsed;
|
||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||
|
||||
struct rpId rp;
|
||||
|
||||
int credLen;
|
||||
|
||||
uint8_t rk;
|
||||
uint8_t uv;
|
||||
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
int pinProtocol;
|
||||
|
||||
CTAP_credentialDescriptor creds[ALLOW_LIST_MAX_SIZE];
|
||||
} CTAP_getAssertion;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int pinProtocol;
|
||||
int subCommand;
|
||||
struct
|
||||
{
|
||||
struct{
|
||||
uint8_t x[32];
|
||||
uint8_t y[32];
|
||||
} pubkey;
|
||||
|
||||
int kty;
|
||||
int crv;
|
||||
} keyAgreement;
|
||||
uint8_t keyAgreementPresent;
|
||||
uint8_t pinAuth[16];
|
||||
uint8_t pinAuthPresent;
|
||||
uint8_t newPinEnc[NEW_PIN_ENC_MAX_SIZE];
|
||||
int newPinEncSize;
|
||||
uint8_t pinHashEnc[16];
|
||||
uint8_t pinHashEncPresent;
|
||||
_Bool getKeyAgreement;
|
||||
_Bool getRetries;
|
||||
} CTAP_clientPin;
|
||||
|
||||
|
||||
void ctap_response_init(CTAP_RESPONSE * resp);
|
||||
|
||||
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);
|
||||
|
||||
// Encodes R,S signature to 2 der sequence of two integers. Sigder must be at least 72 bytes.
|
||||
// @return length of der signature
|
||||
int ctap_encode_der_sig(uint8_t * sigbuf, uint8_t * sigder);
|
||||
|
||||
// Run ctap related power-up procedures (init pinToken, generate shared secret)
|
||||
void ctap_init();
|
||||
|
||||
// Resets state between different accesses of different applications
|
||||
void ctap_reset_state();
|
||||
|
||||
void ctap_update_pin(uint8_t * pin, int len);
|
||||
uint8_t ctap_decrement_pin_attempts();
|
||||
int8_t ctap_leftover_pin_attempts();
|
||||
void ctap_reset_pin_attempts();
|
||||
uint8_t ctap_is_pin_set();
|
||||
uint8_t ctap_pin_matches(uint8_t * pin, int len);
|
||||
void ctap_reset();
|
||||
int8_t ctap_device_locked();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
51
fido2/ctap_errors.h
Normal file
51
fido2/ctap_errors.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#define CTAP1_ERR_SUCCESS 0x00
|
||||
#define CTAP1_ERR_INVALID_COMMAND 0x01
|
||||
#define CTAP1_ERR_INVALID_PARAMETER 0x02
|
||||
#define CTAP1_ERR_INVALID_LENGTH 0x03
|
||||
#define CTAP1_ERR_INVALID_SEQ 0x04
|
||||
#define CTAP1_ERR_TIMEOUT 0x05
|
||||
#define CTAP1_ERR_CHANNEL_BUSY 0x06
|
||||
#define CTAP1_ERR_LOCK_REQUIRED 0x0A
|
||||
#define CTAP1_ERR_INVALID_CHANNEL 0x0B
|
||||
#define CTAP2_ERR_CBOR_PARSING 0x10
|
||||
#define CTAP2_ERR_CBOR_UNEXPECTED_TYPE 0x11
|
||||
#define CTAP2_ERR_INVALID_CBOR 0x12
|
||||
#define CTAP2_ERR_INVALID_CBOR_TYPE 0x13
|
||||
#define CTAP2_ERR_MISSING_PARAMETER 0x14
|
||||
#define CTAP2_ERR_LIMIT_EXCEEDED 0x15
|
||||
#define CTAP2_ERR_UNSUPPORTED_EXTENSION 0x16
|
||||
#define CTAP2_ERR_TOO_MANY_ELEMENTS 0x17
|
||||
#define CTAP2_ERR_EXTENSION_NOT_SUPPORTED 0x18
|
||||
#define CTAP2_ERR_CREDENTIAL_EXCLUDED 0x19
|
||||
#define CTAP2_ERR_CREDENTIAL_NOT_VALID 0x20
|
||||
#define CTAP2_ERR_PROCESSING 0x21
|
||||
#define CTAP2_ERR_INVALID_CREDENTIAL 0x22
|
||||
#define CTAP2_ERR_USER_ACTION_PENDING 0x23
|
||||
#define CTAP2_ERR_OPERATION_PENDING 0x24
|
||||
#define CTAP2_ERR_NO_OPERATIONS 0x25
|
||||
#define CTAP2_ERR_UNSUPPORTED_ALGORITHM 0x26
|
||||
#define CTAP2_ERR_OPERATION_DENIED 0x27
|
||||
#define CTAP2_ERR_KEY_STORE_FULL 0x28
|
||||
#define CTAP2_ERR_NOT_BUSY 0x29
|
||||
#define CTAP2_ERR_NO_OPERATION_PENDING 0x2A
|
||||
#define CTAP2_ERR_UNSUPPORTED_OPTION 0x2B
|
||||
#define CTAP2_ERR_INVALID_OPTION 0x2C
|
||||
#define CTAP2_ERR_KEEPALIVE_CANCEL 0x2D
|
||||
#define CTAP2_ERR_NO_CREDENTIALS 0x2E
|
||||
#define CTAP2_ERR_USER_ACTION_TIMEOUT 0x2F
|
||||
#define CTAP2_ERR_NOT_ALLOWED 0x30
|
||||
#define CTAP2_ERR_PIN_INVALID 0x31
|
||||
#define CTAP2_ERR_PIN_BLOCKED 0x32
|
||||
#define CTAP2_ERR_PIN_AUTH_INVALID 0x33
|
||||
#define CTAP2_ERR_PIN_AUTH_BLOCKED 0x34
|
||||
#define CTAP2_ERR_PIN_NOT_SET 0x35
|
||||
#define CTAP2_ERR_PIN_REQUIRED 0x36
|
||||
#define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37
|
||||
#define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38
|
||||
#define CTAP2_ERR_REQUEST_TOO_LARGE 0x39
|
||||
#define CTAP1_ERR_OTHER 0x7F
|
||||
#define CTAP2_ERR_SPEC_LAST 0xDF
|
||||
#define CTAP2_ERR_EXTENSION_FIRST 0xE0
|
||||
#define CTAP2_ERR_EXTENSION_LAST 0xEF
|
||||
#define CTAP2_ERR_VENDOR_FIRST 0xF0
|
||||
#define CTAP2_ERR_VENDOR_LAST 0xFF
|
1061
fido2/ctap_parse.c
Normal file
1061
fido2/ctap_parse.c
Normal file
File diff suppressed because it is too large
Load Diff
36
fido2/ctap_parse.h
Normal file
36
fido2/ctap_parse.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _CTAP_PARSE_H
|
||||
#define _CTAP_PARSE_H
|
||||
|
||||
|
||||
#define check_ret(r) _check_ret(r,__LINE__, __FILE__);\
|
||||
if ((r) != CborNoError) return CTAP2_ERR_CBOR_PARSING;
|
||||
|
||||
#define check_retr(r) _check_ret(r,__LINE__, __FILE__);\
|
||||
if ((r) != CborNoError) return r;
|
||||
|
||||
|
||||
extern void _check_ret(CborError ret, int line, const char * filename);
|
||||
|
||||
|
||||
const char * cbor_value_get_type_string(const CborValue *value);
|
||||
|
||||
|
||||
uint8_t parse_user(CTAP_makeCredential * MC, CborValue * val);
|
||||
uint8_t parse_pub_key_cred_param(CborValue * val, uint8_t * cred_type, int32_t * alg_type);
|
||||
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_rp_id(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_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 ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length);
|
||||
uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length);
|
||||
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length);
|
||||
uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred);
|
||||
|
||||
|
||||
#endif
|
589
fido2/ctaphid.c
Normal file
589
fido2/ctaphid.c
Normal file
@@ -0,0 +1,589 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
#include "ctap.h"
|
||||
#include "u2f.h"
|
||||
#include "time.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IDLE = 0,
|
||||
HANDLING_REQUEST,
|
||||
} CTAP_STATE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMPTY = 0,
|
||||
BUFFERING,
|
||||
BUFFERED,
|
||||
} CTAP_BUFFER_STATE;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint32_t cid;
|
||||
uint16_t bcnt;
|
||||
int offset;
|
||||
int bytes_written;
|
||||
uint8_t seq;
|
||||
uint8_t buf[HID_MESSAGE_SIZE];
|
||||
} CTAPHID_WRITE_BUFFER;
|
||||
|
||||
struct CID
|
||||
{
|
||||
uint32_t cid;
|
||||
uint64_t last_used;
|
||||
uint8_t busy;
|
||||
uint8_t last_cmd;
|
||||
};
|
||||
|
||||
|
||||
#define SUCESS 0
|
||||
#define SEQUENCE_ERROR 1
|
||||
|
||||
static int state;
|
||||
static struct CID CIDS[10];
|
||||
#define CID_MAX (sizeof(CIDS)/sizeof(struct CID))
|
||||
|
||||
static uint64_t active_cid_timestamp;
|
||||
|
||||
static uint8_t ctap_buffer[CTAPHID_BUFFER_SIZE];
|
||||
static uint32_t ctap_buffer_cid;
|
||||
static int ctap_buffer_cmd;
|
||||
static uint16_t ctap_buffer_bcnt;
|
||||
static int ctap_buffer_offset;
|
||||
static int ctap_packet_seq;
|
||||
|
||||
static void buffer_reset();
|
||||
|
||||
#define CTAPHID_WRITE_INIT 0x01
|
||||
#define CTAPHID_WRITE_FLUSH 0x02
|
||||
#define CTAPHID_WRITE_RESET 0x04
|
||||
|
||||
#define ctaphid_write_buffer_init(x) memset(x,0,sizeof(CTAPHID_WRITE_BUFFER))
|
||||
static void ctaphid_write(CTAPHID_WRITE_BUFFER * wb, void * _data, int len);
|
||||
|
||||
void ctaphid_init()
|
||||
{
|
||||
state = IDLE;
|
||||
buffer_reset();
|
||||
ctap_reset_state();
|
||||
}
|
||||
|
||||
static uint32_t get_new_cid()
|
||||
{
|
||||
static uint32_t cid = 1;
|
||||
do
|
||||
{
|
||||
cid++;
|
||||
}while(cid == 0 || cid == 0xffffffff);
|
||||
return cid;
|
||||
}
|
||||
|
||||
static int8_t add_cid(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (!CIDS[i].busy)
|
||||
{
|
||||
CIDS[i].cid = cid;
|
||||
CIDS[i].busy = 1;
|
||||
CIDS[i].last_used = millis();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int8_t cid_exists(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (CIDS[i].cid == cid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int8_t cid_refresh(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (CIDS[i].cid == cid)
|
||||
{
|
||||
CIDS[i].last_used = millis();
|
||||
CIDS[i].busy = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int8_t cid_del(uint32_t cid)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < CID_MAX-1; i++)
|
||||
{
|
||||
if (CIDS[i].cid == cid)
|
||||
{
|
||||
CIDS[i].busy = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int is_broadcast(CTAPHID_PACKET * pkt)
|
||||
{
|
||||
return (pkt->cid == CTAPHID_BROADCAST_CID);
|
||||
}
|
||||
|
||||
static int is_init_pkt(CTAPHID_PACKET * pkt)
|
||||
{
|
||||
return (pkt->pkt.init.cmd == CTAPHID_INIT);
|
||||
}
|
||||
|
||||
static int is_cont_pkt(CTAPHID_PACKET * pkt)
|
||||
{
|
||||
return !(pkt->pkt.init.cmd & TYPE_INIT);
|
||||
}
|
||||
|
||||
|
||||
static int buffer_packet(CTAPHID_PACKET * pkt)
|
||||
{
|
||||
if (pkt->pkt.init.cmd & TYPE_INIT)
|
||||
{
|
||||
ctap_buffer_bcnt = ctaphid_packet_len(pkt);
|
||||
int pkt_len = (ctap_buffer_bcnt < CTAPHID_INIT_PAYLOAD_SIZE) ? ctap_buffer_bcnt : CTAPHID_INIT_PAYLOAD_SIZE;
|
||||
ctap_buffer_cmd = pkt->pkt.init.cmd;
|
||||
ctap_buffer_cid = pkt->cid;
|
||||
ctap_buffer_offset = pkt_len;
|
||||
ctap_packet_seq = -1;
|
||||
memmove(ctap_buffer, pkt->pkt.init.payload, pkt_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
int leftover = ctap_buffer_bcnt - ctap_buffer_offset;
|
||||
int diff = leftover - CTAPHID_CONT_PAYLOAD_SIZE;
|
||||
ctap_packet_seq++;
|
||||
if (ctap_packet_seq != pkt->pkt.cont.seq)
|
||||
{
|
||||
return SEQUENCE_ERROR;
|
||||
}
|
||||
|
||||
if (diff <= 0)
|
||||
{
|
||||
// only move the leftover amount
|
||||
memmove(ctap_buffer + ctap_buffer_offset, pkt->pkt.cont.payload, leftover);
|
||||
ctap_buffer_offset += leftover;
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(ctap_buffer + ctap_buffer_offset, pkt->pkt.cont.payload, CTAPHID_CONT_PAYLOAD_SIZE);
|
||||
ctap_buffer_offset += CTAPHID_CONT_PAYLOAD_SIZE;
|
||||
}
|
||||
}
|
||||
return SUCESS;
|
||||
}
|
||||
|
||||
static void buffer_reset()
|
||||
{
|
||||
|
||||
ctap_buffer_bcnt = 0;
|
||||
ctap_buffer_offset = 0;
|
||||
ctap_packet_seq = 0;
|
||||
ctap_buffer_cid = 0;
|
||||
}
|
||||
|
||||
static int buffer_status()
|
||||
{
|
||||
if (ctap_buffer_bcnt == 0)
|
||||
{
|
||||
return EMPTY;
|
||||
}
|
||||
else if (ctap_buffer_offset == ctap_buffer_bcnt)
|
||||
{
|
||||
return BUFFERED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return BUFFERING;
|
||||
}
|
||||
}
|
||||
|
||||
static int buffer_cmd()
|
||||
{
|
||||
return ctap_buffer_cmd;
|
||||
}
|
||||
|
||||
static uint32_t buffer_cid()
|
||||
{
|
||||
return ctap_buffer_cid;
|
||||
}
|
||||
|
||||
|
||||
static int buffer_len()
|
||||
{
|
||||
return ctap_buffer_bcnt;
|
||||
}
|
||||
|
||||
// Buffer data and send in HID_MESSAGE_SIZE chunks
|
||||
// if len == 0, FLUSH
|
||||
static void ctaphid_write(CTAPHID_WRITE_BUFFER * wb, void * _data, int len)
|
||||
{
|
||||
uint8_t * data = (uint8_t *)_data;
|
||||
if (_data == NULL)
|
||||
{
|
||||
if (wb->offset == 0 && wb->bytes_written == 0)
|
||||
{
|
||||
memmove(wb->buf, &wb->cid, 4);
|
||||
wb->offset += 4;
|
||||
|
||||
wb->buf[4] = wb->cmd;
|
||||
wb->buf[5] = (wb->bcnt & 0xff00) >> 8;
|
||||
wb->buf[6] = (wb->bcnt & 0xff) >> 0;
|
||||
wb->offset += 3;
|
||||
}
|
||||
|
||||
if (wb->offset > 0)
|
||||
{
|
||||
memset(wb->buf + wb->offset, 0, HID_MESSAGE_SIZE - wb->offset);
|
||||
ctaphid_write_block(wb->buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (wb->offset == 0 )
|
||||
{
|
||||
memmove(wb->buf, &wb->cid, 4);
|
||||
wb->offset += 4;
|
||||
|
||||
if (wb->bytes_written == 0)
|
||||
{
|
||||
wb->buf[4] = wb->cmd;
|
||||
wb->buf[5] = (wb->bcnt & 0xff00) >> 8;
|
||||
wb->buf[6] = (wb->bcnt & 0xff) >> 0;
|
||||
wb->offset += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
wb->buf[4] = wb->seq++;
|
||||
wb->offset += 1;
|
||||
}
|
||||
}
|
||||
wb->buf[wb->offset++] = data[i];
|
||||
wb->bytes_written += 1;
|
||||
if (wb->offset == HID_MESSAGE_SIZE)
|
||||
{
|
||||
ctaphid_write_block(wb->buf);
|
||||
wb->offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ctaphid_send_error(uint32_t cid, uint8_t error)
|
||||
{
|
||||
CTAPHID_WRITE_BUFFER wb;
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
|
||||
wb.cid = cid;
|
||||
wb.cmd = CTAPHID_ERROR;
|
||||
wb.bcnt = 1;
|
||||
|
||||
ctaphid_write(&wb, &error, 1);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
}
|
||||
|
||||
static void send_init_response(uint32_t oldcid, uint32_t newcid, uint8_t * nonce)
|
||||
{
|
||||
CTAPHID_INIT_RESPONSE init_resp;
|
||||
CTAPHID_WRITE_BUFFER wb;
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = oldcid;
|
||||
wb.cmd = CTAPHID_INIT;
|
||||
wb.bcnt = 17;
|
||||
|
||||
memmove(init_resp.nonce, nonce, 8);
|
||||
init_resp.cid = newcid;
|
||||
init_resp.protocol_version = 0;//?
|
||||
init_resp.version_major = 0;//?
|
||||
init_resp.version_minor = 0;//?
|
||||
init_resp.build_version = 0;//?
|
||||
init_resp.capabilities = CTAP_CAPABILITIES;
|
||||
|
||||
ctaphid_write(&wb,&init_resp,sizeof(CTAPHID_INIT_RESPONSE));
|
||||
ctaphid_write(&wb,NULL,0);
|
||||
}
|
||||
|
||||
|
||||
void ctaphid_check_timeouts()
|
||||
{
|
||||
uint8_t i;
|
||||
for(i = 0; i < CID_MAX; i++)
|
||||
{
|
||||
if (CIDS[i].busy && ((millis() - CIDS[i].last_used) >= 750))
|
||||
{
|
||||
printf1(TAG_HID, "TIMEOUT CID: %08x\n", CIDS[i].cid);
|
||||
ctaphid_send_error(CIDS[i].cid, CTAP1_ERR_TIMEOUT);
|
||||
memset(CIDS + i, 0, sizeof(struct CID));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ctaphid_handle_packet(uint8_t * pkt_raw)
|
||||
{
|
||||
CTAPHID_PACKET * pkt = (CTAPHID_PACKET *)(pkt_raw);
|
||||
|
||||
printf1(TAG_HID, "Recv packet\n");
|
||||
printf1(TAG_HID, " CID: %08x \n", pkt->cid);
|
||||
printf1(TAG_HID, " cmd: %02x\n", pkt->pkt.init.cmd);
|
||||
if (!is_cont_pkt(pkt)) printf1(TAG_HID, " length: %d\n", ctaphid_packet_len(pkt));
|
||||
|
||||
int ret;
|
||||
uint8_t status;
|
||||
uint32_t oldcid;
|
||||
uint32_t newcid;
|
||||
static CTAPHID_WRITE_BUFFER wb;
|
||||
uint32_t active_cid;
|
||||
|
||||
CTAP_RESPONSE ctap_resp;
|
||||
|
||||
|
||||
if (is_init_pkt(pkt))
|
||||
{
|
||||
if (ctaphid_packet_len(pkt) != 8)
|
||||
{
|
||||
printf2(TAG_ERR, "Error,invalid length field for init packet\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
}
|
||||
if (pkt->cid == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, invalid cid 0\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
ctaphid_init();
|
||||
if (is_broadcast(pkt))
|
||||
{
|
||||
// Check if any existing cids are busy first ?
|
||||
printf1(TAG_HID,"adding a new cid\n");
|
||||
oldcid = CTAPHID_BROADCAST_CID;
|
||||
newcid = get_new_cid();
|
||||
ret = add_cid(newcid);
|
||||
// handle init here
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_HID, "synchronizing to cid\n");
|
||||
oldcid = pkt->cid;
|
||||
newcid = pkt->cid;
|
||||
if (cid_exists(newcid))
|
||||
ret = cid_refresh(newcid);
|
||||
else
|
||||
ret = add_cid(newcid);
|
||||
}
|
||||
if (ret == -1)
|
||||
{
|
||||
printf2(TAG_ERR, "Error, not enough memory for new CID. return BUSY.\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
}
|
||||
send_init_response(oldcid, newcid, pkt->pkt.init.payload);
|
||||
cid_del(newcid);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if matches existing CID
|
||||
if (pkt->cid == CTAPHID_BROADCAST_CID)
|
||||
{
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_CHANNEL);
|
||||
return;
|
||||
}
|
||||
if (cid_exists(pkt->cid))
|
||||
{
|
||||
if (buffer_status() == BUFFERING)
|
||||
{
|
||||
if (pkt->cid == buffer_cid() && ! is_cont_pkt(pkt))
|
||||
{
|
||||
printf2(TAG_ERR,"INVALID_SEQ\n");
|
||||
printf2(TAG_ERR,"Have %d/%d bytes\n", ctap_buffer_offset, ctap_buffer_bcnt);
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_SEQ);
|
||||
return;
|
||||
}
|
||||
else if (pkt->cid != buffer_cid())
|
||||
{
|
||||
printf2(TAG_ERR,"BUSY with %08x\n", buffer_cid());
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (! is_cont_pkt(pkt))
|
||||
{
|
||||
|
||||
if (ctaphid_packet_len(pkt) > CTAPHID_BUFFER_SIZE)
|
||||
{
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer_status() == EMPTY || pkt->cid != buffer_cid())
|
||||
{
|
||||
printf2(TAG_ERR,"ignoring random cont packet\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (buffer_packet(pkt) == SEQUENCE_ERROR)
|
||||
{
|
||||
printf2(TAG_ERR,"Buffering sequence error\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_SEQ);
|
||||
return;
|
||||
}
|
||||
ret = cid_refresh(pkt->cid);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error, refresh cid failed\n");
|
||||
exit(1);
|
||||
}
|
||||
active_cid = pkt->cid;
|
||||
}
|
||||
else if (is_cont_pkt(pkt))
|
||||
{
|
||||
printf2(TAG_ERR,"ignoring unwarranted cont packet\n");
|
||||
// Ignore
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf2(TAG_ERR,"BUSY\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch(buffer_status())
|
||||
{
|
||||
case BUFFERING:
|
||||
printf1(TAG_HID,"BUFFERING\n");
|
||||
active_cid_timestamp = millis();
|
||||
break;
|
||||
|
||||
case EMPTY:
|
||||
printf1(TAG_HID,"empty buffer!\n");
|
||||
case BUFFERED:
|
||||
switch(buffer_cmd())
|
||||
{
|
||||
case CTAPHID_INIT:
|
||||
printf2(TAG_ERR,"CTAPHID_INIT, error this should already be handled\n");
|
||||
exit(1);
|
||||
break;
|
||||
case CTAPHID_PING:
|
||||
printf1(TAG_HID,"CTAPHID_PING\n");
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = active_cid;
|
||||
wb.cmd = CTAPHID_PING;
|
||||
wb.bcnt = buffer_len();
|
||||
|
||||
ctaphid_write(&wb, ctap_buffer, buffer_len());
|
||||
ctaphid_write(&wb, NULL,0);
|
||||
|
||||
break;
|
||||
|
||||
case CTAPHID_WINK:
|
||||
printf1(TAG_HID,"CTAPHID_WINK\n");
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
|
||||
wb.cid = active_cid;
|
||||
wb.cmd = CTAPHID_WINK;
|
||||
|
||||
ctaphid_write(&wb,NULL,0);
|
||||
|
||||
break;
|
||||
|
||||
case CTAPHID_CBOR:
|
||||
printf1(TAG_HID,"CTAPHID_CBOR\n");
|
||||
if (buffer_len() == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error,invalid 0 length field for cbor packet\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
ctap_response_init(&ctap_resp);
|
||||
status = ctap_request(ctap_buffer, buffer_len(), &ctap_resp);
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = active_cid;
|
||||
wb.cmd = CTAPHID_CBOR;
|
||||
wb.bcnt = (ctap_resp.length+1);
|
||||
|
||||
ctaphid_write(&wb, &status, 1);
|
||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
break;
|
||||
|
||||
case CTAPHID_MSG:
|
||||
printf1(TAG_HID,"CTAPHID_MSG\n");
|
||||
if (buffer_len() == 0)
|
||||
{
|
||||
printf2(TAG_ERR,"Error,invalid 0 length field for MSG/U2F packet\n");
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
ctap_response_init(&ctap_resp);
|
||||
u2f_request((struct u2f_request_apdu*)ctap_buffer, &ctap_resp);
|
||||
|
||||
ctaphid_write_buffer_init(&wb);
|
||||
wb.cid = active_cid;
|
||||
wb.cmd = CTAPHID_MSG;
|
||||
wb.bcnt = (ctap_resp.length);
|
||||
|
||||
ctaphid_write(&wb, ctap_resp.data, ctap_resp.length);
|
||||
ctaphid_write(&wb, NULL, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf2(TAG_ERR,"error, unimplemented HID cmd: %02x\r\n", buffer_cmd());
|
||||
ctaphid_send_error(pkt->cid, CTAP1_ERR_INVALID_COMMAND);
|
||||
break;
|
||||
}
|
||||
cid_del(buffer_cid());
|
||||
buffer_reset();
|
||||
break;
|
||||
|
||||
default:
|
||||
printf2(TAG_ERR,"invalid buffer state; abort\n");
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
printf1(TAG_HID,"\n");
|
||||
|
||||
}
|
||||
|
80
fido2/ctaphid.h
Normal file
80
fido2/ctaphid.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef _CTAPHID_H_H
|
||||
#define _CTAPHID_H_H
|
||||
|
||||
#include "device.h"
|
||||
#include "ctap_errors.h"
|
||||
|
||||
#define TYPE_INIT 0x80
|
||||
#define TYPE_CONT 0x00
|
||||
|
||||
#define CTAPHID_PING (TYPE_INIT | 0x01)
|
||||
#define CTAPHID_MSG (TYPE_INIT | 0x03)
|
||||
#define CTAPHID_LOCK (TYPE_INIT | 0x04)
|
||||
#define CTAPHID_INIT (TYPE_INIT | 0x06)
|
||||
#define CTAPHID_WINK (TYPE_INIT | 0x08)
|
||||
#define CTAPHID_CBOR (TYPE_INIT | 0x10)
|
||||
#define CTAPHID_CANCEL (TYPE_INIT | 0x11)
|
||||
#define CTAPHID_ERROR (TYPE_INIT | 0x3f)
|
||||
|
||||
#define ERR_INVALID_CMD 0x01
|
||||
#define ERR_INVALID_PAR 0x02
|
||||
#define ERR_INVALID_SEQ 0x04
|
||||
#define ERR_MSG_TIMEOUT 0x05
|
||||
#define ERR_CHANNEL_BUSY 0x06
|
||||
|
||||
|
||||
#define CTAPHID_INIT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-7)
|
||||
#define CTAPHID_CONT_PAYLOAD_SIZE (HID_MESSAGE_SIZE-5)
|
||||
|
||||
#define CTAPHID_BROADCAST_CID 0xffffffff
|
||||
|
||||
#define CTAPHID_BUFFER_SIZE 7609
|
||||
|
||||
#define CAPABILITY_WINK 0x01
|
||||
#define CAPABILITY_LOCK 0x02
|
||||
#define CAPABILITY_CBOR 0x04
|
||||
#define CAPABILITY_NMSG 0x08
|
||||
|
||||
#define CTAP_CAPABILITIES (CAPABILITY_WINK | CAPABILITY_CBOR)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cid;
|
||||
union{
|
||||
struct{
|
||||
uint8_t cmd;
|
||||
uint8_t bcnth;
|
||||
uint8_t bcntl;
|
||||
uint8_t payload[CTAPHID_INIT_PAYLOAD_SIZE];
|
||||
} init;
|
||||
struct{
|
||||
uint8_t seq;
|
||||
uint8_t payload[CTAPHID_CONT_PAYLOAD_SIZE];
|
||||
} cont;
|
||||
} pkt;
|
||||
} CTAPHID_PACKET;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t nonce[8];
|
||||
uint32_t cid;
|
||||
uint8_t protocol_version;
|
||||
uint8_t version_major;
|
||||
uint8_t version_minor;
|
||||
uint8_t build_version;
|
||||
uint8_t capabilities;
|
||||
} __attribute__((packed)) CTAPHID_INIT_RESPONSE;
|
||||
|
||||
|
||||
|
||||
void ctaphid_init();
|
||||
|
||||
void ctaphid_handle_packet(uint8_t * pkt_raw);
|
||||
|
||||
void ctaphid_check_timeouts();
|
||||
|
||||
|
||||
#define ctaphid_packet_len(pkt) ((uint16_t)((pkt)->pkt.init.bcnth << 8) | ((pkt)->pkt.init.bcntl))
|
||||
|
||||
#endif
|
44
fido2/device.h
Normal file
44
fido2/device.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _DEVICE_H
|
||||
#define _DEVICE_H
|
||||
|
||||
void device_init();
|
||||
|
||||
uint64_t millis();
|
||||
|
||||
// HID message size in bytes
|
||||
#define HID_MESSAGE_SIZE 64
|
||||
|
||||
void usbhid_init();
|
||||
|
||||
int usbhid_recv(uint8_t * msg);
|
||||
|
||||
void usbhid_send(uint8_t * msg);
|
||||
|
||||
void usbhid_close();
|
||||
|
||||
void main_loop_delay();
|
||||
|
||||
void heartbeat();
|
||||
|
||||
|
||||
// Test for user presence
|
||||
// Return 1 for user is present, 0 user not present
|
||||
extern int ctap_user_presence_test();
|
||||
|
||||
// Generate @num bytes of random numbers to @dest
|
||||
// return 1 if success, error otherwise
|
||||
extern int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||
|
||||
// Increment atomic counter and return it.
|
||||
// Must support two counters, @sel selects counter0 or counter1.
|
||||
uint32_t ctap_atomic_count(int sel);
|
||||
|
||||
// Verify the user
|
||||
// return 1 if user is verified, 0 if not
|
||||
extern int ctap_user_verification(uint8_t arg);
|
||||
|
||||
// Must be implemented by application
|
||||
// data is HID_MESSAGE_SIZE long in bytes
|
||||
extern void ctaphid_write_block(uint8_t * data);
|
||||
|
||||
#endif
|
85
fido2/log.c
Normal file
85
fido2/log.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
static uint32_t LOGMASK = TAG_FILENO;
|
||||
|
||||
void set_logging_mask(uint32_t mask)
|
||||
{
|
||||
LOGMASK = mask;
|
||||
}
|
||||
struct logtag
|
||||
{
|
||||
uint32_t tagn;
|
||||
const char * tag;
|
||||
};
|
||||
|
||||
struct logtag tagtable[] = {
|
||||
{TAG_GEN,""},
|
||||
{TAG_MC,"MC"},
|
||||
{TAG_GA,"GA"},
|
||||
{TAG_CP,"CP"},
|
||||
{TAG_ERR,"ERR"},
|
||||
{TAG_PARSE,"PARSE"},
|
||||
{TAG_CTAP,"CTAP"},
|
||||
{TAG_U2F,"U2F"},
|
||||
{TAG_DUMP,"DUMP"},
|
||||
{TAG_HID,"HID"},
|
||||
{TAG_USB,"USB"},
|
||||
{TAG_GREEN,"[1;32mDEBUG[0m"},
|
||||
{TAG_RED,"[1;31mDEBUG[0m"},
|
||||
{TAG_TIME,"[1;33mTIME[0m"},
|
||||
};
|
||||
|
||||
|
||||
__attribute__((weak)) void set_logging_tag(uint32_t tag)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (((tag & 0x7fffffff) & LOGMASK) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < sizeof(tagtable)/sizeof(struct logtag); i++)
|
||||
{
|
||||
if (tag & tagtable[i].tagn)
|
||||
{
|
||||
if (tagtable[i].tag[0]) printf("[%s] ", tagtable[i].tag);
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != 0)
|
||||
{
|
||||
printf2(TAG_ERR,"INVALID LOG TAG\n");
|
||||
exit(1);
|
||||
}
|
||||
set_logging_tag(tag);
|
||||
#ifdef ENABLE_FILE_LOGGING
|
||||
if (tag & TAG_FILENO)
|
||||
{
|
||||
printf("%s:%d: ", filename, num);
|
||||
}
|
||||
#endif
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void LOG_HEX(uint32_t tag, uint8_t * data, int length)
|
||||
{
|
||||
if (((tag & 0x7fffffff) & LOGMASK) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
set_logging_tag(tag);
|
||||
dump_hex(data,length);
|
||||
}
|
48
fido2/log.h
Normal file
48
fido2/log.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
#define DEBUG_LEVEL 1
|
||||
#define ENABLE_FILE_LOGGING
|
||||
|
||||
void LOG(uint32_t tag, const char * filename, int num, const char * fmt, ...);
|
||||
void LOG_HEX(uint32_t tag, uint8_t * data, int length);
|
||||
void set_logging_mask(uint32_t mask);
|
||||
void set_logging_tag(uint32_t tag);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TAG_GEN = (1 << 0),
|
||||
TAG_MC = (1 << 1),
|
||||
TAG_GA = (1 << 2),
|
||||
TAG_CP = (1 << 3),
|
||||
TAG_ERR = (1 << 4),
|
||||
TAG_PARSE= (1 << 5),
|
||||
TAG_CTAP = (1 << 6),
|
||||
TAG_U2F = (1 << 7),
|
||||
TAG_DUMP = (1 << 8),
|
||||
TAG_GREEN = (1 << 9),
|
||||
TAG_RED= (1 << 10),
|
||||
TAG_TIME= (1 << 11),
|
||||
TAG_HID = (1 << 12),
|
||||
TAG_USB = (1 << 13),
|
||||
|
||||
TAG_FILENO = (1<<31)
|
||||
} LOG_TAG;
|
||||
|
||||
#if DEBUG_LEVEL == 1
|
||||
|
||||
#define printf1(tag,fmt, ...) LOG(tag & ~(TAG_FILENO), NULL, 0, fmt, ##__VA_ARGS__)
|
||||
#define printf2(tag,fmt, ...) LOG(tag | TAG_FILENO,__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
#define printf3(tag,fmt, ...) LOG(tag | TAG_FILENO,__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define dump_hex1(tag,data,len) LOG_HEX(tag,data,len)
|
||||
|
||||
#else
|
||||
|
||||
#define printf1(fmt, ...)
|
||||
#define printf2(fmt, ...)
|
||||
#define printf3(fmt, ...)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
88
fido2/main.c
Normal file
88
fido2/main.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
#include "bsp.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
|
||||
|
||||
#if !defined(TEST)
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int count = 0;
|
||||
uint64_t t1 = 0;
|
||||
uint64_t t2 = 0;
|
||||
uint64_t accum = 0;
|
||||
uint8_t hidmsg[64];
|
||||
|
||||
set_logging_mask(
|
||||
/*0*/
|
||||
/*TAG_GEN|*/
|
||||
/*TAG_MC |*/
|
||||
/*TAG_GA |*/
|
||||
/*TAG_CP |*/
|
||||
TAG_CTAP|
|
||||
/*TAG_HID|*/
|
||||
/*TAG_U2F|*/
|
||||
/*TAG_PARSE |*/
|
||||
/*TAG_TIME|*/
|
||||
TAG_DUMP|
|
||||
/*TAG_GREEN|*/
|
||||
/*TAG_RED|*/
|
||||
TAG_ERR
|
||||
);
|
||||
|
||||
device_init();
|
||||
printf1(TAG_GEN,"init device\n");
|
||||
|
||||
printf1(TAG_GEN,"init ctaphid\n");
|
||||
ctaphid_init();
|
||||
|
||||
printf1(TAG_GEN,"init ctap\n");
|
||||
ctap_init();
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (millis() - t1 > 100)
|
||||
{
|
||||
/*printf("heartbeat %ld\n", beat++);*/
|
||||
heartbeat();
|
||||
t1 = millis();
|
||||
}
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
printf1(TAG_DUMP,"%d>> ",count++); dump_hex1(TAG_DUMP, hidmsg,sizeof(hidmsg));
|
||||
t2 = millis();
|
||||
ctaphid_handle_packet(hidmsg);
|
||||
accum += millis() - t2;
|
||||
printf1(TAG_TIME,"accum: %lu\n", (uint32_t)accum);
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*main_loop_delay();*/
|
||||
}
|
||||
ctaphid_check_timeouts();
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
usbhid_close();
|
||||
printf("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
56
fido2/stubs.c
Normal file
56
fido2/stubs.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include "device.h"
|
||||
#include "util.h"
|
||||
#include "ctap.h"
|
||||
#include "u2f.h"
|
||||
|
||||
#if defined(STUB_CTAPHID) || defined(STUB_CTAP)
|
||||
|
||||
|
||||
|
||||
void ctap_init()
|
||||
{
|
||||
printf("STUB: ctap_init\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STUB_CTAPHID)
|
||||
void ctaphid_init()
|
||||
{
|
||||
printf("STUB: ctaphid_init\n");
|
||||
}
|
||||
void ctaphid_handle_packet(uint8_t * hidmsg)
|
||||
{
|
||||
printf("STUB: ctaphid_handle_packet\n");
|
||||
}
|
||||
|
||||
void ctaphid_check_timeouts()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef STUB_CTAP
|
||||
|
||||
void ctap_reset_state()
|
||||
{
|
||||
printf("STUB: ctap_reset_state\n");
|
||||
}
|
||||
|
||||
void ctap_response_init(CTAP_RESPONSE * resp)
|
||||
{
|
||||
}
|
||||
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
{
|
||||
printf("STUB: u2f_request\n");
|
||||
}
|
||||
|
||||
uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||
{
|
||||
printf("STUB: ctap_request\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
160
fido2/test_power.c
Normal file
160
fido2/test_power.c
Normal file
@@ -0,0 +1,160 @@
|
||||
#ifdef TEST_POWER
|
||||
|
||||
/*
|
||||
* Standalone test that runs through CTAP makeCredential and getAssertion
|
||||
* for each button press. Used for testing power consumption.
|
||||
*
|
||||
* */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "device.h"
|
||||
#include "ctaphid.h"
|
||||
#include "bsp.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "ctap.h"
|
||||
|
||||
|
||||
|
||||
#define BUTT NRF_GPIO_PIN_MAP(0,11)
|
||||
#define TRIG NRF_GPIO_PIN_MAP(0,30)
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int count = 0;
|
||||
uint64_t t1 = 0;
|
||||
uint64_t t2 = 0;
|
||||
uint64_t accum = 0;
|
||||
uint8_t hidmsg[64];
|
||||
|
||||
set_logging_mask(
|
||||
0
|
||||
/*TAG_GEN|*/
|
||||
/*TAG_MC |*/
|
||||
/*TAG_GA |*/
|
||||
/*TAG_CP |*/
|
||||
/*TAG_CTAP|*/
|
||||
/*TAG_HID|*/
|
||||
/*TAG_U2F|*/
|
||||
/*TAG_PARSE |*/
|
||||
/*TAG_TIME|*/
|
||||
/*TAG_DUMP|*/
|
||||
/*TAG_GREEN|*/
|
||||
/*TAG_RED|*/
|
||||
/*TAG_ERR*/
|
||||
);
|
||||
|
||||
device_init();
|
||||
ctaphid_init();
|
||||
ctap_init();
|
||||
|
||||
nrf_gpio_cfg_input(BUTT, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_output(TRIG);
|
||||
nrf_gpio_pin_clear(TRIG);
|
||||
|
||||
memset(hidmsg,0,sizeof(hidmsg));
|
||||
|
||||
printf1(TAG_GEN,"recv'ing hid msg \n");
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (millis() - t1 > 100)
|
||||
{
|
||||
/*printf("heartbeat %ld\n", beat++);*/
|
||||
heartbeat();
|
||||
t1 = millis();
|
||||
}
|
||||
|
||||
if (usbhid_recv(hidmsg) > 0)
|
||||
{
|
||||
printf1(TAG_DUMP,"%d>> ",count++); dump_hex1(TAG_DUMP, hidmsg,sizeof(hidmsg));
|
||||
t2 = millis();
|
||||
ctaphid_handle_packet(hidmsg);
|
||||
accum += millis() - t2;
|
||||
printf1(TAG_TIME,"accum: %lu\n", (uint32_t)accum);
|
||||
memset(hidmsg, 0, sizeof(hidmsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*main_loop_delay();*/
|
||||
}
|
||||
ctaphid_check_timeouts();
|
||||
}
|
||||
|
||||
// Should never get here
|
||||
usbhid_close();
|
||||
printf("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void delay(int ms)
|
||||
{
|
||||
uint64_t t1;
|
||||
t1 = millis();
|
||||
while(millis()-t1 < ms)
|
||||
;
|
||||
}
|
||||
|
||||
void ctaphid_write_block(uint8_t * data)
|
||||
{
|
||||
// Don't actually use usb
|
||||
/*usbhid_send(data);*/
|
||||
}
|
||||
|
||||
uint8_t hidcmds[][64] = {"\x03\x00\x00\x00\x86\x00\x08\x2d\x73\x95\x80\x2e\xbb\x44\x8d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\x03\x00\x00\x00\x90\x00\x01\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\x03\x00\x00\x00\x90\x00\x75\x01\xa5\x01\x58\x20\xe5\x64\xed\x22\x01\xda\x3c\x2d\xab\x85\x3c\x1d\x04\x62\x67\x8a\x40\xaa\x1c\x3f\x31\x22\x21\x23\x35\xd5\xf8\xe4\x26\xc8\xd1\xa0\x02\xa2\x62\x69\x64\x6b\x65\x78\x61\x6d\x70\x6c\x6f\x2e\x6f\x72\x67\x64\x6e\x61",
|
||||
"\x03\x00\x00\x00\x00\x6d\x65\x65\x45\x78\x61\x52\x50\x03\xa2\x62\x69\x64\x47\x75\x73\x65\x65\x5f\x6f\x64\x64\x6e\x61\x6d\x65\x67\x41\x42\x20\x55\x73\x65\x72\x04\x81\xa2\x63\x61\x6c\x67\x26\x64\x74\x79\x70\x65\x6a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x05",
|
||||
"\x03\x00\x00\x00\x01\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\x03\x00\x00\x00\x90\x00\x01\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\x03\x00\x00\x00\x90\x00\xf2\x02\xa3\x01\x6b\x65\x78\x61\x6d\x70\x6c\x6f\x2e\x6f\x72\x67\x02\x58\x20\xc4\x74\xef\xcd\xb3\xf9\x61\x18\xdd\xfb\x2f\xe5\x7b\x05\xd2\xf1\x23\xba\x20\x7c\x87\xea\x9e\xfd\x07\xa3\xe3\x21\xdc\x60\x9f\x63\x03\x81\xa2\x62\x69\x64\x58",
|
||||
"\x03\x00\x00\x00\x00\xa8\x6a\x7e\x7b\xe7\x95\x63\xb1\x38\x2e\x2f\x03\xd6\x6c\xf5\xa3\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x08\x24\x17\x4e\x23\xfd\x17\x7f\xb3\x18\x7c\x74\xe0\xbe\x35\x35\x94\x02\x7f\x61\xe3\x1c\xae\x73\xb4\x02\x7f\xf6\x7e\xc1\x36\x43\x2b\xc2",
|
||||
"\x03\x00\x00\x00\x01\x60\xdd\xb8\x0b\x4a\xbb\x6f\x61\xac\xc3\xc6\x37\x9d\x33\x71\xe3\xcf\xa2\x4f\x5c\x11\x97\x44\xf8\x87\xb0\xd2\x67\xe8\x9a\xeb\x61\x39\x29\x61\xbf\xf7\xd1\xe1\xa9\x79\x26\x4a\x1a\xe7\x26\x60\xa4\x3d\x9f\x5c\xfe\x57\xbc\x4a\x74\x71\xf5\x67",
|
||||
"\x03\x00\x00\x00\x02\xdd\x8d\x40\x49\x1e\x2d\x28\x15\x18\xbd\xf2\xe2\xef\x61\xbc\xb6\x04\x6f\x51\xdb\xe6\xc6\xd0\x9f\xbb\x06\xae\xac\xe4\xf6\xbd\x05\x85\xd3\x31\x5b\x98\x75\x2a\x4a\x31\xea\x5d\xc8\x78\x15\xee\xbe\x56\x0b\x43\x64\x74\x79\x70\x65\x6a\x70\x75",
|
||||
"\x03\x00\x00\x00\x03\x62\x6c\x69\x63\x2d\x6b\x65\x79\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"};
|
||||
|
||||
int usbhid_recv(uint8_t * msg)
|
||||
{
|
||||
static int lastval = 0;
|
||||
static int reading = 0;
|
||||
int val;
|
||||
// button1 == p0.11
|
||||
// button2 == p0.12
|
||||
// button3 == p0.24
|
||||
// button4 == p0.25
|
||||
if (!reading)
|
||||
{
|
||||
delay(1);
|
||||
nrf_gpio_pin_clear(TRIG);
|
||||
val = nrf_gpio_pin_read(BUTT);
|
||||
if (val == 0)
|
||||
{
|
||||
if (lastval != 0)
|
||||
{
|
||||
printf1(TAG_GEN, "button!\n");
|
||||
/*printf1(TAG_GEN,"size of array: %d elements", sizeof(hidcmds)/64);*/
|
||||
reading = 1;
|
||||
}
|
||||
}
|
||||
lastval = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_gpio_pin_set(TRIG);
|
||||
memmove(msg, hidcmds[reading-1], 64);
|
||||
reading++;
|
||||
if (reading-1 == sizeof(hidcmds)/64)
|
||||
{
|
||||
reading = 0;
|
||||
}
|
||||
return 64;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
281
fido2/u2f.c
Normal file
281
fido2/u2f.c
Normal file
@@ -0,0 +1,281 @@
|
||||
#include <stdlib.h>
|
||||
#include "u2f.h"
|
||||
#include "ctap.h"
|
||||
#include "crypto.h"
|
||||
#include "log.h"
|
||||
#include "device.h"
|
||||
|
||||
// void u2f_response_writeback(uint8_t * buf, uint8_t len);
|
||||
static int16_t u2f_register(struct u2f_register_request * req);
|
||||
static int16_t u2f_version();
|
||||
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control);
|
||||
static int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
|
||||
|
||||
static CTAP_RESPONSE * _u2f_resp = NULL;
|
||||
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)
|
||||
{
|
||||
uint16_t rcode;
|
||||
uint64_t t1,t2;
|
||||
uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16));
|
||||
uint8_t byte;
|
||||
|
||||
_u2f_resp = resp;
|
||||
|
||||
if (req->cla != 0)
|
||||
{
|
||||
printf1(TAG_U2F, "CLA not zero\n");
|
||||
rcode = U2F_SW_CLASS_NOT_SUPPORTED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch(req->ins)
|
||||
{
|
||||
case U2F_REGISTER:
|
||||
printf1(TAG_U2F, "U2F_REGISTER\n");
|
||||
if (len != 64)
|
||||
{
|
||||
rcode = U2F_SW_WRONG_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = millis();
|
||||
rcode = u2f_register((struct u2f_register_request*)req->payload);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"u2f_register time: %d ms\n", t2-t1);
|
||||
}
|
||||
break;
|
||||
case U2F_AUTHENTICATE:
|
||||
printf1(TAG_U2F, "U2F_AUTHENTICATE\n");
|
||||
t1 = millis();
|
||||
rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1);
|
||||
t2 = millis();
|
||||
printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", t2-t1);
|
||||
break;
|
||||
case U2F_VERSION:
|
||||
printf1(TAG_U2F, "U2F_VERSION\n");
|
||||
if (len)
|
||||
{
|
||||
rcode = U2F_SW_WRONG_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
rcode = u2f_version();
|
||||
}
|
||||
break;
|
||||
case U2F_VENDOR_FIRST:
|
||||
case U2F_VENDOR_LAST:
|
||||
printf1(TAG_U2F, "U2F_VENDOR\n");
|
||||
rcode = U2F_SW_NO_ERROR;
|
||||
break;
|
||||
default:
|
||||
printf1(TAG_ERR, "Error, unknown U2F command\n");
|
||||
rcode = U2F_SW_INS_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
end:
|
||||
if (rcode != U2F_SW_NO_ERROR)
|
||||
{
|
||||
printf1(TAG_U2F,"U2F Error code %04x\n", rcode);
|
||||
ctap_response_init(_u2f_resp);
|
||||
}
|
||||
|
||||
byte = (rcode & 0xff00)>>8;
|
||||
u2f_response_writeback(&byte,1);
|
||||
byte = rcode & 0xff;
|
||||
u2f_response_writeback(&byte,1);
|
||||
|
||||
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
|
||||
}
|
||||
|
||||
|
||||
static int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len)
|
||||
{
|
||||
if ((_u2f_resp->length + len) > _u2f_resp->data_size)
|
||||
{
|
||||
printf2(TAG_ERR, "Not enough space for U2F response, writeback\n");
|
||||
exit(1);
|
||||
}
|
||||
memmove(_u2f_resp->data + _u2f_resp->length, buf, len);
|
||||
_u2f_resp->length += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void dump_signature_der(uint8_t * sig)
|
||||
{
|
||||
uint8_t sigder[72];
|
||||
int len;
|
||||
len = ctap_encode_der_sig(sig, sigder);
|
||||
u2f_response_writeback(sigder, len);
|
||||
}
|
||||
static int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t * appid)
|
||||
{
|
||||
crypto_ecc256_load_key((uint8_t*)kh, U2F_KEY_HANDLE_SIZE, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * tag)
|
||||
{
|
||||
uint8_t hashbuf[32];
|
||||
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, hashbuf);
|
||||
crypto_sha256_update(kh->key, U2F_KEY_HANDLE_KEY_SIZE);
|
||||
crypto_sha256_update(appid, U2F_APPLICATION_SIZE);
|
||||
crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0,hashbuf);
|
||||
memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE);
|
||||
}
|
||||
|
||||
static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey)
|
||||
{
|
||||
ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE);
|
||||
u2f_make_auth_tag(kh, appid, kh->tag);
|
||||
|
||||
crypto_ecc256_derive_public_key((uint8_t*)kh, U2F_KEY_HANDLE_SIZE, pubkey, pubkey+32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid)
|
||||
{
|
||||
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
|
||||
u2f_make_auth_tag(kh, appid, tag);
|
||||
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf1(TAG_U2F, "key handle + appid not authentic\n");
|
||||
printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE);
|
||||
printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control)
|
||||
{
|
||||
|
||||
uint8_t up = 1;
|
||||
uint32_t count;
|
||||
uint8_t hash[32];
|
||||
uint8_t * sig = (uint8_t*)req;
|
||||
|
||||
if (control == U2F_AUTHENTICATE_CHECK)
|
||||
{
|
||||
if (u2f_appid_eq(&req->kh, req->app) == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return U2F_SW_WRONG_DATA;
|
||||
}
|
||||
}
|
||||
if (
|
||||
control != U2F_AUTHENTICATE_SIGN ||
|
||||
req->khl != U2F_KEY_HANDLE_SIZE ||
|
||||
u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important
|
||||
u2f_load_key(&req->kh, req->app) != 0
|
||||
|
||||
)
|
||||
{
|
||||
return U2F_SW_WRONG_PAYLOAD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (ctap_user_presence_test() == 0)
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
count = ctap_atomic_count(0);
|
||||
|
||||
crypto_sha256_init();
|
||||
|
||||
crypto_sha256_update(req->app,32);
|
||||
crypto_sha256_update(&up,1);
|
||||
crypto_sha256_update((uint8_t *)&count,4);
|
||||
crypto_sha256_update(req->chal,32);
|
||||
|
||||
crypto_sha256_final(hash);
|
||||
|
||||
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F,hash,32);
|
||||
crypto_ecc256_sign(hash, 32, sig);
|
||||
|
||||
u2f_response_writeback(&up,1);
|
||||
u2f_response_writeback((uint8_t *)&count,4);
|
||||
dump_signature_der(sig);
|
||||
|
||||
return U2F_SW_NO_ERROR;
|
||||
}
|
||||
|
||||
static int16_t u2f_register(struct u2f_register_request * req)
|
||||
{
|
||||
uint8_t i[] = {0x0,U2F_EC_FMT_UNCOMPRESSED};
|
||||
|
||||
struct u2f_key_handle key_handle;
|
||||
uint8_t pubkey[64];
|
||||
uint8_t hash[32];
|
||||
uint8_t * sig = (uint8_t*)req;
|
||||
|
||||
|
||||
const uint16_t attest_size = attestation_cert_der_size;
|
||||
|
||||
if ( ! ctap_user_presence_test())
|
||||
{
|
||||
return U2F_SW_CONDITIONS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1)
|
||||
{
|
||||
return U2F_SW_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
crypto_sha256_init();
|
||||
crypto_sha256_update(i,1);
|
||||
crypto_sha256_update(req->app,32);
|
||||
|
||||
crypto_sha256_update(req->chal,32);
|
||||
|
||||
crypto_sha256_update((uint8_t*)&key_handle,U2F_KEY_HANDLE_SIZE);
|
||||
crypto_sha256_update(i+1,1);
|
||||
crypto_sha256_update(pubkey,64);
|
||||
crypto_sha256_final(hash);
|
||||
|
||||
crypto_ecc256_load_attestation_key();
|
||||
|
||||
/*printf("check key handle size: %d vs %d\n", U2F_KEY_HANDLE_SIZE, sizeof(struct u2f_key_handle));*/
|
||||
|
||||
printf1(TAG_U2F, "sha256: "); dump_hex1(TAG_U2F,hash,32);
|
||||
crypto_ecc256_sign(hash, 32, sig);
|
||||
|
||||
i[0] = 0x5;
|
||||
u2f_response_writeback(i,2);
|
||||
u2f_response_writeback(pubkey,64);
|
||||
i[0] = U2F_KEY_HANDLE_SIZE;
|
||||
u2f_response_writeback(i,1);
|
||||
u2f_response_writeback((uint8_t*)&key_handle,U2F_KEY_HANDLE_SIZE);
|
||||
|
||||
u2f_response_writeback(attestation_cert_der,attest_size);
|
||||
|
||||
dump_signature_der(sig);
|
||||
|
||||
/*printf1(TAG_U2F, "dersig: "); dump_hex1(TAG_U2F,sig,74);*/
|
||||
|
||||
|
||||
return U2F_SW_NO_ERROR;
|
||||
}
|
||||
|
||||
static int16_t u2f_version()
|
||||
{
|
||||
const char version[] = "U2F_V2";
|
||||
u2f_response_writeback((uint8_t*)version, sizeof(version)-1);
|
||||
return U2F_SW_NO_ERROR;
|
||||
}
|
102
fido2/u2f.h
Normal file
102
fido2/u2f.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef _U2F_H_
|
||||
#define _U2F_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ctap.h"
|
||||
|
||||
#define U2F_EC_FMT_UNCOMPRESSED 0x04
|
||||
|
||||
#define U2F_EC_POINT_SIZE 32
|
||||
#define U2F_EC_PUBKEY_SIZE 65
|
||||
#define U2F_APDU_SIZE 7
|
||||
#define U2F_CHALLENGE_SIZE 32
|
||||
#define U2F_APPLICATION_SIZE 32
|
||||
#define U2F_KEY_HANDLE_TAG_SIZE 16
|
||||
#define U2F_KEY_HANDLE_KEY_SIZE 32
|
||||
#define U2F_KEY_HANDLE_SIZE (U2F_KEY_HANDLE_KEY_SIZE+U2F_KEY_HANDLE_TAG_SIZE)
|
||||
#define U2F_REGISTER_REQUEST_SIZE (U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE)
|
||||
#define U2F_MAX_REQUEST_PAYLOAD (1 + U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE + 1 + U2F_KEY_HANDLE_SIZE)
|
||||
|
||||
|
||||
// U2F native commands
|
||||
#define U2F_REGISTER 0x01
|
||||
#define U2F_AUTHENTICATE 0x02
|
||||
#define U2F_VERSION 0x03
|
||||
#define U2F_VENDOR_FIRST 0xc0
|
||||
#define U2F_VENDOR_LAST 0xff
|
||||
|
||||
// U2F_CMD_REGISTER command defines
|
||||
#define U2F_REGISTER_ID 0x05
|
||||
#define U2F_REGISTER_HASH_ID 0x00
|
||||
|
||||
// U2F Authenticate
|
||||
#define U2F_AUTHENTICATE_CHECK 0x7
|
||||
#define U2F_AUTHENTICATE_SIGN 0x3
|
||||
|
||||
|
||||
// Command status responses
|
||||
#define U2F_SW_NO_ERROR 0x9000
|
||||
#define U2F_SW_WRONG_DATA 0x6984
|
||||
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985
|
||||
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00
|
||||
#define U2F_SW_WRONG_LENGTH 0x6700
|
||||
#define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00
|
||||
#define U2F_SW_WRONG_PAYLOAD 0x6a80
|
||||
#define U2F_SW_INSUFFICIENT_MEMORY 0x9210
|
||||
|
||||
// Delay in milliseconds to wait for user input
|
||||
#define U2F_MS_USER_INPUT_WAIT 3000
|
||||
|
||||
struct u2f_request_apdu
|
||||
{
|
||||
uint8_t cla;
|
||||
uint8_t ins;
|
||||
uint8_t p1;
|
||||
uint8_t p2;
|
||||
uint8_t LC1;
|
||||
uint8_t LC2;
|
||||
uint8_t LC3;
|
||||
uint8_t payload[U2F_MAX_REQUEST_PAYLOAD];
|
||||
};
|
||||
|
||||
struct u2f_ec_point
|
||||
{
|
||||
uint8_t fmt;
|
||||
uint8_t x[U2F_EC_POINT_SIZE];
|
||||
uint8_t y[U2F_EC_POINT_SIZE];
|
||||
};
|
||||
|
||||
struct u2f_register_request
|
||||
{
|
||||
uint8_t chal[U2F_CHALLENGE_SIZE];
|
||||
uint8_t app[U2F_APPLICATION_SIZE];
|
||||
};
|
||||
|
||||
|
||||
struct u2f_key_handle
|
||||
{
|
||||
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
|
||||
uint8_t key[U2F_KEY_HANDLE_KEY_SIZE];
|
||||
};
|
||||
|
||||
|
||||
struct u2f_authenticate_request
|
||||
{
|
||||
uint8_t chal[U2F_CHALLENGE_SIZE];
|
||||
uint8_t app[U2F_APPLICATION_SIZE];
|
||||
uint8_t khl;
|
||||
struct u2f_key_handle kh;
|
||||
};
|
||||
|
||||
// u2f_request send a U2F message to U2F protocol
|
||||
// @req U2F message
|
||||
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/* Platform specific functions that must be implemented by user */
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#endif /* U2F_H_ */
|
12
fido2/util.c
Normal file
12
fido2/util.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void dump_hex(uint8_t * buf, int size)
|
||||
{
|
||||
while(size--)
|
||||
{
|
||||
printf("%02x ", *buf++);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
15
fido2/util.h
Normal file
15
fido2/util.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _UTIL_H
|
||||
#define _UTIL_H
|
||||
|
||||
|
||||
void dump_hex(uint8_t * buf, int size);
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user