parsed make_credential
This commit is contained in:
parent
0c5c3dc742
commit
51f8ef2e76
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
|||||||
src = $(wildcard *.c)
|
src = $(wildcard *.c) $(wildcard crypto/*.c)
|
||||||
obj = $(src:.c=.o)
|
obj = $(src:.c=.o)
|
||||||
|
|
||||||
LDFLAGS = -Wl,--gc-sections ./tinycbor/lib/libtinycbor.a
|
LDFLAGS = -Wl,--gc-sections ./tinycbor/lib/libtinycbor.a
|
||||||
CFLAGS = -O2 -fdata-sections -ffunction-sections -I./tinycbor/src
|
CFLAGS = -O2 -fdata-sections -ffunction-sections -I./tinycbor/src -I./crypto
|
||||||
|
|
||||||
name = main
|
name = main
|
||||||
|
|
||||||
|
519
ctap.c
519
ctap.c
@ -5,6 +5,7 @@
|
|||||||
#include "cbor.h"
|
#include "cbor.h"
|
||||||
|
|
||||||
#include "ctap.h"
|
#include "ctap.h"
|
||||||
|
#include "crypto.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
@ -18,6 +19,53 @@ static void check_ret(CborError ret)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char * cbor_value_get_type_string(const CborValue *value)
|
||||||
|
{
|
||||||
|
switch(cbor_value_get_type(value))
|
||||||
|
{
|
||||||
|
case CborIntegerType:
|
||||||
|
return "CborIntegerType";
|
||||||
|
break;
|
||||||
|
case CborByteStringType:
|
||||||
|
return "CborByteStringType";
|
||||||
|
break;
|
||||||
|
case CborTextStringType:
|
||||||
|
return "CborTextStringType";
|
||||||
|
break;
|
||||||
|
case CborArrayType:
|
||||||
|
return "CborArrayType";
|
||||||
|
break;
|
||||||
|
case CborMapType:
|
||||||
|
return "CborMapType";
|
||||||
|
break;
|
||||||
|
case CborTagType:
|
||||||
|
return "CborTagType";
|
||||||
|
break;
|
||||||
|
case CborSimpleType:
|
||||||
|
return "CborSimpleType";
|
||||||
|
break;
|
||||||
|
case CborBooleanType:
|
||||||
|
return "CborBooleanType";
|
||||||
|
break;
|
||||||
|
case CborNullType:
|
||||||
|
return "CborNullType";
|
||||||
|
break;
|
||||||
|
case CborUndefinedType:
|
||||||
|
return "CborUndefinedType";
|
||||||
|
break;
|
||||||
|
case CborHalfFloatType:
|
||||||
|
return "CborHalfFloatType";
|
||||||
|
break;
|
||||||
|
case CborFloatType:
|
||||||
|
return "CborFloatType";
|
||||||
|
break;
|
||||||
|
case CborDoubleType:
|
||||||
|
return "CborDoubleType";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "Invalid type";
|
||||||
|
}
|
||||||
|
|
||||||
void ctap_get_info(CborEncoder * encoder)
|
void ctap_get_info(CborEncoder * encoder)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -54,10 +102,476 @@ void ctap_get_info(CborEncoder * encoder)
|
|||||||
}
|
}
|
||||||
ret = cbor_encoder_close_container(encoder, &map);
|
ret = cbor_encoder_close_container(encoder, &map);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_client_data_hash(CTAP_makeCredential * MC, CborValue * val)
|
||||||
|
{
|
||||||
|
size_t sz;
|
||||||
|
int ret;
|
||||||
|
if (cbor_value_get_type(val) != CborByteStringType)
|
||||||
|
{
|
||||||
|
printf("error, wrong type\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = cbor_value_calculate_string_length(val, &sz);
|
||||||
|
check_ret(ret);
|
||||||
|
if (sz != CLIENT_DATA_HASH_SIZE)
|
||||||
|
{
|
||||||
|
printf("error, wrong size for client data hash\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = cbor_value_copy_byte_string(val, MC->clientDataHash, &sz, NULL);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
MC->paramsParsed |= PARAM_clientDataHash;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int parse_user(CTAP_makeCredential * MC, CborValue * val)
|
||||||
|
{
|
||||||
|
size_t sz, map_length;
|
||||||
|
uint8_t key[8];
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
CborValue map;
|
||||||
|
|
||||||
|
|
||||||
|
if (cbor_value_get_type(val) != CborMapType)
|
||||||
|
{
|
||||||
|
printf("error, wrong type\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_enter_container(val,&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
ret = cbor_value_get_map_length(val, &map_length);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
for (i = 0; i < map_length; i++)
|
||||||
|
{
|
||||||
|
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf("Error, expecting text string type for user map key, got %s\n", cbor_value_get_type_string(&map));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = sizeof(key);
|
||||||
|
ret = cbor_value_copy_text_string(&map, key, &sz, NULL);
|
||||||
|
|
||||||
|
if (ret == CborErrorOutOfMemory)
|
||||||
|
{
|
||||||
|
printf("Error, rp map key is too large\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
check_ret(ret);
|
||||||
|
key[sizeof(key) - 1] = 0;
|
||||||
|
|
||||||
|
ret = cbor_value_advance(&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
if (strcmp(key, "id") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (cbor_value_get_type(&map) != CborByteStringType)
|
||||||
|
{
|
||||||
|
printf("Error, expecting byte string type for rp map value\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = USER_ID_MAX_SIZE;
|
||||||
|
ret = cbor_value_copy_byte_string(&map, MC->userId, &sz, NULL);
|
||||||
|
if (ret == CborErrorOutOfMemory)
|
||||||
|
{
|
||||||
|
printf("Error, USER_ID is too large\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
MC->userIdSize = sz;
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "name") == 0)
|
||||||
|
{
|
||||||
|
sz = USER_NAME_LIMIT;
|
||||||
|
ret = cbor_value_copy_text_string(&map, MC->userName, &sz, NULL);
|
||||||
|
if (ret != CborErrorOutOfMemory)
|
||||||
|
{ // Just truncate the name it's okay
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
MC->userName[USER_NAME_LIMIT - 1] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ignoring key %s for user map\n", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_advance(&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MC->paramsParsed |= PARAM_user;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_pub_key_cred_param(CborValue * val, uint8_t * cred_type, int32_t * alg_type)
|
||||||
|
{
|
||||||
|
CborValue map;
|
||||||
|
CborValue cred;
|
||||||
|
CborValue alg;
|
||||||
|
int ret;
|
||||||
|
uint8_t type_str[16];
|
||||||
|
size_t sz = sizeof(type_str);
|
||||||
|
|
||||||
|
if (cbor_value_get_type(val) != CborMapType)
|
||||||
|
{
|
||||||
|
printf("error, expecting map type\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_map_find_value(val, "type", &cred);
|
||||||
|
check_ret(ret);
|
||||||
|
ret = cbor_value_map_find_value(val, "alg", &alg);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
if (cbor_value_get_type(&cred) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf("Error, parse_pub_key could not find credential param\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (cbor_value_get_type(&alg) != CborIntegerType)
|
||||||
|
{
|
||||||
|
printf("Error, parse_pub_key could not find alg param\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_copy_text_string(&cred, type_str, &sz, NULL);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
type_str[sizeof(type_str) - 1] = 0;
|
||||||
|
|
||||||
|
if (strcmp(type_str, "public-key") == 0)
|
||||||
|
{
|
||||||
|
*cred_type = PUB_KEY_CRED_PUB_KEY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*cred_type = PUB_KEY_CRED_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_get_int_checked(&alg, alg_type);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if public key credential+algorithm type is supported
|
||||||
|
static int pub_key_cred_param_supported(uint8_t cred, int32_t alg)
|
||||||
|
{
|
||||||
|
if (cred == PUB_KEY_CRED_PUB_KEY)
|
||||||
|
{
|
||||||
|
if (alg == COSE_ALG_ES256)
|
||||||
|
{
|
||||||
|
return CREDENTIAL_IS_SUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CREDENTIAL_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
|
||||||
|
{
|
||||||
|
size_t sz, arr_length;
|
||||||
|
uint8_t cred_type;
|
||||||
|
int32_t alg_type;
|
||||||
|
uint8_t key[8];
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
CborValue arr;
|
||||||
|
|
||||||
|
|
||||||
|
if (cbor_value_get_type(val) != CborArrayType)
|
||||||
|
{
|
||||||
|
printf("error, expecting array type\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_enter_container(val,&arr);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
ret = cbor_value_get_array_length(val, &arr_length);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
for (i = 0; i < arr_length; i++)
|
||||||
|
{
|
||||||
|
if (parse_pub_key_cred_param(&arr, &cred_type, &alg_type) == 0)
|
||||||
|
{
|
||||||
|
if (pub_key_cred_param_supported(cred_type, alg_type) == CREDENTIAL_IS_SUPPORTED)
|
||||||
|
{
|
||||||
|
MC->publicKeyCredentialType = cred_type;
|
||||||
|
MC->COSEAlgorithmIdentifier = alg_type;
|
||||||
|
MC->paramsParsed |= PARAM_pubKeyCredParams;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Continue? fail?
|
||||||
|
}
|
||||||
|
ret = cbor_value_advance(&arr);
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Error, no public key credential parameters are supported!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int parse_rp(CTAP_makeCredential * MC, CborValue * val)
|
||||||
|
{
|
||||||
|
size_t sz, map_length;
|
||||||
|
uint8_t key[8];
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
CborValue map;
|
||||||
|
|
||||||
|
|
||||||
|
if (cbor_value_get_type(val) != CborMapType)
|
||||||
|
{
|
||||||
|
printf("error, wrong type\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_enter_container(val,&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
ret = cbor_value_get_map_length(val, &map_length);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
for (i = 0; i < map_length; i++)
|
||||||
|
{
|
||||||
|
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf("Error, expecting text string type for rp map key, got %s\n", cbor_value_get_type_string(&map));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = sizeof(key);
|
||||||
|
ret = cbor_value_copy_text_string(&map, key, &sz, NULL);
|
||||||
|
|
||||||
|
if (ret == CborErrorOutOfMemory)
|
||||||
|
{
|
||||||
|
printf("Error, rp map key is too large\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
check_ret(ret);
|
||||||
|
key[sizeof(key) - 1] = 0;
|
||||||
|
|
||||||
|
ret = cbor_value_advance(&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
if (cbor_value_get_type(&map) != CborTextStringType)
|
||||||
|
{
|
||||||
|
printf("Error, expecting text string type for rp map value\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, "id") == 0)
|
||||||
|
{
|
||||||
|
sz = DOMAIN_NAME_MAX_SIZE;
|
||||||
|
ret = cbor_value_copy_text_string(&map, MC->rpId, &sz, NULL);
|
||||||
|
if (ret == CborErrorOutOfMemory)
|
||||||
|
{
|
||||||
|
printf("Error, RP_ID is too large\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
MC->rpId[DOMAIN_NAME_MAX_SIZE] = 0; // Extra byte defined in struct.
|
||||||
|
MC->rpIdSize = sz;
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "name") == 0)
|
||||||
|
{
|
||||||
|
sz = RP_NAME_LIMIT;
|
||||||
|
ret = cbor_value_copy_text_string(&map, MC->rpName, &sz, NULL);
|
||||||
|
if (ret != CborErrorOutOfMemory)
|
||||||
|
{ // Just truncate the name it's okay
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
MC->rpName[RP_NAME_LIMIT - 1] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ignoring key %s for RP map\n", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_advance(&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MC->paramsParsed |= PARAM_rp;
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
int key;
|
||||||
|
size_t map_length;
|
||||||
|
size_t sz;
|
||||||
|
CborParser parser;
|
||||||
|
CborValue it,map;
|
||||||
|
|
||||||
|
memset(MC, 0, sizeof(CTAP_makeCredential));
|
||||||
|
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
CborType type = cbor_value_get_type(&it);
|
||||||
|
if (type != CborMapType)
|
||||||
|
{
|
||||||
|
printf("Error, expecting cbor map\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_enter_container(&it,&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
ret = cbor_value_get_map_length(&it, &map_length);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
printf("map has %d elements\n",map_length);
|
||||||
|
|
||||||
|
for (i = 0; i < map_length; i++)
|
||||||
|
{
|
||||||
|
type = cbor_value_get_type(&map);
|
||||||
|
if (type != CborIntegerType)
|
||||||
|
{
|
||||||
|
printf("Error, expecting int for map key\n");
|
||||||
|
}
|
||||||
|
ret = cbor_value_get_int_checked(&map, &key);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
ret = cbor_value_advance(&map);
|
||||||
|
check_ret(ret);
|
||||||
|
|
||||||
|
switch(key)
|
||||||
|
{
|
||||||
|
|
||||||
|
case MC_clientDataHash:
|
||||||
|
printf("CTAP_clientDataHash\n");
|
||||||
|
|
||||||
|
ret = parse_client_data_hash(MC, &map);
|
||||||
|
|
||||||
|
printf(" "); dump_hex(MC->clientDataHash, 32);
|
||||||
|
break;
|
||||||
|
case MC_rp:
|
||||||
|
printf("CTAP_rp\n");
|
||||||
|
|
||||||
|
ret = parse_rp(MC, &map);
|
||||||
|
|
||||||
|
printf(" ID: %s\n", MC->rpId);
|
||||||
|
printf(" name: %s\n", MC->rpName);
|
||||||
|
break;
|
||||||
|
case MC_user:
|
||||||
|
printf("CTAP_user\n");
|
||||||
|
|
||||||
|
ret = parse_user(MC, &map);
|
||||||
|
|
||||||
|
printf(" ID: "); dump_hex(MC->userId, MC->userIdSize);
|
||||||
|
printf(" name: %s\n", MC->userName);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MC_pubKeyCredParams:
|
||||||
|
printf("CTAP_pubKeyCredParams\n");
|
||||||
|
|
||||||
|
ret = parse_pub_key_cred_params(MC, &map);
|
||||||
|
|
||||||
|
printf(" cred_type: 0x%02x\n", MC->publicKeyCredentialType);
|
||||||
|
printf(" alg_type: %d\n", MC->COSEAlgorithmIdentifier);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MC_excludeList:
|
||||||
|
printf("CTAP_excludeList\n");
|
||||||
|
break;
|
||||||
|
case MC_extensions:
|
||||||
|
printf("CTAP_extensions\n");
|
||||||
|
break;
|
||||||
|
case MC_options:
|
||||||
|
printf("CTAP_options\n");
|
||||||
|
break;
|
||||||
|
case MC_pinAuth:
|
||||||
|
printf("CTAP_pinAuth\n");
|
||||||
|
break;
|
||||||
|
case MC_pinProtocol:
|
||||||
|
printf("CTAP_pinProtocol\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("invalid key %d\n", key);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
cbor_value_advance(&map);
|
||||||
|
check_ret(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ctap_make_credential(CborEncoder * encoder, uint8_t * request, int length)
|
||||||
|
{
|
||||||
|
CTAP_makeCredential MC;
|
||||||
|
CTAP_authData authData;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
ret = ctap_parse_make_credential(&MC,encoder,request,length);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
printf("error, parse_make_credential failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
|
||||||
|
{
|
||||||
|
printf("error, required parameter(s) for makeCredential are missing\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(MC.rpId, MC.rpIdSize);
|
||||||
|
crypto_sha256_final(authData.rpIdHash);
|
||||||
|
|
||||||
|
authData.flags = (ctap_user_presence_test() << 0);
|
||||||
|
authData.flags |= (ctap_user_verification(0) << 2);
|
||||||
|
authData.flags |= (1 << 6);//include attestation data
|
||||||
|
|
||||||
|
authData.signCount = ctap_atomic_count();
|
||||||
|
|
||||||
|
memmove(authData.attest.aaguid, CTAP_AAGUID, 16);
|
||||||
|
authData.attest.credLenL = CREDENTIAL_ID_SIZE & 0x00FF;
|
||||||
|
authData.attest.credLenH = (CREDENTIAL_ID_SIZE & 0xFF00) >> 8;
|
||||||
|
|
||||||
|
#if CREDENTIAL_ID_SIZE != 32
|
||||||
|
#error "need to update credential ID layout"
|
||||||
|
#else
|
||||||
|
memmove(authData.attest.credentialId, authData.rpIdHash, 16);
|
||||||
|
ctap_generate_rng(authData.attest.credentialId + 16, 16);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t ctap_handle_packet(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
uint8_t ctap_handle_packet(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
||||||
{
|
{
|
||||||
uint8_t cmd = *pkt_raw;
|
uint8_t cmd = *pkt_raw;
|
||||||
@ -73,11 +587,16 @@ uint8_t ctap_handle_packet(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
CborEncoder encoder;
|
CborEncoder encoder;
|
||||||
cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
|
cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
|
||||||
|
|
||||||
|
printf("cbor req: "); dump_hex(pkt_raw, length - 1);
|
||||||
|
|
||||||
|
|
||||||
switch(cmd)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case CTAP_MAKE_CREDENTIAL:
|
case CTAP_MAKE_CREDENTIAL:
|
||||||
printf("CTAP_MAKE_CREDENTIAL\n");
|
printf("CTAP_MAKE_CREDENTIAL\n");
|
||||||
|
ctap_make_credential(&encoder, pkt_raw, length - 1);
|
||||||
|
dump_hex(buf, cbor_encoder_get_buffer_size(&encoder, buf));
|
||||||
|
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
|
||||||
break;
|
break;
|
||||||
case CTAP_GET_ASSERTION:
|
case CTAP_GET_ASSERTION:
|
||||||
printf("CTAP_GET_ASSERTION\n");
|
printf("CTAP_GET_ASSERTION\n");
|
||||||
|
109
ctap.h
109
ctap.h
@ -13,15 +13,124 @@
|
|||||||
|
|
||||||
#define CTAP_AAGUID ((uint8_t*)"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")
|
#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_keyAgreement 0x03
|
||||||
|
#define CP_pinAuth 0x04
|
||||||
|
#define CP_newPinEnc 0x05
|
||||||
|
#define CP_pinHashEnc 0x06
|
||||||
|
#define CP_getKeyAgreement 0x07
|
||||||
|
#define CP_getRetries 0x08
|
||||||
|
|
||||||
|
#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 CREDENTIAL_ID_SIZE 32
|
||||||
|
|
||||||
|
#define PUB_KEY_CRED_PUB_KEY 0x01
|
||||||
|
#define PUB_KEY_CRED_UNKNOWN 0x3F
|
||||||
|
|
||||||
|
#define CREDENTIAL_IS_SUPPORTED 1
|
||||||
|
#define CREDENTIAL_NOT_SUPPORTED 0
|
||||||
|
|
||||||
|
#define COSE_ALG_ES256 -7
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t aaguid[16];
|
||||||
|
uint8_t credLenL;
|
||||||
|
uint8_t credLenH;
|
||||||
|
uint8_t credentialId[CREDENTIAL_ID_SIZE];
|
||||||
|
} __attribute__((packed)) CTAP_attestHeader;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t rpIdHash[32];
|
||||||
|
uint8_t flags;
|
||||||
|
uint32_t signCount;
|
||||||
|
CTAP_attestHeader attest;
|
||||||
|
} __attribute__((packed)) CTAP_authData;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t * data;
|
uint8_t * data;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
} CTAP_RESPONSE;
|
} CTAP_RESPONSE;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t paramsParsed;
|
||||||
|
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||||
|
|
||||||
|
uint8_t rpId[DOMAIN_NAME_MAX_SIZE + 1]; // extra for NULL termination
|
||||||
|
size_t rpIdSize;
|
||||||
|
uint8_t rpName[RP_NAME_LIMIT];
|
||||||
|
|
||||||
|
uint8_t userId[USER_ID_MAX_SIZE];
|
||||||
|
uint8_t userIdSize;
|
||||||
|
uint8_t userName[USER_NAME_LIMIT];
|
||||||
|
|
||||||
|
uint8_t publicKeyCredentialType;
|
||||||
|
int32_t COSEAlgorithmIdentifier;
|
||||||
|
|
||||||
|
uint8_t pinProtocol;
|
||||||
|
} CTAP_makeCredential;
|
||||||
|
|
||||||
uint8_t ctap_handle_packet(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);
|
uint8_t ctap_handle_packet(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
extern int ctap_generate_rng(uint8_t * dst, size_t num);
|
||||||
|
|
||||||
|
// Increment atomic counter and return it
|
||||||
|
extern uint32_t ctap_atomic_count();
|
||||||
|
|
||||||
|
// 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
|
// Must be implemented by application
|
||||||
// data is HID_MESSAGE_SIZE long in bytes
|
// data is HID_MESSAGE_SIZE long in bytes
|
||||||
extern void ctap_write_block(uint8_t * data);
|
extern void ctap_write_block(uint8_t * data);
|
||||||
|
@ -53,4 +53,31 @@ void ctap_write(void * _data, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ctap_user_presence_test()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctap_user_verification(uint8_t arg)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t ctap_atomic_count()
|
||||||
|
{
|
||||||
|
static uint32_t counter = 25;
|
||||||
|
return counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctap_generate_rng(uint8_t * dst, size_t num)
|
||||||
|
{
|
||||||
|
FILE * urand = fopen("/dev/urandom","r");
|
||||||
|
if (urand == NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fread(dst, 1, num, urand);
|
||||||
|
fclose(urand);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user