solo1/fido2/ctap_parse.c

1083 wiersze
30 KiB
C

/*
Copyright 2018 Conor Patrick
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdint.h>
#include "cbor.h"
#include "ctap.h"
#include "ctap_parse.h"
#include "ctap_errors.h"
#include "cose_key.h"
#include "util.h"
#include "log.h"
void _check_ret(CborError ret, int line, const char * filename)
{
if (ret != CborNoError)
{
printf1(TAG_ERR,"CborError: 0x%x: %s: %d: %s\n", ret, filename, line, cbor_error_string(ret));
/*exit(1);*/
}
}
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;
default:
return "Invalid type";
}
}
uint8_t 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)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
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)
{
printf2(TAG_ERR,"Error, expecting text string type for user map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
sz = sizeof(key);
ret = cbor_value_copy_text_string(&map, (char *)key, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, rp map key is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
check_ret(ret);
key[sizeof(key) - 1] = 0;
ret = cbor_value_advance(&map);
check_ret(ret);
if (strcmp((const char*)key, "id") == 0)
{
if (cbor_value_get_type(&map) != CborByteStringType)
{
printf2(TAG_ERR,"Error, expecting byte string type for rp map value\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
sz = USER_ID_MAX_SIZE;
ret = cbor_value_copy_byte_string(&map, MC->user.id, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, USER_ID is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
MC->user.id_size = sz;
check_ret(ret);
}
else if (strcmp((const char *)key, "name") == 0)
{
sz = USER_NAME_LIMIT;
ret = cbor_value_copy_text_string(&map, (char *)MC->user.name, &sz, NULL);
if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay
check_ret(ret);
}
MC->user.name[USER_NAME_LIMIT - 1] = 0;
}
else
{
printf1(TAG_PARSE,"ignoring key %s for user map\n", key);
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
MC->paramsParsed |= PARAM_user;
return 0;
}
uint8_t parse_pub_key_cred_param(CborValue * val, uint8_t * cred_type, int32_t * alg_type)
{
CborValue cred;
CborValue alg;
int ret;
uint8_t type_str[16];
size_t sz = sizeof(type_str);
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, expecting map type, got %s\n", cbor_value_get_type_string(val));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
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)
{
printf2(TAG_ERR,"Error, parse_pub_key could not find credential param\n");
return CTAP2_ERR_MISSING_PARAMETER;
}
if (cbor_value_get_type(&alg) != CborIntegerType)
{
printf2(TAG_ERR,"Error, parse_pub_key could not find alg param\n");
return CTAP2_ERR_MISSING_PARAMETER;
}
ret = cbor_value_copy_text_string(&cred, (char*)type_str, &sz, NULL);
check_ret(ret);
type_str[sizeof(type_str) - 1] = 0;
if (strcmp((const char*)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, (int*)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;
}
uint8_t parse_pub_key_cred_params(CTAP_makeCredential * MC, CborValue * val)
{
size_t arr_length;
uint8_t cred_type;
int32_t alg_type;
int ret;
int i;
CborValue arr;
if (cbor_value_get_type(val) != CborArrayType)
{
printf2(TAG_ERR,"error, expecting array type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
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 ((ret = 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?
return ret;
}
ret = cbor_value_advance(&arr);
check_ret(ret);
}
printf2(TAG_ERR,"Error, no public key credential parameters are supported!\n");
return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
}
uint8_t parse_fixed_byte_string(CborValue * map, uint8_t * dst, int len)
{
size_t sz;
int ret;
if (cbor_value_get_type(map) == CborByteStringType)
{
sz = len;
ret = cbor_value_copy_byte_string(map, dst, &sz, NULL);
check_ret(ret);
if (sz != len)
{
return CTAP1_ERR_OTHER;
}
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
return 0;
}
uint8_t parse_rp_id(struct rpId * rp, CborValue * val)
{
size_t sz = DOMAIN_NAME_MAX_SIZE;
int ret = cbor_value_copy_text_string(val, (char*)rp->id, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, RP_ID is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
check_ret(ret);
rp->id[DOMAIN_NAME_MAX_SIZE] = 0; // Extra byte defined in struct.
rp->size = sz;
return 0;
}
uint8_t parse_rp(struct rpId * rp, CborValue * val)
{
size_t sz, map_length;
char key[8];
int ret;
int i;
CborValue map;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(val,&map);
check_ret(ret);
ret = cbor_value_get_map_length(val, &map_length);
check_ret(ret);
rp->size = 0;
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborTextStringType)
{
printf2(TAG_ERR,"Error, expecting text string type for rp map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
sz = sizeof(key);
ret = cbor_value_copy_text_string(&map, key, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, rp map key is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
check_ret(ret);
key[sizeof(key) - 1] = 0;
ret = cbor_value_advance(&map);
check_ret(ret);
if (cbor_value_get_type(&map) != CborTextStringType)
{
printf2(TAG_ERR,"Error, expecting text string type for rp map value\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
if (strcmp(key, "id") == 0)
{
ret = parse_rp_id(rp, &map);
if (ret != 0)
{
return ret;
}
}
else if (strcmp(key, "name") == 0)
{
sz = RP_NAME_LIMIT;
ret = cbor_value_copy_text_string(&map, (char*)rp->name, &sz, NULL);
if (ret != CborErrorOutOfMemory)
{ // Just truncate the name it's okay
check_ret(ret);
}
rp->name[RP_NAME_LIMIT - 1] = 0;
}
else
{
printf1(TAG_PARSE,"ignoring key %s for RP map\n", key);
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
if (rp->size == 0)
{
printf2(TAG_ERR,"Error, no RPID provided\n");
return CTAP2_ERR_MISSING_PARAMETER;
}
return 0;
}
uint8_t parse_options(CborValue * val, uint8_t * rk, uint8_t * uv)
{
size_t sz, map_length;
char key[8];
int ret;
int i;
_Bool b;
CborValue map;
if (cbor_value_get_type(val) != CborMapType)
{
printf2(TAG_ERR,"error, wrong type\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
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)
{
printf2(TAG_ERR,"Error, expecting text string type for options map key, got %s\n", cbor_value_get_type_string(&map));
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
sz = sizeof(key);
ret = cbor_value_copy_text_string(&map, key, &sz, NULL);
if (ret == CborErrorOutOfMemory)
{
printf2(TAG_ERR,"Error, rp map key is too large\n");
return CTAP2_ERR_LIMIT_EXCEEDED;
}
check_ret(ret);
key[sizeof(key) - 1] = 0;
ret = cbor_value_advance(&map);
check_ret(ret);
if (cbor_value_get_type(&map) != CborBooleanType)
{
printf2(TAG_ERR,"Error, expecting text string type for rp map value\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
if (strcmp(key, "rk") == 0)
{
ret = cbor_value_get_boolean(&map, &b);
check_ret(ret);
*rk = b;
}
else if (strcmp(key, "uv") == 0)
{
ret = cbor_value_get_boolean(&map, &b);
check_ret(ret);
*uv = b;
}
else
{
printf1(TAG_PARSE,"ignoring key %s for option map\n", key);
}
}
return 0;
}
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length)
{
int ret;
int i;
int key;
size_t map_length;
CborParser parser;
CborValue it,map;
memset(MC, 0, sizeof(CTAP_makeCredential));
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_retr(ret);
CborType type = cbor_value_get_type(&it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
ret = cbor_value_enter_container(&it,&map);
check_ret(ret);
ret = cbor_value_get_map_length(&it, &map_length);
check_ret(ret);
printf1(TAG_MC,"map has %d elements\n",map_length);
for (i = 0; i < map_length; i++)
{
type = cbor_value_get_type(&map);
if (type != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
ret = 0;
switch(key)
{
case MC_clientDataHash:
printf1(TAG_MC,"CTAP_clientDataHash\n");
ret = parse_fixed_byte_string(&map, MC->clientDataHash, CLIENT_DATA_HASH_SIZE);
if (ret == 0)
{
MC->paramsParsed |= PARAM_clientDataHash;
}
printf1(TAG_MC," "); dump_hex1(TAG_MC,MC->clientDataHash, 32);
break;
case MC_rp:
printf1(TAG_MC,"CTAP_rp\n");
ret = parse_rp(&MC->rp, &map);
if (ret == 0)
{
MC->paramsParsed |= PARAM_rp;
}
printf1(TAG_MC," ID: %s\n", MC->rp.id);
printf1(TAG_MC," name: %s\n", MC->rp.name);
break;
case MC_user:
printf1(TAG_MC,"CTAP_user\n");
ret = parse_user(MC, &map);
printf1(TAG_MC," ID: "); dump_hex1(TAG_MC, MC->user.id, MC->user.id_size);
printf1(TAG_MC," name: %s\n", MC->user.name);
break;
case MC_pubKeyCredParams:
printf1(TAG_MC,"CTAP_pubKeyCredParams\n");
ret = parse_pub_key_cred_params(MC, &map);
printf1(TAG_MC," cred_type: 0x%02x\n", MC->publicKeyCredentialType);
printf1(TAG_MC," alg_type: %d\n", MC->COSEAlgorithmIdentifier);
break;
case MC_excludeList:
printf1(TAG_MC,"CTAP_excludeList\n");
if( cbor_value_get_type(&map) == CborArrayType )
{
ret = cbor_value_enter_container(&map, &MC->excludeList);
check_ret(ret);
ret = cbor_value_get_array_length(&map, &MC->excludeListSize);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
printf1(TAG_MC,"CTAP_excludeList done\n");
break;
case MC_extensions:
printf1(TAG_MC,"CTAP_extensions\n");
break;
case MC_options:
printf1(TAG_MC,"CTAP_options\n");
ret = parse_options(&map, &MC->rk, &MC->uv);
check_retr(ret);
break;
case MC_pinAuth:
printf1(TAG_MC,"CTAP_pinAuth\n");
ret = parse_fixed_byte_string(&map, MC->pinAuth, 16);
check_retr(ret);
MC->pinAuthPresent = 1;
break;
case MC_pinProtocol:
printf1(TAG_MC,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, &MC->pinProtocol);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
default:
printf1(TAG_MC,"invalid key %d\n", key);
}
if (ret != 0)
{
return ret;
}
cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}
uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred)
{
int ret;
size_t buflen;
char type[12];
CborValue val;
if (cbor_value_get_type(arr) != CborMapType)
{
printf2(TAG_ERR,"Error, CborMapType expected in credential\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_map_find_value(arr, "id", &val);
check_ret(ret);
if (cbor_value_get_type(&val) != CborByteStringType)
{
printf2(TAG_ERR,"Error, No valid ID field (%s)\n", cbor_value_get_type_string(&val));
return CTAP2_ERR_MISSING_PARAMETER;
}
buflen = sizeof(struct Credential);
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential, &buflen, NULL);
if (buflen != CREDENTIAL_ID_SIZE)
{
printf2(TAG_ERR,"Error, credential is incorrect length\n");
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail?
}
ret = cbor_value_map_find_value(arr, "type", &val);
check_ret(ret);
if (cbor_value_get_type(&val) != CborTextStringType)
{
printf2(TAG_ERR,"Error, No valid type field\n");
return CTAP2_ERR_MISSING_PARAMETER;
}
buflen = sizeof(type);
cbor_value_copy_text_string(&val, type, &buflen, NULL);
if (strcmp(type, "public-key") == 0)
{
cred->type = PUB_KEY_CRED_PUB_KEY;
}
else
{
cred->type = PUB_KEY_CRED_UNKNOWN;
}
return 0;
}
uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it)
{
CborValue arr;
size_t len;
int i,ret;
CTAP_credentialDescriptor * cred;
if (cbor_value_get_type(it) != CborArrayType)
{
printf2(TAG_ERR,"Error, expecting cbor array\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(it,&arr);
check_ret(ret);
ret = cbor_value_get_array_length(it, &len);
check_ret(ret);
GA->credLen = 0;
for(i = 0; i < len; i++)
{
if (i >= ALLOW_LIST_MAX_SIZE)
{
printf1(TAG_PARSE,"Error, out of memory for allow list.\n");
return CTAP2_ERR_TOO_MANY_ELEMENTS;
}
GA->credLen += 1;
cred = &GA->creds[i];
ret = parse_credential_descriptor(&arr,cred);
check_retr(ret);
ret = cbor_value_advance(&arr);
check_ret(ret);
}
return 0;
}
uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length)
{
int ret;
int i;
int key;
size_t map_length;
CborParser parser;
CborValue it,map;
memset(GA, 0, sizeof(CTAP_getAssertion));
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret);
CborType type = cbor_value_get_type(&it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(&it,&map);
check_ret(ret);
ret = cbor_value_get_map_length(&it, &map_length);
check_ret(ret);
printf1(TAG_GA,"GA map has %d elements\n",map_length);
for (i = 0; i < map_length; i++)
{
type = cbor_value_get_type(&map);
if (type != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
ret = 0;
switch(key)
{
case GA_clientDataHash:
printf1(TAG_GA,"GA_clientDataHash\n");
ret = parse_fixed_byte_string(&map, GA->clientDataHash, CLIENT_DATA_HASH_SIZE);
check_retr(ret);
printf1(TAG_GA," "); dump_hex1(TAG_GA, GA->clientDataHash, 32);
break;
case GA_rpId:
printf1(TAG_GA,"GA_rpId\n");
ret = parse_rp_id(&GA->rp, &map);
printf1(TAG_GA," ID: %s\n", GA->rp.id);
break;
case GA_allowList:
printf1(TAG_GA,"GA_allowList\n");
ret = parse_allow_list(GA, &map);
if (ret == 0)
{
}
break;
case GA_extensions:
printf1(TAG_GA,"GA_extensions\n");
break;
case GA_options:
printf1(TAG_GA,"CTAP_options\n");
ret = parse_options(&map, &GA->rk, &GA->uv);
check_retr(ret);
break;
case GA_pinAuth:
printf1(TAG_GA,"CTAP_pinAuth\n");
ret = parse_fixed_byte_string(&map, GA->pinAuth, 16);
check_retr(ret);
GA->pinAuthPresent = 1;
break;
case GA_pinProtocol:
printf1(TAG_GA,"CTAP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, &GA->pinProtocol);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
}
if (ret != 0)
{
printf2(TAG_ERR,"error, parsing failed\n");
return ret;
}
cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}
uint8_t parse_cose_key(CborValue * it, uint8_t * x, uint8_t * y, int * kty, int * crv)
{
CborValue map;
size_t map_length;
int i,ret,key;
int xkey = 0,ykey = 0;
*kty = 0;
*crv = 0;
CborType type = cbor_value_get_type(it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(it,&map);
check_ret(ret);
ret = cbor_value_get_map_length(it, &map_length);
check_ret(ret);
printf1(TAG_PARSE,"cose key has %d elements\n",map_length);
for (i = 0; i < map_length; i++)
{
if (cbor_value_get_type(&map) != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
switch(key)
{
case COSE_KEY_LABEL_KTY:
printf1(TAG_PARSE,"COSE_KEY_LABEL_KTY\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, kty);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case COSE_KEY_LABEL_ALG:
printf1(TAG_PARSE,"COSE_KEY_LABEL_ALG\n");
break;
case COSE_KEY_LABEL_CRV:
printf1(TAG_PARSE,"COSE_KEY_LABEL_CRV\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
ret = cbor_value_get_int_checked(&map, crv);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case COSE_KEY_LABEL_X:
printf1(TAG_PARSE,"COSE_KEY_LABEL_X\n");
ret = parse_fixed_byte_string(&map, x, 32);
check_retr(ret);
xkey = 1;
break;
case COSE_KEY_LABEL_Y:
printf1(TAG_PARSE,"COSE_KEY_LABEL_Y\n");
ret = parse_fixed_byte_string(&map, y, 32);
check_retr(ret);
ykey = 1;
break;
default:
printf1(TAG_PARSE,"Warning, unrecognized cose key option %d\n", key);
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
if (xkey == 0 || ykey == 0 || *kty == 0 || *crv == 0)
{
return CTAP2_ERR_MISSING_PARAMETER;
}
return 0;
}
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length)
{
int ret;
int i;
int key;
size_t map_length;
size_t sz;
CborParser parser;
CborValue it,map;
memset(CP, 0, sizeof(CTAP_clientPin));
ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret);
CborType type = cbor_value_get_type(&it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_enter_container(&it,&map);
check_ret(ret);
ret = cbor_value_get_map_length(&it, &map_length);
check_ret(ret);
printf1(TAG_CP,"CP map has %d elements\n",map_length);
for (i = 0; i < map_length; i++)
{
type = cbor_value_get_type(&map);
if (type != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);
ret = cbor_value_advance(&map);
check_ret(ret);
ret = 0;
switch(key)
{
case CP_pinProtocol:
printf1(TAG_CP,"CP_pinProtocol\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
cbor_value_get_int_checked(&map, &CP->pinProtocol);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CP_subCommand:
printf1(TAG_CP,"CP_subCommand\n");
if (cbor_value_get_type(&map) == CborIntegerType)
{
cbor_value_get_int_checked(&map, &CP->subCommand);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CP_keyAgreement:
printf1(TAG_CP,"CP_keyAgreement\n");
ret = parse_cose_key(&map, CP->keyAgreement.pubkey.x, CP->keyAgreement.pubkey.y, &CP->keyAgreement.kty, &CP->keyAgreement.crv);
check_retr(ret);
CP->keyAgreementPresent = 1;
break;
case CP_pinAuth:
printf1(TAG_CP,"CP_pinAuth\n");
ret = parse_fixed_byte_string(&map, CP->pinAuth, 16);
check_retr(ret);
CP->pinAuthPresent = 1;
break;
case CP_newPinEnc:
printf1(TAG_CP,"CP_newPinEnc\n");
if (cbor_value_get_type(&map) == CborByteStringType)
{
ret = cbor_value_calculate_string_length(&map, &sz);
check_ret(ret);
if (sz > NEW_PIN_ENC_MAX_SIZE)
{
return CTAP1_ERR_OTHER;
}
CP->newPinEncSize = sz;
sz = NEW_PIN_ENC_MAX_SIZE;
ret = cbor_value_copy_byte_string(&map, CP->newPinEnc, &sz, NULL);
check_ret(ret);
}
else
{
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
break;
case CP_pinHashEnc:
printf1(TAG_CP,"CP_pinHashEnc\n");
ret = parse_fixed_byte_string(&map, CP->pinHashEnc, 16);
check_retr(ret);
CP->pinHashEncPresent = 1;
break;
case CP_getKeyAgreement:
printf1(TAG_CP,"CP_getKeyAgreement\n");
ret = cbor_value_get_boolean(&map, &CP->getKeyAgreement);
check_ret(ret);
break;
case CP_getRetries:
printf1(TAG_CP,"CP_getRetries\n");
ret = cbor_value_get_boolean(&map, &CP->getRetries);
check_ret(ret);
break;
default:
printf1(TAG_CP,"Unknown key %d\n", key);
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}