1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-13 08:40:26 +01:00

Merge pull request #18663 from Ollrogge/fido2_follow_up2

sys/fido2: follow up continued
This commit is contained in:
Karl Fessel 2024-11-28 10:09:47 +00:00 committed by GitHub
commit 737f675442
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 671 additions and 392 deletions

View File

@ -10,7 +10,9 @@ endif
ifneq (,$(filter fido2_ctap,$(USEMODULE)))
FEATURES_REQUIRED += periph_flashpage
ifeq (,$(filter native,$(CPU)))
FEATURES_REQUIRED += periph_flashpage_in_address_space
endif
FEATURES_REQUIRED += periph_gpio_irq
USEPKG += tiny-asn1
@ -26,4 +28,5 @@ ifneq (,$(filter fido2_ctap,$(USEMODULE)))
USEMODULE += crypto_aes_256
USEMODULE += hashes
USEMODULE += fido2
USEMODULE += fmt
endif

View File

@ -248,26 +248,26 @@ static uint8_t _pin_token[CTAP_PIN_TOKEN_SZ];
*/
static int _rem_pin_att_boot = CTAP_PIN_MAX_ATTS_BOOT;
int fido2_ctap_init(void)
ctap_status_code_t fido2_ctap_init(void)
{
int ret;
ret = fido2_ctap_mem_init();
if (ret != CTAP2_OK) {
return -EPROTO;
return ret;
}
ret = fido2_ctap_mem_read_state_from_flash(&_state);
if (ret != CTAP2_OK) {
return -EPROTO;
return ret;
}
/* first startup of the device */
if (_state.initialized_marker != CTAP_INITIALIZED_MARKER) {
ret = _reset();
if (ret != CTAP2_OK) {
return -EPROTO;
return ret;
}
}
@ -275,29 +275,29 @@ int fido2_ctap_init(void)
ret = fido2_ctap_utils_init_gpio_pin(CTAP_UP_BUTTON, CTAP_UP_BUTTON_MODE,
CTAP_UP_BUTTON_FLANK);
if (ret != CTAP2_OK) {
return -EPROTO;
return ret;
}
}
ret = fido2_ctap_crypto_init();
if (ret != CTAP2_OK) {
return -EPROTO;
return ret;
}
/* initialize pin_token */
ret = fido2_ctap_crypto_prng(_pin_token, sizeof(_pin_token));
if (ret != CTAP2_OK) {
return -EPROTO;
return ret;
}
DEBUG("fido2_ctap: initialization successful \n");
return 0;
return CTAP2_OK;
}
size_t fido2_ctap_handle_request(ctap_req_t *req, ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_handle_request(ctap_req_t *req, ctap_resp_t *resp)
{
assert(req);
assert(resp);
@ -305,35 +305,38 @@ size_t fido2_ctap_handle_request(ctap_req_t *req, ctap_resp_t *resp)
switch (req->method) {
case CTAP_GET_INFO:
DEBUG("fido2_ctap: get_info req \n");
return fido2_ctap_get_info(resp);
fido2_ctap_get_info(resp);
break;
case CTAP_MAKE_CREDENTIAL:
DEBUG("fido2_ctap: make_credential req \n");
return fido2_ctap_make_credential(req, resp);
fido2_ctap_make_credential(req, resp);
break;
case CTAP_GET_ASSERTION:
DEBUG("fido2_ctap: get_assertion req \n");
return fido2_ctap_get_assertion(req, resp);
fido2_ctap_get_assertion(req, resp);
break;
case CTAP_GET_NEXT_ASSERTION:
DEBUG("fido2_ctap: get_next_assertion req \n");
return fido2_ctap_get_next_assertion(resp);
fido2_ctap_get_next_assertion(resp);
break;
case CTAP_CLIENT_PIN:
DEBUG("fido2_ctap: client_pin req \n");
return fido2_ctap_client_pin(req, resp);
fido2_ctap_client_pin(req, resp);
break;
case CTAP_RESET:
DEBUG("fido2_ctap: reset req \n");
return fido2_ctap_reset(resp);
fido2_ctap_reset(resp);
break;
default:
DEBUG("fido2_ctap: unknown req: %u \n", req->method);
resp->status = CTAP1_ERR_INVALID_COMMAND;
resp->len = 0x0;
break;
}
return 0;
DEBUG("Resp status %d \n", resp->status);
return resp->status;
}
ctap_state_t *fido2_ctap_get_state(void)
@ -341,18 +344,19 @@ ctap_state_t *fido2_ctap_get_state(void)
return &_state;
}
size_t fido2_ctap_get_info(ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_get_info(ctap_resp_t *resp)
{
assert(resp);
fido2_ctap_cbor_init_encoder(resp->data, sizeof(resp->data));
resp->status = _get_info();
resp->len = fido2_ctap_cbor_get_buffer_size(resp->data);
return fido2_ctap_cbor_get_buffer_size(resp->data);
return resp->status;
}
size_t fido2_ctap_make_credential(ctap_req_t *req, ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_make_credential(ctap_req_t *req, ctap_resp_t *resp)
{
assert(req);
assert(resp);
@ -360,11 +364,12 @@ size_t fido2_ctap_make_credential(ctap_req_t *req, ctap_resp_t *resp)
fido2_ctap_cbor_init_encoder(resp->data, sizeof(resp->data));
resp->status = _make_credential(req);
resp->len = fido2_ctap_cbor_get_buffer_size(resp->data);
return fido2_ctap_cbor_get_buffer_size(resp->data);
return resp->status;
}
size_t fido2_ctap_get_assertion(ctap_req_t *req, ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_get_assertion(ctap_req_t *req, ctap_resp_t *resp)
{
assert(req);
assert(resp);
@ -372,22 +377,24 @@ size_t fido2_ctap_get_assertion(ctap_req_t *req, ctap_resp_t *resp)
fido2_ctap_cbor_init_encoder(resp->data, sizeof(resp->data));
resp->status = _get_assertion(req);
resp->len = fido2_ctap_cbor_get_buffer_size(resp->data);
return fido2_ctap_cbor_get_buffer_size(resp->data);
return resp->status;
}
size_t fido2_ctap_get_next_assertion(ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_get_next_assertion(ctap_resp_t *resp)
{
assert(resp);
fido2_ctap_cbor_init_encoder(resp->data, sizeof(resp->data));
resp->status = _get_next_assertion();
resp->len = fido2_ctap_cbor_get_buffer_size(resp->data);
return fido2_ctap_cbor_get_buffer_size(resp->data);
return resp->status;
}
size_t fido2_ctap_client_pin(ctap_req_t *req, ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_client_pin(ctap_req_t *req, ctap_resp_t *resp)
{
assert(req);
assert(resp);
@ -395,15 +402,19 @@ size_t fido2_ctap_client_pin(ctap_req_t *req, ctap_resp_t *resp)
fido2_ctap_cbor_init_encoder(resp->data, sizeof(resp->data));
resp->status = _client_pin(req);
resp->len = fido2_ctap_cbor_get_buffer_size(resp->data);
return fido2_ctap_cbor_get_buffer_size(resp->data);
return resp->status;
}
size_t fido2_ctap_reset(ctap_resp_t *resp)
ctap_status_code_t fido2_ctap_reset(ctap_resp_t *resp)
{
resp->status = _reset();
assert(resp);
return 0;
resp->status = _reset();
resp->len = 0x0;
return resp->status;
}
static uint32_t get_id(void)
@ -413,7 +424,11 @@ static uint32_t get_id(void)
static int _reset(void)
{
fido2_ctap_mem_erase_flash();
int ret = fido2_ctap_mem_erase_flash();
if (ret != CTAP2_OK) {
return ret;
}
_state.initialized_marker = CTAP_INITIALIZED_MARKER;
_state.rem_pin_att = CTAP_PIN_MAX_ATTS;
@ -540,12 +555,12 @@ static int _make_credential(ctap_req_t *req_raw)
}
/* last moment where transaction can be cancelled */
if (IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)) {
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#if IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#endif
/* user presence test to create a new credential */
if (IS_ACTIVE(CONFIG_FIDO2_CTAP_DISABLE_UP)) {
@ -697,10 +712,12 @@ static int _get_assertion(ctap_req_t *req_raw)
rk = &_assert_state.rks[_assert_state.cred_counter++];
/* last moment where transaction can be cancelled */
#if IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#endif
ret = _make_auth_data_assert(req.rp_id, req.rp_id_len, &auth_data, uv,
up,
@ -855,7 +872,7 @@ static int _client_pin(ctap_req_t *req_raw)
}
/* common error handling */
if (req.sub_command != CTAP_CP_REQ_SUB_COMMAND_GET_RETRIES) {
if (req.sub_command != CTAP_PIN_GET_RETRIES) {
if (_is_locked()) {
return CTAP2_ERR_PIN_BLOCKED;
}
@ -870,19 +887,19 @@ static int _client_pin(ctap_req_t *req_raw)
}
switch (req.sub_command) {
case CTAP_CP_REQ_SUB_COMMAND_GET_RETRIES:
case CTAP_PIN_GET_RETRIES:
ret = _get_retries();
break;
case CTAP_CP_REQ_SUB_COMMAND_GET_KEY_AGREEMENT:
case CTAP_PIN_GET_KEY_AGREEMENT:
ret = _get_key_agreement();
break;
case CTAP_CP_REQ_SUB_COMMAND_SET_PIN:
case CTAP_PIN_SET_PIN:
ret = _set_pin(&req);
break;
case CTAP_CP_REQ_SUB_COMMAND_CHANGE_PIN:
case CTAP_PIN_CHANGE_PIN:
ret = _change_pin(&req);
break;
case CTAP_CP_REQ_SUB_COMMAND_GET_PIN_TOKEN:
case CTAP_PIN_GET_PIN_TOKEN:
ret = _get_pin_token(&req);
break;
default:
@ -904,7 +921,6 @@ static int _get_key_agreement(void)
int ret;
ctap_public_key_cose_t key = { 0 };
/* generate key agreement key */
ret =
fido2_ctap_crypto_gen_keypair(&_state.ag_key.pub, _state.ag_key.priv,
@ -989,12 +1005,12 @@ static int _set_pin(ctap_client_pin_req_t *req)
}
/* last moment where transaction can be cancelled */
if (IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)) {
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#if IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#endif
sz = fmt_strnlen((char *)new_pin_dec, CTAP_PIN_MAX_SIZE + 1);
if (sz < CTAP_PIN_MIN_SIZE || sz > CTAP_PIN_MAX_SIZE) {
@ -1100,13 +1116,12 @@ static int _change_pin(ctap_client_pin_req_t *req)
}
/* last moment where transaction can be cancelled */
if (IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)) {
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#if IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#endif
/* verify decrypted pinHash against LEFT(SHA-256(curPin), 16) */
if (memcmp(pin_hash_dec, _state.pin_hash, CTAP_PIN_TOKEN_SZ) != 0) {
DEBUG("fido2_ctap: _get_pin_token - invalid pin \n");
@ -1198,13 +1213,12 @@ static int _get_pin_token(ctap_client_pin_req_t *req)
}
/* last moment where transaction can be cancelled */
if (IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)) {
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#if IS_USED(MODULE_FIDO2_CTAP_TRANSPORT_HID)
if (fido2_ctap_transport_hid_should_cancel()) {
ret = CTAP2_ERR_KEEPALIVE_CANCEL;
goto done;
}
#endif
/* sha256 of shared secret ((abG).x) to obtain shared key */
ret = fido2_ctap_crypto_sha256(shared_secret, sizeof(shared_secret), shared_key);

View File

@ -33,99 +33,101 @@ typedef enum {
* data structure into @ref ctap_rp_ent_t or @ref ctap_user_ent_t struct
* respectively.
*/
static int _parse_entity(CborValue *it, void *entity, entity_type_t type);
static ctap_status_code_t _parse_entity(CborValue *it, void *entity, entity_type_t type);
/**
* @brief Parse CBOR encoded sequence of PublicKeyCredentialDescriptors into
* @ref ctap_cred_desc_alt_t struct
*/
static int _parse_exclude_list(CborValue *it, ctap_cred_desc_alt_t *exclude_list,
static ctap_status_code_t _parse_exclude_list(CborValue *it, ctap_cred_desc_alt_t *exclude_list,
size_t *exclude_list_len);
/**
* @brief Parse CBOR encoded sequence of PublicKeyCredentialDescriptors into
* @ref ctap_cred_desc_alt_t struct
*/
static int _parse_allow_list(CborValue *it, ctap_cred_desc_alt_t *allow_list,
static ctap_status_code_t _parse_allow_list(CborValue *it, ctap_cred_desc_alt_t *allow_list,
uint8_t *allow_list_len);
/**
* @brief Parse CBOR encoded sequence of PublicKeyCredentialType and cryptographic
* algorithm type pairs and check if the combination is supported
*/
static int _parse_pub_key_cred_params(CborValue *it,
static ctap_status_code_t _parse_pub_key_cred_params(CborValue *it,
ctap_make_credential_req_t *req);
/**
* @brief Parse CBOR encoded PublicKeyCredentialType and cryptographic
* algorithm type
*/
static int _parse_pub_key_cred_param(CborValue *it, uint8_t *cred_type,
static ctap_status_code_t _parse_pub_key_cred_param(CborValue *it, uint8_t *cred_type,
int32_t *alg_type);
/**
* @brief Parse CBOR encoded map of authenticator options into @ref ctap_options_t
* struct
*/
static int _parse_options(CborValue *it, ctap_options_t *options);
static ctap_status_code_t _parse_options(CborValue *it, ctap_options_t *options);
/**
* @brief Parse public key in COSE_KEY format into ctap_public_key_cose_t struct
*/
static int _parse_public_key_cose(CborValue *it, ctap_public_key_cose_t *cose_key);
static ctap_status_code_t _parse_public_key_cose(CborValue *it, ctap_public_key_cose_t *cose_key);
/**
* @brief Parse CBOR encoded fixed length array into dst
*/
static int _parse_fixed_len_byte_array(CborValue *map, uint8_t *dst,
static ctap_status_code_t _parse_fixed_len_byte_array(CborValue *map, uint8_t *dst,
size_t *len);
/**
* @brief Parse CBOR encoded unknown length array into dst
*/
static int _parse_byte_array(CborValue *it, uint8_t *dst, size_t *len);
static ctap_status_code_t _parse_byte_array(CborValue *it, uint8_t *dst, size_t *len);
/**
* @brief Parse CBOR encoded unknown length array into dst
*/
static int _parse_byte_array_u8len(CborValue *it, uint8_t *dst, uint8_t *len);
static ctap_status_code_t _parse_byte_array_u8len(CborValue *it, uint8_t *dst, uint8_t *len);
/**
* @brief Parse CBOR encoded string into dst
*/
static int _parse_text_string(CborValue *it, char *dst, size_t *len);
static ctap_status_code_t _parse_text_string(CborValue *it, char *dst, size_t *len);
/**
* @brief Parse CBOR encoded string into dst
*/
static int _parse_text_string_u8len(CborValue *it, char *dst, uint8_t *len);
static ctap_status_code_t _parse_text_string_u8len(CborValue *it, char *dst, uint8_t *len);
/**
* @brief Parse CBOR encoded int into num
*/
static int _parse_int(CborValue *it, int *num);
static ctap_status_code_t _parse_int(CborValue *it, int *num);
/**
* @brief Parse credential description
*/
static int _fido2_ctap_cbor_parse_cred_desc(CborValue *arr, ctap_cred_desc_alt_t *cred);
static ctap_status_code_t _fido2_ctap_cbor_parse_cred_desc(CborValue *arr,
ctap_cred_desc_alt_t *cred);
/**
* @brief Encode public key into COSE_KEY format
*
* See https://tools.ietf.org/html/rfc8152#page-34 Section 13.1.1 for details.
*/
static int _encode_public_key_cose(CborEncoder *cose_key, const ctap_public_key_cose_t *key);
static ctap_status_code_t _encode_public_key_cose(CborEncoder *cose_key,
const ctap_public_key_cose_t *key);
/**
* @brief Encode PublicKeyCredentialDescriptor into CBOR format
*/
static int _encode_credential(CborEncoder *encoder, const void *cred_ptr,
static ctap_status_code_t _encode_credential(CborEncoder *encoder, const void *cred_ptr,
bool rk);
/**
* @brief Encode PublicKeyCredentialUserEntity into CBOR format
*/
static int _encode_user_entity(CborEncoder *it, const ctap_resident_key_t *rk);
static ctap_status_code_t _encode_user_entity(CborEncoder *it, const ctap_resident_key_t *rk);
/**
* @brief CBOR encoder
@ -142,7 +144,7 @@ void fido2_ctap_cbor_init_encoder(uint8_t *buf, size_t len)
cbor_encoder_init(&_encoder, buf, len, 0);
}
int fido2_ctap_cbor_encode_info(const ctap_info_t *info)
ctap_status_code_t fido2_ctap_cbor_encode_info(const ctap_info_t *info)
{
int ret;
size_t sz = 0;
@ -339,7 +341,7 @@ int fido2_ctap_cbor_encode_info(const ctap_info_t *info)
return CTAP2_OK;
}
int fido2_ctap_cbor_encode_assertion_object(const ctap_auth_data_header_t *auth_data,
ctap_status_code_t fido2_ctap_cbor_encode_assertion_object(const ctap_auth_data_header_t *auth_data,
const uint8_t *client_data_hash,
ctap_resident_key_t *rk,
uint8_t valid_cred_count)
@ -457,7 +459,7 @@ int fido2_ctap_cbor_encode_assertion_object(const ctap_auth_data_header_t *auth_
return CTAP2_OK;
}
int fido2_ctap_cbor_encode_attestation_object(const ctap_auth_data_t *auth_data,
ctap_status_code_t fido2_ctap_cbor_encode_attestation_object(const ctap_auth_data_t *auth_data,
const uint8_t *client_data_hash,
ctap_resident_key_t *rk)
{
@ -580,7 +582,7 @@ int fido2_ctap_cbor_encode_attestation_object(const ctap_auth_data_t *auth_data,
return CTAP2_OK;
}
static int _encode_credential(CborEncoder *encoder, const void *cred_ptr,
static ctap_status_code_t _encode_credential(CborEncoder *encoder, const void *cred_ptr,
bool rk)
{
CborEncoder desc;
@ -630,7 +632,7 @@ static int _encode_credential(CborEncoder *encoder, const void *cred_ptr,
return CTAP2_OK;
}
int fido2_ctap_cbor_encode_key_agreement(const ctap_public_key_cose_t *key)
ctap_status_code_t fido2_ctap_cbor_encode_key_agreement(const ctap_public_key_cose_t *key)
{
int ret;
CborEncoder map;
@ -659,7 +661,7 @@ int fido2_ctap_cbor_encode_key_agreement(const ctap_public_key_cose_t *key)
return CTAP2_OK;
}
int fido2_ctap_cbor_encode_retries(uint8_t tries_left)
ctap_status_code_t fido2_ctap_cbor_encode_retries(uint8_t tries_left)
{
int ret;
CborEncoder map;
@ -687,7 +689,7 @@ int fido2_ctap_cbor_encode_retries(uint8_t tries_left)
return CTAP2_OK;
}
int fido2_ctap_cbor_encode_pin_token(uint8_t *token, size_t len)
ctap_status_code_t fido2_ctap_cbor_encode_pin_token(uint8_t *token, size_t len)
{
int ret;
CborEncoder map;
@ -715,7 +717,7 @@ int fido2_ctap_cbor_encode_pin_token(uint8_t *token, size_t len)
return CTAP2_OK;
}
static int _encode_user_entity(CborEncoder *encoder,
static ctap_status_code_t _encode_user_entity(CborEncoder *encoder,
const ctap_resident_key_t *rk)
{
int ret;
@ -743,7 +745,8 @@ static int _encode_user_entity(CborEncoder *encoder,
return CTAP2_OK;
}
static int _encode_public_key_cose(CborEncoder *cose_key, const ctap_public_key_cose_t *key)
static ctap_status_code_t _encode_public_key_cose(CborEncoder *cose_key,
const ctap_public_key_cose_t *key)
{
int ret;
CborEncoder map;
@ -806,7 +809,7 @@ static int _encode_public_key_cose(CborEncoder *cose_key, const ctap_public_key_
return CTAP2_OK;
}
int fido2_ctap_cbor_parse_get_assertion_req(ctap_get_assertion_req_t *req,
ctap_status_code_t fido2_ctap_cbor_parse_get_assertion_req(ctap_get_assertion_req_t *req,
const uint8_t *req_raw, size_t len)
{
uint8_t required_parsed = 0;
@ -928,7 +931,7 @@ int fido2_ctap_cbor_parse_get_assertion_req(ctap_get_assertion_req_t *req,
return CTAP2_OK;
}
int fido2_ctap_cbor_parse_client_pin_req(ctap_client_pin_req_t *req,
ctap_status_code_t fido2_ctap_cbor_parse_client_pin_req(ctap_client_pin_req_t *req,
const uint8_t *req_raw, size_t len)
{
uint8_t required_parsed = 0;
@ -1041,7 +1044,7 @@ int fido2_ctap_cbor_parse_client_pin_req(ctap_client_pin_req_t *req,
return CTAP2_OK;
}
int fido2_ctap_cbor_parse_make_credential_req(ctap_make_credential_req_t *req,
ctap_status_code_t fido2_ctap_cbor_parse_make_credential_req(ctap_make_credential_req_t *req,
const uint8_t *buf,
size_t size)
{
@ -1172,7 +1175,7 @@ int fido2_ctap_cbor_parse_make_credential_req(ctap_make_credential_req_t *req,
return CTAP2_OK;
}
static int _parse_public_key_cose(CborValue *it, ctap_public_key_cose_t *cose_key)
static ctap_status_code_t _parse_public_key_cose(CborValue *it, ctap_public_key_cose_t *cose_key)
{
int ret;
int type;
@ -1256,7 +1259,7 @@ static int _parse_public_key_cose(CborValue *it, ctap_public_key_cose_t *cose_ke
return CTAP2_OK;
}
static int _parse_entity(CborValue *it, void *entity, entity_type_t type)
static ctap_status_code_t _parse_entity(CborValue *it, void *entity, entity_type_t type)
{
int ret;
int cbor_type;
@ -1386,7 +1389,7 @@ static int _parse_entity(CborValue *it, void *entity, entity_type_t type)
return CTAP2_OK;
}
static int _parse_pub_key_cred_params(CborValue *it,
static ctap_status_code_t _parse_pub_key_cred_params(CborValue *it,
ctap_make_credential_req_t *req)
{
int type;
@ -1434,7 +1437,7 @@ static int _parse_pub_key_cred_params(CborValue *it,
return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
}
static int _parse_pub_key_cred_param(CborValue *it, uint8_t *cred_type,
static ctap_status_code_t _parse_pub_key_cred_param(CborValue *it, uint8_t *cred_type,
int32_t *alg_type)
{
int ret;
@ -1490,7 +1493,7 @@ static int _parse_pub_key_cred_param(CborValue *it, uint8_t *cred_type,
return CTAP2_OK;
}
static int _parse_options(CborValue *it, ctap_options_t *options)
static ctap_status_code_t _parse_options(CborValue *it, ctap_options_t *options)
{
int ret;
int cbor_type;
@ -1569,7 +1572,7 @@ static int _parse_options(CborValue *it, ctap_options_t *options)
return CTAP2_OK;
}
static int _parse_allow_list(CborValue *it, ctap_cred_desc_alt_t *allow_list,
static ctap_status_code_t _parse_allow_list(CborValue *it, ctap_cred_desc_alt_t *allow_list,
uint8_t *allow_list_len)
{
size_t len2 = *allow_list_len;
@ -1579,7 +1582,7 @@ static int _parse_allow_list(CborValue *it, ctap_cred_desc_alt_t *allow_list,
return retval;
}
static int _parse_exclude_list(CborValue *it, ctap_cred_desc_alt_t *exclude_list,
static ctap_status_code_t _parse_exclude_list(CborValue *it, ctap_cred_desc_alt_t *exclude_list,
size_t *exclude_list_len)
{
int ret;
@ -1620,7 +1623,8 @@ static int _parse_exclude_list(CborValue *it, ctap_cred_desc_alt_t *exclude_list
return CTAP2_OK;
}
static int _fido2_ctap_cbor_parse_cred_desc(CborValue *arr, ctap_cred_desc_alt_t *cred)
static ctap_status_code_t _fido2_ctap_cbor_parse_cred_desc(CborValue *arr,
ctap_cred_desc_alt_t *cred)
{
int ret;
int type;
@ -1685,7 +1689,7 @@ static int _fido2_ctap_cbor_parse_cred_desc(CborValue *arr, ctap_cred_desc_alt_t
return CTAP2_OK;
}
static int _parse_fixed_len_byte_array(CborValue *it, uint8_t *dst, size_t *len)
static ctap_status_code_t _parse_fixed_len_byte_array(CborValue *it, uint8_t *dst, size_t *len)
{
int ret;
int type;
@ -1708,7 +1712,7 @@ static int _parse_fixed_len_byte_array(CborValue *it, uint8_t *dst, size_t *len)
return CTAP2_OK;
}
static int _parse_byte_array(CborValue *it, uint8_t *dst, size_t *len)
static ctap_status_code_t _parse_byte_array(CborValue *it, uint8_t *dst, size_t *len)
{
int type;
int ret;
@ -1726,7 +1730,7 @@ static int _parse_byte_array(CborValue *it, uint8_t *dst, size_t *len)
return CTAP2_OK;
}
static int _parse_byte_array_u8len(CborValue *it, uint8_t *dst, uint8_t *len)
static ctap_status_code_t _parse_byte_array_u8len(CborValue *it, uint8_t *dst, uint8_t *len)
{
size_t len2 = *len;
int retval = _parse_byte_array(it, dst, &len2);
@ -1735,7 +1739,7 @@ static int _parse_byte_array_u8len(CborValue *it, uint8_t *dst, uint8_t *len)
return retval;
}
static int _parse_text_string(CborValue *it, char *dst, size_t *len)
static ctap_status_code_t _parse_text_string(CborValue *it, char *dst, size_t *len)
{
int type;
int ret;
@ -1755,7 +1759,7 @@ static int _parse_text_string(CborValue *it, char *dst, size_t *len)
return CTAP2_OK;
}
static int _parse_text_string_u8len(CborValue *it, char *dst, uint8_t *len)
static ctap_status_code_t _parse_text_string_u8len(CborValue *it, char *dst, uint8_t *len)
{
size_t len2 = *len;
int retval = _parse_text_string(it, dst, &len2);
@ -1764,7 +1768,7 @@ static int _parse_text_string_u8len(CborValue *it, char *dst, uint8_t *len)
return retval;
}
static int _parse_int(CborValue *it, int *num)
static ctap_status_code_t _parse_int(CborValue *it, int *num)
{
int type;
int ret;

View File

@ -28,7 +28,6 @@
#include "tiny-asn1.h"
#include "fido2/ctap/ctap_crypto.h"
#include "fido2/ctap.h"
#include "fido2/ctap/ctap_utils.h"
#define ENABLE_DEBUG (0)
@ -37,7 +36,7 @@
/**
* @brief Parse signature into ASN.1 DER format
*/
static int _sig_to_der_format(uint8_t *r, uint8_t *s, uint8_t *sig,
static ctap_status_code_t _sig_to_der_format(uint8_t *r, uint8_t *s, uint8_t *sig,
size_t *sig_len);
/**
@ -45,72 +44,72 @@ static int _sig_to_der_format(uint8_t *r, uint8_t *s, uint8_t *sig,
*
* wrapper for @ref fido2_ctap_crypto_prng
*/
static int _RNG(uint8_t *dest, unsigned size);
int fido2_ctap_crypto_init(void)
{
uECC_set_rng(&_RNG);
return CTAP2_OK;
}
static int _RNG(uint8_t *dest, unsigned size)
{
fido2_ctap_crypto_prng(dest, (size_t)size);
return 1;
}
int fido2_ctap_crypto_prng(uint8_t *buf, size_t len)
ctap_status_code_t fido2_ctap_crypto_init(void)
{
uECC_set_rng(&_RNG);
return CTAP2_OK;
}
ctap_status_code_t fido2_ctap_crypto_prng(uint8_t *buf, size_t len)
{
random_bytes(buf, len);
return CTAP2_OK;
}
int fido2_ctap_crypto_sha256_init(sha256_context_t *ctx)
ctap_status_code_t fido2_ctap_crypto_sha256_init(sha256_context_t *ctx)
{
sha256_init(ctx);
return CTAP2_OK;
}
int fido2_ctap_crypto_sha256_update(sha256_context_t *ctx, const void *data, size_t len)
ctap_status_code_t fido2_ctap_crypto_sha256_update(sha256_context_t *ctx,
const void *data, size_t len)
{
sha256_update(ctx, data, len);
return CTAP2_OK;
}
int fido2_ctap_crypto_sha256_final(sha256_context_t *ctx, void *digest)
ctap_status_code_t fido2_ctap_crypto_sha256_final(sha256_context_t *ctx, void *digest)
{
sha256_final(ctx, digest);
return CTAP2_OK;
}
int fido2_ctap_crypto_sha256(const void *data, size_t len,
ctap_status_code_t fido2_ctap_crypto_sha256(const void *data, size_t len,
void *digest)
{
sha256(data, len, digest);
return CTAP2_OK;
}
int fido2_ctap_crypto_hmac_sha256_init(hmac_context_t *ctx, const void *key,
ctap_status_code_t fido2_ctap_crypto_hmac_sha256_init(hmac_context_t *ctx, const void *key,
size_t key_length)
{
hmac_sha256_init(ctx, key, key_length);
return CTAP2_OK;
}
int fido2_ctap_crypto_hmac_sha256_update(hmac_context_t *ctx, const void *data, size_t len)
ctap_status_code_t fido2_ctap_crypto_hmac_sha256_update(hmac_context_t *ctx,
const void *data, size_t len)
{
hmac_sha256_update(ctx, data, len);
return CTAP2_OK;
}
int fido2_ctap_crypto_hmac_sha256_final(hmac_context_t *ctx, void *digest)
ctap_status_code_t fido2_ctap_crypto_hmac_sha256_final(hmac_context_t *ctx, void *digest)
{
hmac_sha256_final(ctx, digest);
return CTAP2_OK;
}
int fido2_ctap_crypto_hmac_sha256(const void *key,
ctap_status_code_t fido2_ctap_crypto_hmac_sha256(const void *key,
size_t key_length, const void *data, size_t len,
void *digest)
{
@ -118,7 +117,7 @@ int fido2_ctap_crypto_hmac_sha256(const void *key,
return CTAP2_OK;
}
int fido2_ctap_crypto_ecdh(uint8_t *out, size_t len,
ctap_status_code_t fido2_ctap_crypto_ecdh(uint8_t *out, size_t len,
ctap_crypto_pub_key_t *pub_key, uint8_t *priv_key, size_t key_len)
{
assert(len == CTAP_CRYPTO_KEY_SIZE);
@ -136,7 +135,7 @@ int fido2_ctap_crypto_ecdh(uint8_t *out, size_t len,
return CTAP2_OK;
}
int fido2_ctap_crypto_aes_enc(uint8_t *out, size_t *out_len, uint8_t *in,
ctap_status_code_t fido2_ctap_crypto_aes_enc(uint8_t *out, size_t *out_len, uint8_t *in,
size_t in_len, const uint8_t *key,
size_t key_len)
{
@ -160,7 +159,7 @@ int fido2_ctap_crypto_aes_enc(uint8_t *out, size_t *out_len, uint8_t *in,
return CTAP2_OK;
}
int fido2_ctap_crypto_aes_dec(uint8_t *out, size_t *out_len, uint8_t *in,
ctap_status_code_t fido2_ctap_crypto_aes_dec(uint8_t *out, size_t *out_len, uint8_t *in,
size_t in_len, const uint8_t *key,
size_t key_len)
{
@ -184,7 +183,7 @@ int fido2_ctap_crypto_aes_dec(uint8_t *out, size_t *out_len, uint8_t *in,
return CTAP2_OK;
}
int fido2_ctap_crypto_aes_ccm_enc(uint8_t *out, size_t out_len,
ctap_status_code_t fido2_ctap_crypto_aes_ccm_enc(uint8_t *out, size_t out_len,
const uint8_t *in, size_t in_len,
uint8_t *auth_data, size_t auth_data_len,
uint8_t mac_len, uint8_t length_encoding,
@ -213,7 +212,7 @@ int fido2_ctap_crypto_aes_ccm_enc(uint8_t *out, size_t out_len,
return CTAP2_OK;
}
int fido2_ctap_crypto_aes_ccm_dec(uint8_t *out, size_t out_len,
ctap_status_code_t fido2_ctap_crypto_aes_ccm_dec(uint8_t *out, size_t out_len,
const uint8_t *in, size_t in_len,
uint8_t *auth_data, size_t auth_data_len,
uint8_t mac_len, uint8_t length_encoding,
@ -242,7 +241,7 @@ int fido2_ctap_crypto_aes_ccm_dec(uint8_t *out, size_t out_len,
return CTAP2_OK;
}
int fido2_ctap_crypto_gen_keypair(ctap_crypto_pub_key_t *pub_key,
ctap_status_code_t fido2_ctap_crypto_gen_keypair(ctap_crypto_pub_key_t *pub_key,
uint8_t *priv_key, size_t len)
{
assert(len == CTAP_CRYPTO_KEY_SIZE);
@ -258,7 +257,7 @@ int fido2_ctap_crypto_gen_keypair(ctap_crypto_pub_key_t *pub_key,
return CTAP2_OK;
}
int fido2_ctap_crypto_get_sig(uint8_t *hash, size_t hash_len, uint8_t *sig,
ctap_status_code_t fido2_ctap_crypto_get_sig(uint8_t *hash, size_t hash_len, uint8_t *sig,
size_t *sig_len, const uint8_t *key,
size_t key_len)
{
@ -293,7 +292,7 @@ int fido2_ctap_crypto_get_sig(uint8_t *hash, size_t hash_len, uint8_t *sig,
return CTAP2_OK;
}
static int _sig_to_der_format(uint8_t *r, uint8_t *s, uint8_t *sig,
static ctap_status_code_t _sig_to_der_format(uint8_t *r, uint8_t *s, uint8_t *sig,
size_t *sig_len)
{
asn1_tree t;

View File

@ -28,16 +28,22 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifdef BOARD_NATIVE
#include "mtd_default.h"
/* native mtd is file backed => Start address of flash is 0. */
char *_backing_memory = NULL;
static mtd_dev_t *_mtd_dev = NULL;
#else
/**
* @brief Reserve flash memory to store CTAP data
*/
FLASH_WRITABLE_INIT(_backing_memory, CONFIG_FIDO2_CTAP_NUM_FLASHPAGES);
/**
* @brief MTD device descriptor initialized with flash-page driver
*/
static mtd_flashpage_t _mtd_flash_dev = MTD_FLASHPAGE_INIT_VAL(CTAP_FLASH_PAGES_PER_SECTOR);
static mtd_dev_t *_mtd_dev = &_mtd_flash_dev.base;
#endif
/**
* @brief Check if flash region is erased
@ -52,15 +58,14 @@ static unsigned _amount_flashpages_rk(void);
/**
* @brief Write to flash memory
*/
static int _flash_write(const void *buf, uint32_t addr, size_t len);
static ctap_status_code_t _flash_write(const void *buf, uint32_t addr, size_t len);
/**
* @brief Get start address of reserved flash memory region
*/
static unsigned _flash_start(void);
int fido2_ctap_mem_init(void)
ctap_status_code_t fido2_ctap_mem_init(void)
{
#ifdef BOARD_NATIVE
_mtd_dev = mtd_default_get_dev(0);
#endif
int ret = mtd_init(_mtd_dev);
if (ret < 0) {
@ -75,10 +80,9 @@ static unsigned _amount_flashpages_rk(void)
return _mtd_dev->sector_count * _mtd_dev->pages_per_sector;
}
int fido2_ctap_mem_read(void *buf, uint32_t page, uint32_t offset, uint32_t len)
ctap_status_code_t fido2_ctap_mem_read(void *buf, uint32_t page, uint32_t offset, uint32_t len)
{
assert(buf);
int ret;
ret = mtd_read_page(_mtd_dev, buf, page, offset, len);
@ -90,7 +94,7 @@ int fido2_ctap_mem_read(void *buf, uint32_t page, uint32_t offset, uint32_t len)
return CTAP2_OK;
}
static int _flash_write(const void *buf, uint32_t addr, size_t len)
static ctap_status_code_t _flash_write(const void *buf, uint32_t addr, size_t len)
{
assert(buf);
int ret;
@ -119,6 +123,9 @@ static int _flash_write(const void *buf, uint32_t addr, size_t len)
static bool _flash_is_erased(uint32_t addr, size_t len)
{
#ifdef BOARD_NATIVE
return true;
#else
for (size_t i = 0; i < len; i++) {
if (*(uint32_t *)(addr + i) != FLASHPAGE_ERASE_STATE) {
return false;
@ -126,34 +133,35 @@ static bool _flash_is_erased(uint32_t addr, size_t len)
}
return true;
#endif
}
static unsigned _flash_start(void)
static uint32_t _flash_start_addr(void)
{
return flashpage_page((void *)_backing_memory);
return (uint32_t)_backing_memory;
}
int fido2_ctap_mem_erase_flash(void)
ctap_status_code_t fido2_ctap_mem_erase_flash(void)
{
unsigned start = _flash_start();
unsigned end = start + CONFIG_FIDO2_CTAP_NUM_FLASHPAGES;
unsigned addr = _flash_start_addr();
unsigned sector_size = _mtd_dev->pages_per_sector * _mtd_dev->page_size;
for (unsigned page = start; page < end; page++) {
flashpage_erase(page);
}
int ret = mtd_erase(_mtd_dev, addr, sector_size * CONFIG_FIDO2_CTAP_NUM_FLASHPAGES);
return CTAP2_OK;
return ret == 0 ? CTAP2_OK : CTAP1_ERR_OTHER;
}
/**
* CTAP state information is stored at flashpage 0 of the memory area
* dedicated for storing CTAP data
*/
int fido2_ctap_mem_read_state_from_flash(ctap_state_t *state)
ctap_status_code_t fido2_ctap_mem_read_state_from_flash(ctap_state_t *state)
{
uint32_t addr = (uint32_t)flashpage_addr(_flash_start());
uint32_t addr = _flash_start_addr();
return mtd_read(_mtd_dev, state, addr, sizeof(ctap_state_t));
int ret = mtd_read(_mtd_dev, state, addr, sizeof(ctap_state_t));
return ret == 0 ? CTAP2_OK : CTAP1_ERR_OTHER;
}
/**
@ -163,10 +171,10 @@ int fido2_ctap_mem_read_state_from_flash(ctap_state_t *state)
* so rk's can't be deleted, only overwritten => we can be sure that there are
* no holes when reading keys from flash memory
*/
int fido2_ctap_mem_write_rk_to_flash(ctap_resident_key_t *rk)
ctap_status_code_t fido2_ctap_mem_write_rk_to_flash(ctap_resident_key_t *rk)
{
int ret;
uint32_t addr = (uint32_t)flashpage_addr(_flash_start() + CTAP_FLASH_RK_OFF);
uint32_t addr = _flash_start_addr() + FLASHPAGE_SIZE;
uint16_t amt_stored = fido2_ctap_get_state()->rk_amount_stored;
ctap_resident_key_t tmp = { 0 };
bool equal = false;
@ -205,24 +213,23 @@ int fido2_ctap_mem_write_rk_to_flash(ctap_resident_key_t *rk)
return _flash_write(rk, addr, CTAP_FLASH_RK_SZ);
}
int fido2_ctap_mem_write_state_to_flash(ctap_state_t *state)
ctap_status_code_t fido2_ctap_mem_write_state_to_flash(ctap_state_t *state)
{
uint32_t addr = (uint32_t)flashpage_addr(_flash_start());
return _flash_write(state, addr, CTAP_FLASH_STATE_SZ);
return _flash_write(state, _flash_start_addr(), CTAP_FLASH_STATE_SZ);
}
int fido2_ctap_mem_read_rk_from_flash(ctap_resident_key_t *key, uint8_t *rp_id_hash, uint32_t *addr)
ctap_status_code_t fido2_ctap_mem_read_rk_from_flash(ctap_resident_key_t *key, uint8_t *rp_id_hash,
uint32_t *addr)
{
uint16_t end;
uint16_t amt_stored = fido2_ctap_get_state()->rk_amount_stored;
if (*addr == 0x0) {
end = amt_stored;
*addr = (uint32_t)flashpage_addr(_flash_start() + CTAP_FLASH_RK_OFF);
*addr = _flash_start_addr() + FLASHPAGE_SIZE;
}
else {
uint32_t start_addr = (uint32_t)flashpage_addr(_flash_start() + CTAP_FLASH_RK_OFF);
uint32_t start_addr = _flash_start_addr() + FLASHPAGE_SIZE;
uint16_t rks_read = (*addr - start_addr) / CTAP_FLASH_RK_SZ;
if (rks_read > amt_stored) {

View File

@ -44,7 +44,7 @@ static gpio_t _pin;
*/
static void _gpio_cb(void *arg);
int fido2_ctap_utils_init_gpio_pin(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank)
ctap_status_code_t fido2_ctap_utils_init_gpio_pin(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank)
{
if (gpio_init_int(pin, mode, flank, _gpio_cb, NULL) < 0) {
return CTAP1_ERR_OTHER;
@ -55,7 +55,7 @@ int fido2_ctap_utils_init_gpio_pin(gpio_t pin, gpio_mode_t mode, gpio_flank_t fl
return CTAP2_OK;
}
int fido2_ctap_utils_user_presence_test(void)
ctap_status_code_t fido2_ctap_utils_user_presence_test(void)
{
int ret;

View File

@ -18,7 +18,6 @@
#include <string.h>
#include "ztimer.h"
#include "ztimer64.h"
#include "usb/usbus.h"
#include "usb/usbus/hid.h"
#include "usb/usbus/hid_io.h"
@ -478,9 +477,8 @@ static uint32_t _handle_init_packet(uint32_t cid, uint16_t bcnt,
static void _handle_cbor_packet(uint8_t cmd, uint32_t cid, uint8_t *buf, uint16_t bcnt)
{
ctap_resp_t resp;
ctap_resp_t resp = {0x0};
uint8_t err;
size_t size;
if (bcnt == 0) {
err = CTAP_HID_ERR_INVALID_LEN;
@ -489,26 +487,24 @@ static void _handle_cbor_packet(uint8_t cmd, uint32_t cid, uint8_t *buf, uint16_
return;
}
memset(&resp, 0, sizeof(ctap_resp_t));
ctap_req_t req = {
.method = *buf,
.buf = buf + 1,
.len = bcnt - 1
};
ctap_req_t req;
req.method = *buf;
req.buf = buf + 1;
req.len = bcnt - 1;
size = fido2_ctap_handle_request(&req, &resp);
ctap_status_code_t status = fido2_ctap_handle_request(&req, &resp);
/* transaction done, clear should_cancel flag */
_state.should_cancel = false;
if (resp.status == CTAP2_OK && size > 0) {
if (status == CTAP2_OK && resp.len > 0) {
/* status + data */
_ctap_hid_write(cmd, cid, &resp, size + sizeof(resp.status));
_ctap_hid_write(cmd, cid, &resp, resp.len + sizeof(resp.status));
}
else {
/* status only */
_ctap_hid_write(cmd, cid, &resp.status, sizeof(resp.status));
_ctap_hid_write(cmd, cid, &resp.status, sizeof(status));
}
}
@ -529,7 +525,7 @@ bool fido2_ctap_transport_hid_should_cancel(void)
void fido2_ctap_transport_hid_check_timeouts(void)
{
uint64_t now = ztimer64_now(ZTIMER64_MSEC);
uint32_t now = ztimer_now(ZTIMER_MSEC);
for (uint8_t i = 0; i < CTAP_HID_CIDS_MAX; i++) {
/* transaction timed out because cont packets didn't arrive in time */
@ -548,14 +544,14 @@ void fido2_ctap_transport_hid_check_timeouts(void)
static int8_t _add_cid(uint32_t cid)
{
uint64_t oldest = ztimer64_now(ZTIMER64_MSEC);
uint32_t oldest = ztimer_now(ZTIMER_MSEC);
int8_t index_oldest = -1;
for (int i = 0; i < CTAP_HID_CIDS_MAX; i++) {
if (!g_cids[i].taken) {
g_cids[i].taken = true;
g_cids[i].cid = cid;
g_cids[i].last_used = ztimer64_now(ZTIMER64_MSEC);
g_cids[i].last_used = ztimer_now(ZTIMER_MSEC);
return CTAP_HID_OK;
}
@ -570,7 +566,7 @@ static int8_t _add_cid(uint32_t cid)
if (index_oldest > -1) {
g_cids[index_oldest].taken = true;
g_cids[index_oldest].cid = cid;
g_cids[index_oldest].last_used = ztimer64_now(ZTIMER64_MSEC);
g_cids[index_oldest].last_used = ztimer_now(ZTIMER_MSEC);
return CTAP_HID_OK;
}
@ -581,7 +577,7 @@ static int8_t _refresh_cid(uint32_t cid)
{
for (int i = 0; i < CTAP_HID_CIDS_MAX; i++) {
if (g_cids[i].cid == cid) {
g_cids[i].last_used = ztimer64_now(ZTIMER64_MSEC);
g_cids[i].last_used = ztimer_now(ZTIMER_MSEC);
return CTAP_HID_OK;
}
}

View File

@ -98,7 +98,22 @@ typedef enum {
CTAP2_ERR_EXTENSION_LAST = 0xEF,
CTAP2_ERR_VENDOR_FIRST = 0xF0,
CTAP2_ERR_VENDOR_LAST = 0xFF
} ctap_status_codes_t;
} ctap_status_code_t;
/** @} */
/**
* @brief CTAP methods
*
* @{
*/
typedef enum {
CTAP_MAKE_CREDENTIAL = 0x01,
CTAP_GET_ASSERTION = 0x02,
CTAP_GET_INFO = 0x04,
CTAP_CLIENT_PIN = 0x06,
CTAP_RESET = 0x07,
CTAP_GET_NEXT_ASSERTION = 0x08
} ctap_method_t;
/** @} */
/**
@ -118,17 +133,17 @@ typedef struct {
* CTAP specification (version 20190130) section 6.2
*/
typedef struct {
uint8_t status; /**< response status */
ctap_status_code_t status; /**< response status */
uint8_t data[CTAP_MAX_MSG_SIZE]; /**< response data */
size_t len; /**< length of response data */
} ctap_resp_t;
/**
* @brief Initialize ctap
*
* @return 0 for success
* @return negative error code otherwise
* @return @ref ctap_status_code_t
*/
int fido2_ctap_init(void);
ctap_status_code_t fido2_ctap_init(void);
/**
* @brief Handle CBOR encoded ctap request.
@ -139,9 +154,9 @@ int fido2_ctap_init(void);
* @param[in] req request struct
* @param[in] resp response struct
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_handle_request(ctap_req_t *req, ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_handle_request(ctap_req_t *req, ctap_resp_t *resp);
/**
* @brief MakeCredential method
@ -151,9 +166,9 @@ size_t fido2_ctap_handle_request(ctap_req_t *req, ctap_resp_t *resp);
* @param[in] req CTAP request
* @param[in, out] resp CTAP response
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_make_credential(ctap_req_t *req, ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_make_credential(ctap_req_t *req, ctap_resp_t *resp);
/**
* @brief GetAssertion method
@ -163,9 +178,9 @@ size_t fido2_ctap_make_credential(ctap_req_t *req, ctap_resp_t *resp);
* @param[in] req CTAP request
* @param[in, out] resp CTAP response
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_get_assertion(ctap_req_t *req, ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_get_assertion(ctap_req_t *req, ctap_resp_t *resp);
/**
* @brief GetNextAssertion method
@ -174,9 +189,9 @@ size_t fido2_ctap_get_assertion(ctap_req_t *req, ctap_resp_t *resp);
*
* @param[in, out] resp CTAP response
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_get_next_assertion(ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_get_next_assertion(ctap_resp_t *resp);
/**
* @brief GetInfo method
@ -185,9 +200,9 @@ size_t fido2_ctap_get_next_assertion(ctap_resp_t *resp);
*
* @param[in, out] resp CTAP response
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_get_info(ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_get_info(ctap_resp_t *resp);
/**
* @brief ClientPIN method
@ -197,9 +212,9 @@ size_t fido2_ctap_get_info(ctap_resp_t *resp);
* @param[in] req CTAP request
* @param[in, out] resp CTAP response
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_client_pin(ctap_req_t *req, ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_client_pin(ctap_req_t *req, ctap_resp_t *resp);
/**
* @brief Reset method
@ -208,9 +223,9 @@ size_t fido2_ctap_client_pin(ctap_req_t *req, ctap_resp_t *resp);
*
* @param[in, out] resp CTAP response
*
* @return Length of @p resp->data
* @return @ref ctap_status_code_t
*/
size_t fido2_ctap_reset(ctap_resp_t *resp);
ctap_status_code_t fido2_ctap_reset(ctap_resp_t *resp);
#ifdef __cplusplus
}

View File

@ -50,19 +50,6 @@ extern "C" {
*/
#define CTAP_PIN_AUTH_SZ 16
/**
* @name CTAP methods
*
* @{
*/
#define CTAP_MAKE_CREDENTIAL 0x01 /**< authenticatorMakeCredential method */
#define CTAP_GET_ASSERTION 0x02 /**< authenticatorGetAssertion method */
#define CTAP_GET_INFO 0x04 /**< authenticatorGetInfo method */
#define CTAP_CLIENT_PIN 0x06 /**< authenticatorClientPIN method */
#define CTAP_RESET 0x07 /**< authenticatorReset method */
#define CTAP_GET_NEXT_ASSERTION 0x08 /**< authenticatorGetNextAssertion method */
/** @} */
/**
* @name CTAP authenticator data option flags
*
@ -111,15 +98,17 @@ extern "C" {
/** @} */
/**
* @name CTAP Client PIN request subCommand CBOR key values
* @brief CTAP Client PIN request subCommand CBOR key values
*
* @{
*/
#define CTAP_CP_REQ_SUB_COMMAND_GET_RETRIES 0x01 /**< getRetries subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_GET_KEY_AGREEMENT 0x02 /**< getKeyAgreement subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_SET_PIN 0x03 /**< setPIN subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_CHANGE_PIN 0x04 /**< changePIN subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_GET_PIN_TOKEN 0x05 /**< getPinToken subCommand */
typedef enum {
CTAP_PIN_GET_RETRIES = 0x01, /**< getRetries subCommand */
CTAP_PIN_GET_KEY_AGREEMENT = 0x02, /**< getKeyAgreement subCommand */
CTAP_PIN_SET_PIN = 0x03, /**< setPIN subCommand */
CTAP_PIN_CHANGE_PIN = 0x04, /**< changePIN subCommand */
CTAP_PIN_GET_PIN_TOKEN = 0x05 /**< getPinToken subCommand */
} ctap_pin_subcommand_t;
/** @} */
/**
@ -572,7 +561,7 @@ typedef struct {
uint8_t pin_auth[CTAP_PIN_AUTH_SZ]; /**< first 16 bytes of HMAC-SHA-256 of encrypted contents */
uint8_t new_pin_enc[CTAP_PIN_ENC_MAX_SIZE]; /**< Encrypted new PIN using sharedSecret. */
uint8_t pin_hash_enc[SHA256_DIGEST_LENGTH / 2]; /**< Encrypted first 16 bytes of SHA-256 of PIN using sharedSecret. */
uint8_t sub_command; /**< authenticator Client PIN sub command */
ctap_pin_subcommand_t sub_command; /**< ClientPIN sub command */
uint8_t pin_protocol; /**< PIN protocol version chosen by the client */
bool pin_hash_enc_present; /**< indicate pin_hash_enc is present */
bool pin_auth_present; /**< indicate if pin_auth present */
@ -642,7 +631,7 @@ typedef struct {
* @param[in] sig signature buffer
* @param[in] sig_len length of @p sig
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_get_sig(const uint8_t *auth_data, size_t auth_data_len,
const uint8_t *client_data_hash,
@ -668,7 +657,7 @@ bool fido2_ctap_cred_params_supported(uint8_t cred_type, int32_t alg_type);
* @param[in] nonce_len length of @p nonce
* @param[in] id credential id struct storing encrypted resident key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_encrypt_rk(ctap_resident_key_t *rk, uint8_t *nonce,
size_t nonce_len, ctap_cred_id_t *id);

View File

@ -212,9 +212,9 @@ extern "C" {
* @param[in] req_raw raw request
* @param[in] len length of @p req_raw
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_parse_make_credential_req(ctap_make_credential_req_t *req,
ctap_status_code_t fido2_ctap_cbor_parse_make_credential_req(ctap_make_credential_req_t *req,
const uint8_t *req_raw, size_t len);
/**
@ -226,9 +226,9 @@ int fido2_ctap_cbor_parse_make_credential_req(ctap_make_credential_req_t *req,
* @param[in] req_raw raw request
* @param[in] len length of @p req_raw
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_parse_get_assertion_req(ctap_get_assertion_req_t *req,
ctap_status_code_t fido2_ctap_cbor_parse_get_assertion_req(ctap_get_assertion_req_t *req,
const uint8_t *req_raw, size_t len);
/**
@ -238,10 +238,10 @@ int fido2_ctap_cbor_parse_get_assertion_req(ctap_get_assertion_req_t *req,
*
* @param[in] info information about capabilities
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_encode_info(const ctap_info_t *info);
ctap_status_code_t fido2_ctap_cbor_encode_info(const ctap_info_t *info);
/**
* @brief Parse ClientPIN method
*
@ -251,9 +251,9 @@ int fido2_ctap_cbor_encode_info(const ctap_info_t *info);
* @param[in] req_raw raw request
* @param[in] len length of @p req_raw
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_parse_client_pin_req(ctap_client_pin_req_t *req,
ctap_status_code_t fido2_ctap_cbor_parse_client_pin_req(ctap_client_pin_req_t *req,
const uint8_t *req_raw, size_t len);
/**
* @brief Encode attestation object
@ -264,9 +264,9 @@ int fido2_ctap_cbor_parse_client_pin_req(ctap_client_pin_req_t *req,
* @param[in] client_data_hash SHA-256 hash of JSON serialized client data
* @param[in] rk resident key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_encode_attestation_object(const ctap_auth_data_t *auth_data,
ctap_status_code_t fido2_ctap_cbor_encode_attestation_object(const ctap_auth_data_t *auth_data,
const uint8_t *client_data_hash,
ctap_resident_key_t *rk);
@ -280,9 +280,9 @@ int fido2_ctap_cbor_encode_attestation_object(const ctap_auth_data_t *auth_data,
* @param[in] rk resident key
* @param[in] valid_cred_count amount of valid credentials found in allow list
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_encode_assertion_object(const ctap_auth_data_header_t *auth_data,
ctap_status_code_t fido2_ctap_cbor_encode_assertion_object(const ctap_auth_data_header_t *auth_data,
const uint8_t *client_data_hash,
ctap_resident_key_t *rk,
uint8_t valid_cred_count);
@ -291,9 +291,9 @@ int fido2_ctap_cbor_encode_assertion_object(const ctap_auth_data_header_t *auth_
*
* @param[in] key Public key in COSE format
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_encode_key_agreement(const ctap_public_key_cose_t *key);
ctap_status_code_t fido2_ctap_cbor_encode_key_agreement(const ctap_public_key_cose_t *key);
/**
* @brief Encode encrypted pin token
@ -301,18 +301,18 @@ int fido2_ctap_cbor_encode_key_agreement(const ctap_public_key_cose_t *key);
* @param[in] token encrypted pin token
* @param[in] len length of @p token
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_encode_pin_token(uint8_t *token, size_t len);
ctap_status_code_t fido2_ctap_cbor_encode_pin_token(uint8_t *token, size_t len);
/**
* @brief Encode PIN tries left
*
* @param[in] tries_left amount of tries left
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_cbor_encode_retries(uint8_t tries_left);
ctap_status_code_t fido2_ctap_cbor_encode_retries(uint8_t tries_left);
/**
* @brief Get size of CBOR encoded data

View File

@ -26,6 +26,7 @@
#include <stdint.h>
#include "hashes/sha256.h"
#include "fido2/ctap.h"
#ifdef __cplusplus
extern "C" {
@ -64,9 +65,9 @@ typedef struct {
*
* Initializes crypto libs and creates key_agreement key pair
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_init(void);
ctap_status_code_t fido2_ctap_crypto_init(void);
/**
* @brief Wrapper function for @ref random_bytes
@ -74,18 +75,18 @@ int fido2_ctap_crypto_init(void);
* @param[in] buf buffer to hold random bytes
* @param[in] len length of @p buf
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_prng(uint8_t *buf, size_t len);
ctap_status_code_t fido2_ctap_crypto_prng(uint8_t *buf, size_t len);
/**
* @brief Wrapper function for @ref sha256_init
*
* @param ctx sha256_context_t handle to init
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_sha256_init(sha256_context_t *ctx);
ctap_status_code_t fido2_ctap_crypto_sha256_init(sha256_context_t *ctx);
/**
* @brief Wrapper function for @ref sha256_update
@ -94,9 +95,9 @@ int fido2_ctap_crypto_sha256_init(sha256_context_t *ctx);
* @param[in] data Input data
* @param[in] len Length of @p data
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_sha256_update(sha256_context_t *ctx, const void *data, size_t len);
ctap_status_code_t fido2_ctap_crypto_sha256_update(sha256_context_t *ctx, const void *data, size_t len);
/**
* @brief Wrapper for @ref sha256_final
@ -104,9 +105,9 @@ int fido2_ctap_crypto_sha256_update(sha256_context_t *ctx, const void *data, siz
* @param ctx sha256_context_t handle to use
* @param digest resulting digest, this is the hash of all the bytes
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_sha256_final(sha256_context_t *ctx, void *digest);
ctap_status_code_t fido2_ctap_crypto_sha256_final(sha256_context_t *ctx, void *digest);
/**
* @brief Wrapper function for @ref sha256
@ -118,9 +119,9 @@ int fido2_ctap_crypto_sha256_final(sha256_context_t *ctx, void *digest);
*
* @note discards the pointer returned by @ref sha256
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_sha256(const void *data, size_t len,
ctap_status_code_t fido2_ctap_crypto_sha256(const void *data, size_t len,
void *digest);
/**
@ -130,9 +131,9 @@ int fido2_ctap_crypto_sha256(const void *data, size_t len,
* @param[in] key key used in the hmac-sha256 computation
* @param[in] key_length length of @p key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_hmac_sha256_init(hmac_context_t *ctx, const void *key,
ctap_status_code_t fido2_ctap_crypto_hmac_sha256_init(hmac_context_t *ctx, const void *key,
size_t key_length);
/**
@ -142,9 +143,9 @@ int fido2_ctap_crypto_hmac_sha256_init(hmac_context_t *ctx, const void *key,
* @param[in] data pointer to the buffer to generate hash from
* @param[in] len length of @p data
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_hmac_sha256_update(hmac_context_t *ctx, const void *data, size_t len);
ctap_status_code_t fido2_ctap_crypto_hmac_sha256_update(hmac_context_t *ctx, const void *data, size_t len);
/**
* @brief Wrapper function for @ref hmac_sha256_final
@ -153,9 +154,9 @@ int fido2_ctap_crypto_hmac_sha256_update(hmac_context_t *ctx, const void *data,
* @param[out] digest the computed hmac-sha256,
* length MUST be SHA256_DIGEST_LENGTH
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_hmac_sha256_final(hmac_context_t *ctx, void *digest);
ctap_status_code_t fido2_ctap_crypto_hmac_sha256_final(hmac_context_t *ctx, void *digest);
/**
* @brief Wrapper function for @ref hmac_sha256
@ -169,9 +170,9 @@ int fido2_ctap_crypto_hmac_sha256_final(hmac_context_t *ctx, void *digest);
*
* @note discards the pointer returned by @ref hmac_sha256
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_hmac_sha256(const void *key,
ctap_status_code_t fido2_ctap_crypto_hmac_sha256(const void *key,
size_t key_length, const void *data, size_t len,
void *digest);
@ -182,9 +183,9 @@ int fido2_ctap_crypto_hmac_sha256(const void *key,
* @param[in] priv_key private key buffer
* @param[in] len length of @p priv_key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_gen_keypair(ctap_crypto_pub_key_t *pub_key, uint8_t *priv_key, size_t len);
ctap_status_code_t fido2_ctap_crypto_gen_keypair(ctap_crypto_pub_key_t *pub_key, uint8_t *priv_key, size_t len);
/**
* @brief Elliptic-curve Diffie-Hellmann
@ -195,9 +196,9 @@ int fido2_ctap_crypto_gen_keypair(ctap_crypto_pub_key_t *pub_key, uint8_t *priv_
* @param[in] priv_key private key
* @param[in] key_len length of @p priv_key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_ecdh(uint8_t *out, size_t len,
ctap_status_code_t fido2_ctap_crypto_ecdh(uint8_t *out, size_t len,
ctap_crypto_pub_key_t *pub_key, uint8_t *priv_key, size_t key_len);
/**
@ -210,9 +211,9 @@ int fido2_ctap_crypto_ecdh(uint8_t *out, size_t len,
* @param[in] key private key to use for signature
* @param[in] key_len length of @p key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_get_sig(uint8_t *hash, size_t hash_len, uint8_t *sig,
ctap_status_code_t fido2_ctap_crypto_get_sig(uint8_t *hash, size_t hash_len, uint8_t *sig,
size_t *sig_len, const uint8_t *key, size_t key_len);
/**
@ -225,9 +226,9 @@ int fido2_ctap_crypto_get_sig(uint8_t *hash, size_t hash_len, uint8_t *sig,
* @param[in] key symmetric key to use for encryption
* @param[in] key_len length of @p key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_aes_enc(uint8_t * out, size_t *out_len, uint8_t * in,
ctap_status_code_t fido2_ctap_crypto_aes_enc(uint8_t * out, size_t *out_len, uint8_t * in,
size_t in_len, const uint8_t * key, size_t key_len);
/**
@ -240,9 +241,9 @@ int fido2_ctap_crypto_aes_enc(uint8_t * out, size_t *out_len, uint8_t * in,
* @param[in] key symmetric key to use for decryption
* @param[in] key_len length of @p key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_aes_dec(uint8_t * out, size_t *out_len, uint8_t * in,
ctap_status_code_t fido2_ctap_crypto_aes_dec(uint8_t * out, size_t *out_len, uint8_t * in,
size_t in_len, const uint8_t * key, size_t key_len);
/**
@ -261,9 +262,9 @@ int fido2_ctap_crypto_aes_dec(uint8_t * out, size_t *out_len, uint8_t * in,
* @param[in] key symmetric key to use for encryption
* @param[in] key_len length of @p key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_aes_ccm_enc(uint8_t *out, size_t out_len,
ctap_status_code_t fido2_ctap_crypto_aes_ccm_enc(uint8_t *out, size_t out_len,
const uint8_t *in, size_t in_len,
uint8_t *auth_data, size_t auth_data_len,
uint8_t mac_len, uint8_t length_encoding,
@ -286,9 +287,9 @@ int fido2_ctap_crypto_aes_ccm_enc(uint8_t *out, size_t out_len,
* @param[in] key symmetric key to use for encryption
* @param[in] key_len length of @p key
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_crypto_aes_ccm_dec(uint8_t *out, size_t out_len,
ctap_status_code_t fido2_ctap_crypto_aes_ccm_dec(uint8_t *out, size_t out_len,
const uint8_t *in, size_t in_len,
uint8_t *auth_data, size_t auth_data_len,
uint8_t mac_len, uint8_t length_encoding,

View File

@ -100,9 +100,9 @@ extern "C" {
/**
* @brief Initialize memory helper
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_init(void);
ctap_status_code_t fido2_ctap_mem_init(void);
/**
* @brief Read from flash memory
@ -112,34 +112,34 @@ int fido2_ctap_mem_init(void);
* @param[in] offset offset from the start of the page (in bytes)
* @param[in] len number of bytes to write
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_read(void *buf, uint32_t page, uint32_t offset, uint32_t len);
ctap_status_code_t fido2_ctap_mem_read(void *buf, uint32_t page, uint32_t offset, uint32_t len);
/**
* @brief Erase all flashpages containing CTAP data
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_erase_flash(void);
ctap_status_code_t fido2_ctap_mem_erase_flash(void);
/**
* @brief Read authenticator state from flash
*
* @param[in] state pointer to authenticator state
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_read_state_from_flash(ctap_state_t *state);
ctap_status_code_t fido2_ctap_mem_read_state_from_flash(ctap_state_t *state);
/**
* @brief Write authenticator state to flash
*
* @param[in] state pointer to authenticator state
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_write_state_to_flash(ctap_state_t *state);
ctap_status_code_t fido2_ctap_mem_write_state_to_flash(ctap_state_t *state);
/**
* @brief Find resident credential for @p rp_id_hash in flash
@ -153,19 +153,19 @@ int fido2_ctap_mem_write_state_to_flash(ctap_state_t *state);
* @param[in] rp_id_hash pointer to hash of rp domain string
* @param[in] addr pointer to address where to read from
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_read_rk_from_flash(ctap_resident_key_t *key, uint8_t *rp_id_hash,
uint32_t *addr);
ctap_status_code_t fido2_ctap_mem_read_rk_from_flash(ctap_resident_key_t *key, uint8_t *rp_id_hash,
uint32_t *addr);
/**
* @brief Write resident credential to flash
*
* @param[in] rk pointer to resident credential
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_mem_write_rk_to_flash(ctap_resident_key_t *rk);
ctap_status_code_t fido2_ctap_mem_write_rk_to_flash(ctap_resident_key_t *rk);
#ifdef __cplusplus
}

View File

@ -38,18 +38,18 @@ void fido2_ctap_utils_led_animation(void);
/**
* @brief Initialize button to be used for user presence test
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_utils_init_gpio_pin(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank);
ctap_status_code_t fido2_ctap_utils_init_gpio_pin(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank);
/**
* @brief Test user presence
*
* Successful if user clicks button in less than @ref CTAP_UP_TIMEOUT
*
* @return @ref ctap_status_codes_t
* @return @ref ctap_status_code_t
*/
int fido2_ctap_utils_user_presence_test(void);
ctap_status_code_t fido2_ctap_utils_user_presence_test(void);
/**
* @brief Compare fido2 credentials based on id to find more recent one

View File

@ -208,7 +208,7 @@ typedef struct __attribute__((packed)){
typedef struct {
bool taken; /**< is cid taken? */
uint32_t cid; /**< channel identifier */
uint64_t last_used; /**< timestamp of last usage */
uint32_t last_used; /**< timestamp of last usage */
} ctap_hid_cid_t;
/**

View File

@ -1,39 +1,24 @@
BOARD ?= nrf52840dk
#BOARD ?= nrf52840dongle
BOARD ?= native
include ../Makefile.sys_common
USEMODULE += fido2_ctap_transport_hid
USEMODULE += usbus
USEMODULE += ztimer_sec
USEPKG += fido2_tests
BOARD_WHITELIST = \
native \
nrf52840dk \
nrf52840dongle
USB_VID ?= $(USB_VID_TESTING)
USB_PID ?= $(USB_PID_TESTING)
# same as CTAP_STACKSIZE
CFLAGS += -DTHREAD_STACKSIZE_MAIN=15000
# Add unittest framework
USEMODULE += embunit
USEMODULE += fido2_ctap
# Disable user presence tests
# Should be used when running fido2-test to make them run quicker
#CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1
CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1
# Disable user LED animation
#CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_LED=1
# FIDO2 tests except for the ones requiring user presence
#
# Use env -i because fido2-test has a depedency (pyscard) that needs to be
# compiled natively (x86-64). Therefore we need to clear the flags set by e.g.
# BOARD = nrf52840dk
fido2-test:
env -i PATH=$(PATH) $(MAKE) -C $(PKGDIRBASE)/fido2_tests
# FIDO2 user presence tests.
#
# Make sure to enable user presence tests by uncommenting CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1
#
# Use env -i because fido2-test has a depedency (pyscard) that needs to be
# compiled natively (x86-64). Therefore we need to clear the flags set by e.g.
# BOARD = nrf52840dk
fido2-test-up:
env -i PATH=$(PATH) $(MAKE) -C $(PKGDIRBASE)/fido2_tests up-tests
CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_LED=1
include $(RIOTBASE)/Makefile.include

View File

@ -1,59 +1,16 @@
# Test Application for FIDO2 CTAP
# Overview
This test aims to test the FIDO2 CTAP implementation by creating a FIDO2
authenticator which uses CTAPHID as communication protocol.
This test application tests FIDO2 CTAP2 functionality without a transport layer being used.
Note:
* This test application has only been tested on an nrf52840 DK.
To execute the test run e.g.
The test application requires at least 16536 bytes of stack memory which are
divided as follows:
* 512 bytes isr_stack
* 1024 usbus
* 15000 bytes FIDO2 CTAP
```
BOARD = nrf52840dk make flash test
```
## Usage
The FIDO2 authenticator can be tested in two ways:
To generate a new test case array run:
* Note: This requires the [python-fido lib](https://github.com/Yubico/python-fido2)
### Functional testing
1. Flash the device with `make flash`.
2. Test the authenticator on a website like [Webauthn.io](https://webauthn.io/).
Note:
* Due to limited support of FIDO2 CTAP in browsers as of now, make sure to use the
Chromium or Google Chrome browser when testing on [Webauthn.io](https://webauthn.io/).
* When registering and authenticating on [Webauthn.io](https://webauthn.io/) you
will need to push button 1 on your device in order to show user presence.
**Resetting the authenticator**
* To reset the authenticator, meaning that all credentials and state information
will be deleted, execute the `reset.py` file located in this directory.
* This requires you to install the python fido2 package. To install run:
`pip install fido2==0.8.1`.
### Unit testing
Unit testing is based on the `fido2_tests` package.
There are two test targets (fido2-test, fido2-test-up). The former requires no user
interaction the latter does.
Note:
* The tests require python 3.6+.
* The tests require [swig](http://www.swig.org/) to be installed on your host computer.
* Running the tests for the first time will setup a virtual python environment (venv) and install python dependencies of the tests. To check the dependencies please refer to the `requirements.txt` of the [fido2-tests repository](https://github.com/solokeys/fido2-tests).
* The unit tests will require you to reboot the authenticator multiple times. Be patient before continuing as it takes a few seconds for the connection between OS and authenticator to be re-established.
* If you keep getting errors while trying to run the tests try changing to another git branch and back e.g. `git checkout branch1 && git checkout -` in order to remove build artifacts. Then re-flash the device with `make flash term` and try to run the tests again with `make fido2-test` or `make fido2-test-up`.
fido2-test
1. To make benchmarking faster disable user presence tests by enabling the CFLAG
`CONFIG_FIDO2_CTAP_DISABLE_UP` in the Makefile or through KConfig.
2. Flash the device with `make flash`.
3. Run the unit tests by running `make fido2-test`.
fido2-test-up
1. Make sure that the CFLAG `CONFIG_FIDO2_CTAP_DISABLE_UP` is disabled as this test target
requires user interaction.
2. Flash the device with `make flash`.
3. Run the unit tests by running `make fido2-test-up` and follow the instructions. E.g. when `.ACTIVATE UP ONCE` is displayed, press the configured UP button (default button 1) once.
```
python3 gen_test_case.py
```

View File

@ -0,0 +1,92 @@
from fido2.ctap2 import CTAP2
from fido2 import cbor
from fido2.client import Fido2Client
from fido2.server import Fido2Server
from unittest import mock
def mock_device():
device = mock.MagicMock()
return CTAP2(device)
def get_cbor(data):
request = b""
if data is not None:
request += cbor.encode(data)
return request
def args(*params):
"""Constructs a dict from a list of arguments for sending a CBOR command.
None elements will be omitted.
"""
return dict((i, v) for i, v in enumerate(params, 1) if v is not None)
def print_req(req, prefix):
print(f"static uint8_t {prefix}_data[] = {{", end='')
print("".join(f"{hex(x)}, " for x in req), end='')
print("};")
def gen_mc_req():
dev = mock_device()
dev.capabilities = 0
user = {"id": b"user_id", "name": "A. User"}
client = Fido2Client(dev, "https://example.com")
server = Fido2Server({"id": "example.com", "name": "Example RP"}, attestation="direct")
create_options, _ = server.register_begin(user)
create_options = create_options['publicKey']
client_data = client._build_client_data("webauthn.create", create_options['challenge'])
options = {}
options["rk"] = True
return get_cbor(
args(
client_data.hash,
create_options["rp"],
create_options["user"],
create_options["pubKeyCredParams"],
None, # exclude list
None, # extensions
options,
None, # pin_auth
None, # pin protocol version
))
def gen_ga_req():
dev = mock_device()
dev.capabilities = 0
# user = {"id": b"user_id", "name": "A. User"}
client = Fido2Client(dev, "https://example.com")
server = Fido2Server({"id": "example.com", "name": "Example RP"}, attestation="direct")
request_options, _ = server.authenticate_begin()
request_options = request_options['publicKey']
client_data = client._build_client_data("webauthn.get", request_options['challenge'])
return get_cbor(
args(
request_options["rpId"],
client_data.hash,
None, # allow list
None, # extensions
None, # options
None, # pin_uv_param
None # pin_uv_protocol
))
if __name__ == "__main__":
req = gen_mc_req()
print_req(req, "mc")
print("")
req = gen_ga_req()
print_req(req, "ga")

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Freie Universität Berlin
* Copyright (C) 2022 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -10,27 +10,91 @@
* @ingroup tests
* @{
* @file
* @brief FIDO2 CTAP test application that creates an authenticator
* which uses CTAPHID as underlying communication protocol
* @brief FIDO2 CTAP test application that tests CTAP functionality
* without transport layer.
*
* @author Nils Ollrogge <nils-ollrogge@outlook.de>
* @author Nils Ollrogge <nils.ollrogge@mailbox.tu-dresden.de>
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#define ENABLE_DEBUG 0
#include "debug.h"
#include "ztimer.h"
#include "embUnit.h"
#include "fido2/ctap.h"
#include "fido2/ctap/transport/ctap_transport.h"
/**
* To generate a new arrays simply run the gen_test_case.py script
*/
static uint8_t mc_data[] =
{ 0xa5, 0x1, 0x58, 0x20, 0xe0, 0xa1, 0xec, 0x5a, 0xa, 0x12, 0xa1, 0x4, 0xc8, 0xcb, 0x93, 0x54, 0x31,
0xbf, 0x5c, 0x39, 0x7a, 0xee, 0x1b, 0x9f, 0xd0, 0x97, 0x97, 0x7d, 0x7b, 0xfb, 0x1, 0xa1, 0x20,
0x2a, 0xad, 0x5c, 0x2, 0xa2, 0x62, 0x69, 0x64, 0x6b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
0x2e, 0x63, 0x6f, 0x6d, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c,
0x65, 0x20, 0x52, 0x50, 0x3, 0xa2, 0x62, 0x69, 0x64, 0x47, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
0x64, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x67, 0x41, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x72, 0x4, 0x84,
0xa2, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x27, 0x64, 0x74, 0x79, 0x70,
0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c,
0x67, 0x38, 0x24, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d,
0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x39, 0x1, 0x0, 0x64, 0x74, 0x79, 0x70, 0x65,
0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x7, 0xa1, 0x62, 0x72, 0x6b,
0xf5, };
static uint8_t ga_data[] =
{ 0xa2, 0x1, 0x6b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2, 0x58,
0x20, 0x7d, 0xf3, 0x9a, 0x49, 0xa9, 0x8c, 0xa2, 0xd8, 0x3e, 0x50, 0x36, 0x42, 0xd9, 0xc6, 0xfa,
0x39, 0xf5, 0xa7, 0xe9, 0x35, 0x41, 0xb0, 0x1c, 0x59, 0xfa, 0xc2, 0x35, 0x3a, 0xb0, 0xbc, 0xcc,
0x70, };
static void test_ctap(void)
{
fido2_ctap_init();
ctap_req_t req = { 0 };
ctap_resp_t resp = { 0 };
/* reset authenticator */
req.method = CTAP_RESET;
req.buf = NULL;
req.len = 0x0;
fido2_ctap_handle_request(&req, &resp);
TEST_ASSERT(resp.status == CTAP2_OK);
/* create new credential */
req.method = CTAP_MAKE_CREDENTIAL;
req.buf = mc_data;
req.len = sizeof(mc_data);
fido2_ctap_handle_request(&req, &resp);
TEST_ASSERT(resp.status == CTAP2_OK);
/* create assertion using credential */
req.method = CTAP_GET_ASSERTION;
req.buf = ga_data;
req.len = sizeof(ga_data);
fido2_ctap_handle_request(&req, &resp);
TEST_ASSERT(resp.status == CTAP2_OK);
}
Test *ctap_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_ctap),
};
EMB_UNIT_TESTCALLER(ctap_tests, NULL, NULL, fixtures);
return (Test *)&ctap_tests;
}
int main(void)
{
/* sleep in order to see early DEBUG outputs */
ztimer_sleep(ZTIMER_SEC, 3);
fido2_ctap_transport_init();
TESTS_START();
TESTS_RUN(ctap_tests());
TESTS_END();
return 0;
}
/** @} */

View File

@ -0,0 +1,14 @@
#!/usr/bin/env python3
# Copyright (C) 2022 Freie Universität Berlin
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import sys
from testrunner import run_check_unittests
if __name__ == "__main__":
sys.exit(run_check_unittests())

View File

@ -0,0 +1,41 @@
BOARD ?= nrf52840dk
#BOARD ?= nrf52840dongle
include ../Makefile.sys_common
BOARD_WHITELIST = \
nrf52840dk \
nrf52840dongle
USEMODULE += fido2_ctap_transport_hid
USEPKG += fido2_tests
USB_VID ?= $(USB_VID_TESTING)
USB_PID ?= $(USB_PID_TESTING)
# Disable user presence tests
# Should be used when running fido2-test to make them run quicker
CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1
# Disable user LED animation
CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_LED=1
# FIDO2 tests except for the ones requiring user presence
#
# Use env -i because fido2-test has a depedency (pyscard) that needs to be
# compiled natively (x86-64). Therefore we need to clear the flags set by e.g.
# BOARD = nrf52840dk
fido2-test:
env -i PATH=$(PATH) $(MAKE) -C $(RIOTBASE)/build/pkg/fido2_tests
# FIDO2 user presence tests.
#
# Make sure to enable user presence tests by uncommenting CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1
#
# Use env -i because fido2-test has a depedency (pyscard) that needs to be
# compiled natively (x86-64). Therefore we need to clear the flags set by e.g.
# BOARD = nrf52840dk
fido2-test-up:
env -i PATH=$(PATH) $(MAKE) -C $(RIOTBASE)/build/pkg/fido2_tests up-tests
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,59 @@
# Test Application for FIDO2 CTAP using USB HID transport binding
This test aims to test the FIDO2 CTAP implementation by creating a FIDO2
authenticator which uses CTAPHID as communication protocol.
Note:
* This test application has only been tested on an nrf52840 DK.
The test application requires at least 16536 bytes of stack memory which are
divided as follows:
* 512 bytes isr_stack
* 1024 usbus
* 15000 bytes FIDO2 CTAP
## Usage
The FIDO2 authenticator can be tested in two ways:
### Functional testing
1. Flash the device with `make flash`.
2. Test the authenticator on a website like [Webauthn.io](https://webauthn.io/).
Note:
* Due to limited support of FIDO2 CTAP in browsers as of now, make sure to use the
Chromium or Google Chrome browser when testing on [Webauthn.io](https://webauthn.io/).
* When registering and authenticating on [Webauthn.io](https://webauthn.io/) you
will need to push button 1 on your device in order to show user presence.
**Resetting the authenticator**
* To reset the authenticator, meaning that all credentials and state information
will be deleted, execute the `reset.py` file located in this directory.
* This requires you to install the python fido2 package. To install run:
`pip install fido2==0.8.1`.
### Unit testing
Unit testing is based on the `fido2_tests` package.
There are two test targets (fido2-test, fido2-test-up). The former requires no user
interaction the latter does.
Note:
* The tests require python 3.6+.
* The tests require [swig](http://www.swig.org/) to be installed on your host computer.
* Running the tests for the first time will setup a virtual python environment (venv) and install python dependencies of the tests. To check the dependencies please refer to the `requirements.txt` of the [fido2-tests repository](https://github.com/solokeys/fido2-tests).
* The unit tests will require you to reboot the authenticator multiple times. Be patient before continuing as it takes a few seconds for the connection between OS and authenticator to be re-established.
* If you keep getting errors while trying to run the tests try changing to another git branch and back e.g. `git checkout branch1 && git checkout -` in order to remove build artifacts. Then re-flash the device with `make flash term` and try to run the tests again with `make fido2-test` or `make fido2-test-up`.
fido2-test
1. To make benchmarking faster disable user presence tests by enabling the CFLAG
`CONFIG_FIDO2_CTAP_DISABLE_UP` in the Makefile or through KConfig.
2. Flash the device with `make flash`.
3. Run the unit tests by running `make fido2-test`.
fido2-test-up
1. Make sure that the CFLAG `CONFIG_FIDO2_CTAP_DISABLE_UP` is disabled as this test target
requires user interaction.
2. Flash the device with `make flash`.
3. Run the unit tests by running `make fido2-test-up` and follow the instructions. E.g. when `.ACTIVATE UP ONCE` is displayed, press the configured UP button (default button 1) once.

View File

@ -0,0 +1,8 @@
CONFIG_MODULE_AUTO_INIT_USBUS=n
CONFIG_MODULE_USBUS=y
CONFIG_MODULE_FIDO2=y
CONFIG_MODULE_FIDO2_CTAP=y
CONFIG_MODULE_FIDO2_CTAP_TRANSPORT=y
CONFIG_MODULE_FIDO2_CTAP_TRANSPORT_HID=y
CONFIG_PACKAGE_FIDO2_TESTS=y

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2022 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
* @file
* @brief FIDO2 CTAP test application that creates an authenticator
* which uses CTAPHID as underlying communication protocol
*
* @author Nils Ollrogge <nils.ollrogge@mailbox.tu-dresden.de>
* @}
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "ztimer.h"
#include "fido2/ctap/transport/ctap_transport.h"
int main(void)
{
/* sleep in order to see early DEBUG outputs */
ztimer_sleep(ZTIMER_MSEC, 3000);
fido2_ctap_transport_init();
}