diff --git a/sys/fido2/Makefile.dep b/sys/fido2/Makefile.dep index 6164ad235c..9f447ef7e1 100644 --- a/sys/fido2/Makefile.dep +++ b/sys/fido2/Makefile.dep @@ -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 diff --git a/sys/fido2/ctap/ctap.c b/sys/fido2/ctap/ctap.c index 4db1389459..55a61b8eff 100644 --- a/sys/fido2/ctap/ctap.c +++ b/sys/fido2/ctap/ctap.c @@ -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); diff --git a/sys/fido2/ctap/ctap_cbor.c b/sys/fido2/ctap/ctap_cbor.c index ffcde237f1..b1b5b223aa 100644 --- a/sys/fido2/ctap/ctap_cbor.c +++ b/sys/fido2/ctap/ctap_cbor.c @@ -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; diff --git a/sys/fido2/ctap/ctap_crypto.c b/sys/fido2/ctap/ctap_crypto.c index ecc4ffd9e7..0dba6eb76a 100644 --- a/sys/fido2/ctap/ctap_crypto.c +++ b/sys/fido2/ctap/ctap_crypto.c @@ -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; diff --git a/sys/fido2/ctap/ctap_mem.c b/sys/fido2/ctap/ctap_mem.c index 22e7c9fae7..629f7a669d 100644 --- a/sys/fido2/ctap/ctap_mem.c +++ b/sys/fido2/ctap/ctap_mem.c @@ -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) { diff --git a/sys/fido2/ctap/ctap_utils.c b/sys/fido2/ctap/ctap_utils.c index dfa7e654e8..1f022bf4ac 100644 --- a/sys/fido2/ctap/ctap_utils.c +++ b/sys/fido2/ctap/ctap_utils.c @@ -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; diff --git a/sys/fido2/ctap/transport/hid/ctap_hid.c b/sys/fido2/ctap/transport/hid/ctap_hid.c index 0149f22b19..725ba5a19e 100644 --- a/sys/fido2/ctap/transport/hid/ctap_hid.c +++ b/sys/fido2/ctap/transport/hid/ctap_hid.c @@ -18,7 +18,6 @@ #include #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; } } diff --git a/sys/include/fido2/ctap.h b/sys/include/fido2/ctap.h index 07a3363a0e..dbf522b1de 100644 --- a/sys/include/fido2/ctap.h +++ b/sys/include/fido2/ctap.h @@ -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 } diff --git a/sys/include/fido2/ctap/ctap.h b/sys/include/fido2/ctap/ctap.h index 87c1680926..7849ec9f74 100644 --- a/sys/include/fido2/ctap/ctap.h +++ b/sys/include/fido2/ctap/ctap.h @@ -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); diff --git a/sys/include/fido2/ctap/ctap_cbor.h b/sys/include/fido2/ctap/ctap_cbor.h index a506324170..7b5a808e8f 100644 --- a/sys/include/fido2/ctap/ctap_cbor.h +++ b/sys/include/fido2/ctap/ctap_cbor.h @@ -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 diff --git a/sys/include/fido2/ctap/ctap_crypto.h b/sys/include/fido2/ctap/ctap_crypto.h index 49ff65fb0b..ac551ccfb8 100644 --- a/sys/include/fido2/ctap/ctap_crypto.h +++ b/sys/include/fido2/ctap/ctap_crypto.h @@ -26,6 +26,7 @@ #include #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, diff --git a/sys/include/fido2/ctap/ctap_mem.h b/sys/include/fido2/ctap/ctap_mem.h index aefc7ca2ec..96e52d9da2 100644 --- a/sys/include/fido2/ctap/ctap_mem.h +++ b/sys/include/fido2/ctap/ctap_mem.h @@ -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 } diff --git a/sys/include/fido2/ctap/ctap_utils.h b/sys/include/fido2/ctap/ctap_utils.h index 3050a7c2c9..d32d9cc248 100644 --- a/sys/include/fido2/ctap/ctap_utils.h +++ b/sys/include/fido2/ctap/ctap_utils.h @@ -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 diff --git a/sys/include/fido2/ctap/transport/hid/ctap_hid.h b/sys/include/fido2/ctap/transport/hid/ctap_hid.h index 48cdecd510..79908d8198 100644 --- a/sys/include/fido2/ctap/transport/hid/ctap_hid.h +++ b/sys/include/fido2/ctap/transport/hid/ctap_hid.h @@ -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; /** diff --git a/tests/sys/fido2_ctap/Makefile b/tests/sys/fido2_ctap/Makefile index 31999264d5..9fd89cdf42 100644 --- a/tests/sys/fido2_ctap/Makefile +++ b/tests/sys/fido2_ctap/Makefile @@ -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 diff --git a/tests/sys/fido2_ctap/README.md b/tests/sys/fido2_ctap/README.md index 726866ee7f..e73745fec9 100644 --- a/tests/sys/fido2_ctap/README.md +++ b/tests/sys/fido2_ctap/README.md @@ -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 +``` \ No newline at end of file diff --git a/tests/sys/fido2_ctap/gen_test_case.py b/tests/sys/fido2_ctap/gen_test_case.py new file mode 100644 index 0000000000..5b56b33174 --- /dev/null +++ b/tests/sys/fido2_ctap/gen_test_case.py @@ -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") diff --git a/tests/sys/fido2_ctap/main.c b/tests/sys/fido2_ctap/main.c index 6fbf5cd4e7..51fa8bc115 100644 --- a/tests/sys/fido2_ctap/main.c +++ b/tests/sys/fido2_ctap/main.c @@ -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 + * @author Nils Ollrogge * @} */ - #include #include -#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; } +/** @} */ diff --git a/tests/sys/fido2_ctap/tests/01-run.py b/tests/sys/fido2_ctap/tests/01-run.py new file mode 100755 index 0000000000..06365aea55 --- /dev/null +++ b/tests/sys/fido2_ctap/tests/01-run.py @@ -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()) diff --git a/tests/sys/fido2_ctap_hid/Makefile b/tests/sys/fido2_ctap_hid/Makefile new file mode 100644 index 0000000000..0b26274ee7 --- /dev/null +++ b/tests/sys/fido2_ctap_hid/Makefile @@ -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 diff --git a/tests/sys/fido2_ctap_hid/README.md b/tests/sys/fido2_ctap_hid/README.md new file mode 100644 index 0000000000..5846b7da8f --- /dev/null +++ b/tests/sys/fido2_ctap_hid/README.md @@ -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. diff --git a/tests/sys/fido2_ctap_hid/app.config.test b/tests/sys/fido2_ctap_hid/app.config.test new file mode 100644 index 0000000000..df5e7e4f8d --- /dev/null +++ b/tests/sys/fido2_ctap_hid/app.config.test @@ -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 diff --git a/tests/sys/fido2_ctap_hid/main.c b/tests/sys/fido2_ctap_hid/main.c new file mode 100644 index 0000000000..95a30713eb --- /dev/null +++ b/tests/sys/fido2_ctap_hid/main.c @@ -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 + * @} + */ +#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(); +} diff --git a/tests/sys/fido2_ctap/reset.py b/tests/sys/fido2_ctap_hid/reset.py similarity index 100% rename from tests/sys/fido2_ctap/reset.py rename to tests/sys/fido2_ctap_hid/reset.py