move things around and add efm8 and efm32 builds

This commit is contained in:
Conor Patrick
2018-06-27 21:39:19 -04:00
parent e446e29318
commit fb9a592d50
84 changed files with 22289 additions and 419 deletions

16
fido2/cose_key.h Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

264
fido2/ctap.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

36
fido2/ctap_parse.h Normal file
View 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
View 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
View 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
View 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
View 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,"DEBUG"},
{TAG_RED,"DEBUG"},
{TAG_TIME,"TIME"},
};
__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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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