Skip to content

Commit

Permalink
Merge pull request #18663 from Ollrogge/fido2_follow_up2
Browse files Browse the repository at this point in the history
sys/fido2: follow up continued
  • Loading branch information
kfessel authored Nov 28, 2024
2 parents 67a22db + db95ef6 commit 737f675
Show file tree
Hide file tree
Showing 24 changed files with 669 additions and 390 deletions.
3 changes: 3 additions & 0 deletions sys/fido2/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,4 +28,5 @@ ifneq (,$(filter fido2_ctap,$(USEMODULE)))
USEMODULE += crypto_aes_256
USEMODULE += hashes
USEMODULE += fido2
USEMODULE += fmt
endif
130 changes: 72 additions & 58 deletions sys/fido2/ctap/ctap.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,162 +248,173 @@ 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;
}
}

if (!IS_ACTIVE(CONFIG_FIDO2_CTAP_DISABLE_UP)) {
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);

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)
{
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);

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);

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);

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)
{
assert(resp);

resp->status = _reset();
resp->len = 0x0;

return 0;
return resp->status;
}

static uint32_t get_id(void)
Expand All @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand 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,
Expand Down Expand 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;
}
Expand All @@ -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:
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);

Expand Down
Loading

0 comments on commit 737f675

Please sign in to comment.