From ac45986342e9d7bdad7381ab9b25aecd625515d6 Mon Sep 17 00:00:00 2001 From: Lucas PASCAL Date: Mon, 18 Nov 2024 11:54:24 +0100 Subject: [PATCH] [clean] Trying to simplify higher-level, global interfaces --- include/ctap2.h | 103 +----------------- include/globals.h | 41 +++++-- src/ctap2/client_pin.c | 15 +-- src/ctap2/ctap2_utils.c | 68 ++++++++++++ src/ctap2/ctap2_utils.h | 37 +++++++ src/ctap2/get_assertion/get_assertion.c | 17 ++- .../get_assertion/get_assertion_struct.h | 67 ++++++++++++ src/ctap2/get_assertion/get_assertion_utils.c | 4 +- src/ctap2/get_assertion/get_assertion_utils.h | 6 + src/ctap2/get_info.c | 7 +- src/ctap2/make_credential/make_credential.c | 17 ++- .../make_credential/make_credential_struct.h | 40 +++++++ .../make_credential/make_credential_utils.c | 4 +- .../make_credential/make_credential_utils.h | 6 + src/ctap2/processing.c | 54 +-------- src/ctap2/reset/reset.c | 3 +- src/ctap2/reset/reset_utils.c | 5 +- src/globals.c | 17 +-- src/u2f_processing.c | 8 +- tests/unit-tests/Makefile | 2 +- 20 files changed, 325 insertions(+), 196 deletions(-) create mode 100644 src/ctap2/ctap2_utils.c create mode 100644 src/ctap2/ctap2_utils.h create mode 100644 src/ctap2/get_assertion/get_assertion_struct.h create mode 100644 src/ctap2/make_credential/make_credential_struct.h diff --git a/include/ctap2.h b/include/ctap2.h index 310ab45a..58481e75 100644 --- a/include/ctap2.h +++ b/include/ctap2.h @@ -20,17 +20,18 @@ #define __CTAP2_H__ #ifndef UNIT_TESTS -#include "cx.h" -#include "os_io_seproxyhal.h" +#include +#include -#include "u2f_service.h" -#include "u2f_transport.h" +#include +#include #else #include "unit_test.h" #endif #include "cbip_decode.h" #include "extension_hmac_secret.h" +#include "ctap2_utils.h" #define RP_ID_HASH_SIZE CX_SHA256_SIZE #define CRED_RANDOM_SIZE 32 @@ -88,102 +89,8 @@ #define FLAG_EXTENSION_HMAC_SECRET 0x01 -// Helper to detect if CTAP2_CBOR_CMD command is proxyied over U2F_CMD -// - CTAP2 calls that are CTAP2_CMD_CBOR commands: -// There is a direct call from lib_stusb_impl/u2f_impl.c:u2f_message_complete() -// to ctap2_handle_cmd_cbor(), hence G_io_app.apdu_state = APDU_IDLE -// - CTAP2 calls that are encapsulated on an APDU over U2F_CMD_MSG command -// This calls goes through: -// - lib_stusb_impl/u2f_impl.c:u2f_message_complete() -// - lib_stusb_impl/u2f_impl.c:u2f_handle_cmd_msg() -// - .... -// - src/main.c:sample_main() -// - src/u2f_processing.c:handleApdu() -// In this case G_io_app.apdu_state is set to APDU_U2F in -// lib_stusb_impl/u2f_impl.c:u2f_handle_cmd_msg() -#define CMD_IS_OVER_U2F_CMD (G_io_app.apdu_state != APDU_IDLE) -#define CMD_IS_OVER_CTAP2_CBOR_CMD (G_io_app.apdu_state == APDU_IDLE) - -#define CMD_IS_OVER_U2F_USB (G_io_u2f.media == U2F_MEDIA_USB) - -#ifdef HAVE_NFC -#define CMD_IS_OVER_U2F_NFC (G_io_app.apdu_media == IO_APDU_MEDIA_NFC) -void nfc_idle_work2(void); -#else -#define CMD_IS_OVER_U2F_NFC false -#endif - extern const uint8_t AAGUID[16]; -typedef struct ctap2_register_data_s { - uint8_t rpIdHash[CX_SHA256_SIZE]; - uint8_t *buffer; // pointer to the CBOR message in the APDU buffer - char *rpId; - uint32_t rpIdLen; - uint8_t *clientDataHash; - uint8_t *userId; - uint32_t userIdLen; - char *userStr; - uint32_t userStrLen; - int coseAlgorithm; // algorithm chosen following the request message - uint8_t pinRequired; // set if uv is set - uint8_t pinPresented; // set if the PIN request was acknowledged by the user - uint8_t - clientPinAuthenticated; // set if a standard FIDO client PIN authentication was performed - uint8_t residentKey; // set if the credential shall be created as a resident key - uint8_t extensions; // extensions flags as a bitmask -} ctap2_register_data_t; - -typedef union ctap2_assert_multiple_flow_data_s { - struct { - cbipItem_t credentialItem; - uint32_t currentCredential; - } allowList; - struct { - uint16_t minAge; - } rk; -} ctap2_assert_multiple_flow_data_t; - -typedef struct ctap2_assert_data_s { - uint8_t rpIdHash[CX_SHA256_SIZE]; - uint8_t *buffer; // pointer to the CBOR message in the APDU buffer - char *rpId; - uint32_t rpIdLen; - uint8_t *clientDataHash; - uint8_t *credId; - uint32_t credIdLen; - uint8_t *nonce; - uint8_t *credential; - uint32_t credentialLen; - uint8_t pinRequired; // set if uv is set - uint8_t pinPresented; // set if the PIN request was acknowledged by the user - uint8_t - clientPinAuthenticated; // set if a standard FIDO client PIN authentication was performed - uint8_t userPresenceRequired; // set if up is set - uint8_t extensions; // extensions flags as a bitmask - - uint8_t allowListPresent; - uint16_t availableCredentials; - - // Multiple flow data - uint16_t currentCredentialIndex; - ctap2_assert_multiple_flow_data_t multipleFlowData; -} ctap2_assert_data_t; - -typedef enum ctap2_ux_state_e { - CTAP2_UX_STATE_NONE = 0, - CTAP2_UX_STATE_MAKE_CRED, - CTAP2_UX_STATE_GET_ASSERTION, - CTAP2_UX_STATE_MULTIPLE_ASSERTION, - CTAP2_UX_STATE_NO_ASSERTION, - CTAP2_UX_STATE_RESET, -} ctap2_ux_state_t; - -bool ctap2_check_rpid_filter(const char *rpId, uint32_t rpIdLen); -void send_cbor_error(u2f_service_t *service, uint8_t error); -void send_cbor_response(u2f_service_t *service, uint32_t length); -void ctap2_send_keepalive_processing(void); - // Correspond to FIDO2.1 spec performBuiltInUv() operation void performBuiltInUv(void); diff --git a/include/globals.h b/include/globals.h index ff4ad610..10a03ab5 100644 --- a/include/globals.h +++ b/include/globals.h @@ -18,11 +18,12 @@ #pragma once -#include "u2f_service.h" +#include #include "credential.h" #include "u2f_process.h" -#include "ctap2.h" +#include "ctap2/make_credential/make_credential_struct.h" +#include "ctap2/get_assertion/get_assertion_struct.h" #define U2F_VERSION "U2F_V2" #define U2F_VERSION_SIZE (sizeof(U2F_VERSION) - 1) @@ -69,6 +70,31 @@ static const uint8_t FIDO_AID[FIDO_AID_SIZE] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x #define NAME_BUFFER_SIZE 65 +// Helper to detect if CTAP2_CBOR_CMD command is proxyied over U2F_CMD +// - CTAP2 calls that are CTAP2_CMD_CBOR commands: +// There is a direct call from lib_stusb_impl/u2f_impl.c:u2f_message_complete() +// to ctap2_handle_cmd_cbor(), hence G_io_app.apdu_state = APDU_IDLE +// - CTAP2 calls that are encapsulated on an APDU over U2F_CMD_MSG command +// This calls goes through: +// - lib_stusb_impl/u2f_impl.c:u2f_message_complete() +// - lib_stusb_impl/u2f_impl.c:u2f_handle_cmd_msg() +// - .... +// - src/main.c:sample_main() +// - src/u2f_processing.c:handleApdu() +// In this case G_io_app.apdu_state is set to APDU_U2F in +// lib_stusb_impl/u2f_impl.c:u2f_handle_cmd_msg() +#define CMD_IS_OVER_U2F_CMD (G_io_app.apdu_state != APDU_IDLE) +#define CMD_IS_OVER_CTAP2_CBOR_CMD (G_io_app.apdu_state == APDU_IDLE) + +#define CMD_IS_OVER_U2F_USB (G_io_u2f.media == U2F_MEDIA_USB) + +#ifdef HAVE_NFC +#define CMD_IS_OVER_U2F_NFC (G_io_app.apdu_media == IO_APDU_MEDIA_NFC) +void nfc_idle_work2(void); +#else +#define CMD_IS_OVER_U2F_NFC false +#endif + typedef struct global_s { char buffer_20[20]; char buffer1_65[NAME_BUFFER_SIZE]; @@ -115,14 +141,6 @@ static inline ctap2_data_t *globals_get_ctap2_data(void) { return &shared_ctx.u.ctap2Data; } -static inline ctap2_register_data_t *globals_get_ctap2_register_data(void) { - return &shared_ctx.u.ctap2Data.u.ctap2RegisterData; -} - -static inline ctap2_assert_data_t *globals_get_ctap2_assert_data(void) { - return &shared_ctx.u.ctap2Data.u.ctap2AssertData; -} - /* * Truncate strings stored in global buffers to fit screen width. Truncation depends on police size: * - on classic review screens, the police is larger, argument `large` should be `true` . @@ -148,4 +166,7 @@ void truncate_pairs_for_display(bool large); */ void prepare_display_status(bool clean_buffer); +void ctap2_display_copy_username(const char *name, uint8_t nameLength); +void ctap2_display_copy_rp(const char *name, uint8_t nameLength); + void ctap2_copy_info_on_buffers(void); diff --git a/src/ctap2/client_pin.c b/src/ctap2/client_pin.c index b6b37e1f..97989222 100644 --- a/src/ctap2/client_pin.c +++ b/src/ctap2/client_pin.c @@ -16,11 +16,12 @@ * limitations under the License. ********************************************************************************/ -#include "os.h" -#include "cx.h" -#include "ledger_assert.h" +#include +#include +#include #include "ctap2.h" +#include "ctap2_utils.h" #include "config.h" #include "cbip_helper.h" #include "cose_keys.h" @@ -383,7 +384,7 @@ static void handle_store_pin(u2f_service_t *service, authTokeninUse = false; responseBuffer[0] = ERROR_NONE; - send_cbor_response(&G_io_u2f, 1); + send_cbor_response(&G_io_u2f, 1, NULL); } static int check_pin_hash(int protocol, @@ -450,7 +451,7 @@ static void ctap2_handle_get_pin_retries(u2f_service_t *service, cbip_add_int(&encoder, N_u2f.pinRetries); responseBuffer[0] = ERROR_NONE; - send_cbor_response(&G_io_u2f, 1 + encoder.offset); + send_cbor_response(&G_io_u2f, 1 + encoder.offset, NULL); } static void ctap2_handle_get_key_agreement(u2f_service_t *service, @@ -483,7 +484,7 @@ static void ctap2_handle_get_key_agreement(u2f_service_t *service, } responseBuffer[0] = ERROR_NONE; - send_cbor_response(&G_io_u2f, 1 + encoder.offset); + send_cbor_response(&G_io_u2f, 1 + encoder.offset, NULL); } static void ctap2_handle_set_pin(u2f_service_t *service, @@ -664,7 +665,7 @@ static void ctap2_handle_get_pin_token(u2f_service_t *service, cbip_add_byte_string(&encoder, tokenEnc, encryptedLength); responseBuffer[0] = ERROR_NONE; - send_cbor_response(&G_io_u2f, 1 + encoder.offset); + send_cbor_response(&G_io_u2f, 1 + encoder.offset, NULL); } /******************************************/ diff --git a/src/ctap2/ctap2_utils.c b/src/ctap2/ctap2_utils.c new file mode 100644 index 00000000..c79aaf29 --- /dev/null +++ b/src/ctap2/ctap2_utils.c @@ -0,0 +1,68 @@ +/* +******************************************************************************* +* Ledger App Security Key +* (c) 2024 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include +#include + +#include "ctap2.h" +#include "ctap2_utils.h" +#include "globals.h" +#include "nfc_io.h" +#include "sw_code.h" + +#define RPID_FILTER "webctap." +#define RPID_FILTER_SIZE (sizeof(RPID_FILTER) - 1) + +bool ctap2_check_rpid_filter(const char *rpId, uint32_t rpIdLen) { + if ((rpIdLen < RPID_FILTER_SIZE) || (memcmp(rpId, RPID_FILTER, RPID_FILTER_SIZE) != 0)) { + return true; + } else { + return false; + } +} + +void send_cbor_error(u2f_service_t *service, uint8_t error) { + if (CMD_IS_OVER_U2F_CMD) { + io_send_response_pointer((uint8_t *) &error, 1, SW_NO_ERROR); + } else { + u2f_message_reply(service, CTAP2_CMD_CBOR, (uint8_t *) &error, 1); + } +} + +void send_cbor_response(u2f_service_t *service, uint32_t length, const char *status) { + if (CMD_IS_OVER_U2F_NFC) { + nfc_io_set_response_ready(SW_NO_ERROR, length, status); + nfc_io_send_prepared_response(); + } else if (CMD_IS_OVER_U2F_CMD) { + io_send_response_pointer(responseBuffer, length, SW_NO_ERROR); + } else { + u2f_message_reply(service, CTAP2_CMD_CBOR, responseBuffer, length); + } +} + +void ctap2_send_keepalive_processing() { + if (CMD_IS_OVER_CTAP2_CBOR_CMD) { + u2f_transport_ctap2_send_keepalive(&G_io_u2f, KEEPALIVE_REASON_PROCESSING); + io_seproxyhal_io_heartbeat(); + } +} + +void performBuiltInUv(void) { + PRINTF("performBuiltInUv\n"); + // No-op as the user is verified through the session PIN. +} diff --git a/src/ctap2/ctap2_utils.h b/src/ctap2/ctap2_utils.h new file mode 100644 index 00000000..c298229c --- /dev/null +++ b/src/ctap2/ctap2_utils.h @@ -0,0 +1,37 @@ +/* +******************************************************************************* +* Ledger App Security Key +* (c) 2024 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#pragma once + +#ifndef UNIT_TESTS +#include +#else +#include "unit_test.h" +#endif + +bool ctap2_check_rpid_filter(const char *rpId, uint32_t rpIdLen); +void send_cbor_error(u2f_service_t *service, uint8_t error); + +/* + * Sends the CBOR response on the relevant transport. + * + * If the `status` is not NULL AND the transport is NFC, displays a `status` + * message on the screen (this is for GET_ASSERTION and MAKE_CREDENTIALS cmds). + */ +void send_cbor_response(u2f_service_t *service, uint32_t length, const char *status); +void ctap2_send_keepalive_processing(void); diff --git a/src/ctap2/get_assertion/get_assertion.c b/src/ctap2/get_assertion/get_assertion.c index b3cc7fbc..8e28542a 100644 --- a/src/ctap2/get_assertion/get_assertion.c +++ b/src/ctap2/get_assertion/get_assertion.c @@ -17,6 +17,7 @@ ********************************************************************************/ #include +#include #include "ctap2.h" #include "config.h" @@ -279,6 +280,20 @@ static void nfc_handle_get_assertion() { } } +static void copy_assert_info_on_buffers(void) { + ctap2_assert_data_t *ctap2AssertData = globals_get_ctap2_assert_data(); + + ctap2_display_copy_rp(ctap2AssertData->rpId, ctap2AssertData->rpIdLen); + + if (ctap2AssertData->credId) { + ctap2_display_copy_username((char *) ctap2AssertData->credId, ctap2AssertData->credIdLen); + } else { + uint8_t nameLength = MIN(CX_SHA256_SIZE, (sizeof(g.buffer2_65) - 1) / 2); + format_hex(ctap2AssertData->clientDataHash, nameLength, g.buffer2_65, sizeof(g.buffer2_65)); + } + PRINTF("After copy, buffer content:\n1 - '%s'\n2 - '%s'\n", g.buffer1_65, g.buffer2_65); +} + void ctap2_get_assertion_handle(u2f_service_t *service, uint8_t *buffer, uint16_t length) { ctap2_assert_data_t *ctap2AssertData = globals_get_ctap2_assert_data(); cbipDecoder_t decoder; @@ -344,7 +359,7 @@ void ctap2_get_assertion_handle(u2f_service_t *service, uint8_t *buffer, uint16_ goto exit; } - ctap2_copy_info_on_buffers(); + copy_assert_info_on_buffers(); /* if (true) { */ /* nfc_handle_get_assertion(); */ diff --git a/src/ctap2/get_assertion/get_assertion_struct.h b/src/ctap2/get_assertion/get_assertion_struct.h new file mode 100644 index 00000000..675a3c9c --- /dev/null +++ b/src/ctap2/get_assertion/get_assertion_struct.h @@ -0,0 +1,67 @@ +/* +******************************************************************************* +* Ledger App Security Key +* (c) 2024 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#pragma once + +#include +#include "cbip_decode.h" + +typedef union ctap2_assert_multiple_flow_data_s { + struct { + cbipItem_t credentialItem; + uint32_t currentCredential; + } allowList; + struct { + uint16_t minAge; + } rk; +} ctap2_assert_multiple_flow_data_t; + +typedef struct ctap2_assert_data_s { + uint8_t rpIdHash[CX_SHA256_SIZE]; + uint8_t *buffer; // pointer to the CBOR message in the APDU buffer + char *rpId; + uint32_t rpIdLen; + uint8_t *clientDataHash; // size of CX_SHA256_SIZE + uint8_t *credId; + uint32_t credIdLen; + uint8_t *nonce; + uint8_t *credential; + uint32_t credentialLen; + uint8_t pinRequired; // set if uv is set + uint8_t pinPresented; // set if the PIN request was acknowledged by the user + uint8_t + clientPinAuthenticated; // set if a standard FIDO client PIN authentication was performed + uint8_t userPresenceRequired; // set if up is set + uint8_t extensions; // extensions flags as a bitmask + + uint8_t allowListPresent; + uint16_t availableCredentials; + + // Multiple flow data + uint16_t currentCredentialIndex; + ctap2_assert_multiple_flow_data_t multipleFlowData; +} ctap2_assert_data_t; + +typedef enum ctap2_ux_state_e { + CTAP2_UX_STATE_NONE = 0, + CTAP2_UX_STATE_MAKE_CRED, + CTAP2_UX_STATE_GET_ASSERTION, + CTAP2_UX_STATE_MULTIPLE_ASSERTION, + CTAP2_UX_STATE_NO_ASSERTION, + CTAP2_UX_STATE_RESET, +} ctap2_ux_state_t; diff --git a/src/ctap2/get_assertion/get_assertion_utils.c b/src/ctap2/get_assertion/get_assertion_utils.c index adc603fd..d7c1aaaf 100644 --- a/src/ctap2/get_assertion/get_assertion_utils.c +++ b/src/ctap2/get_assertion/get_assertion_utils.c @@ -27,6 +27,8 @@ #include "crypto.h" #include "globals.h" #include "rk_storage.h" +#include "ctap2_utils.h" +#include "ctap2.h" #include "get_assertion_utils.h" @@ -583,7 +585,7 @@ void get_assertion_send(void) { exit: if (status == 0) { - send_cbor_response(&G_io_u2f, 1 + dataLen); + send_cbor_response(&G_io_u2f, 1 + dataLen, "Login request signed"); } else { PRINTF("GET_ASSERTION build / encoding failed '%d'\n", status); send_cbor_error(&G_io_u2f, status); diff --git a/src/ctap2/get_assertion/get_assertion_utils.h b/src/ctap2/get_assertion/get_assertion_utils.h index 307c744e..d38c2585 100644 --- a/src/ctap2/get_assertion/get_assertion_utils.h +++ b/src/ctap2/get_assertion/get_assertion_utils.h @@ -18,7 +18,9 @@ #pragma once +#include "globals.h" #include "cbip_helper.h" +#include "get_assertion_struct.h" #define TAG_RP_ID 0x01 #define TAG_CLIENT_DATA_HASH 0x02 @@ -49,3 +51,7 @@ void get_assertion_send(void); void get_assertion_user_cancel(); int handle_allowList_item(cbipDecoder_t *decoder, cbipItem_t *item, bool unwrap); + +static inline ctap2_assert_data_t *globals_get_ctap2_assert_data(void) { + return &shared_ctx.u.ctap2Data.u.ctap2AssertData; +} diff --git a/src/ctap2/get_info.c b/src/ctap2/get_info.c index 12553a4e..4b4ce1f7 100644 --- a/src/ctap2/get_info.c +++ b/src/ctap2/get_info.c @@ -16,10 +16,11 @@ * limitations under the License. ********************************************************************************/ -#include "os.h" -#include "cx.h" +#include +#include #include "ctap2.h" +#include "ctap2_utils.h" #include "cbip_encode.h" #include "config.h" #include "globals.h" @@ -97,5 +98,5 @@ void ctap2_get_info_handle(u2f_service_t *service, uint8_t *buffer, uint16_t len cbip_add_int(&encoder, PIN_PROTOCOL_VERSION_V1); responseBuffer[0] = ERROR_NONE; - send_cbor_response(service, 1 + encoder.offset); + send_cbor_response(service, 1 + encoder.offset, NULL); } diff --git a/src/ctap2/make_credential/make_credential.c b/src/ctap2/make_credential/make_credential.c index c0a61acf..184981d1 100644 --- a/src/ctap2/make_credential/make_credential.c +++ b/src/ctap2/make_credential/make_credential.c @@ -17,6 +17,7 @@ ********************************************************************************/ #include +#include #include "ctap2.h" #include "cbip_helper.h" @@ -398,6 +399,20 @@ static int process_makeCred_authnr_pin(cbipDecoder_t *decoder, cbipItem_t *mapIt return 0; } +static void copy_register_info_on_buffers(void) { + ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data(); + + ctap2_display_copy_rp(ctap2RegisterData->rpId, ctap2RegisterData->rpIdLen); + + if (ctap2RegisterData->userStr) { + ctap2_display_copy_username(ctap2RegisterData->userStr, ctap2RegisterData->userStrLen); + } else { + uint8_t nameLength = MIN(ctap2RegisterData->userIdLen, (sizeof(g.buffer2_65) - 1) / 2); + format_hex(ctap2RegisterData->userId, nameLength, g.buffer2_65, sizeof(g.buffer2_65)); + } + PRINTF("After copy, buffer content:\n1 - '%s'\n2 - '%s'\n", g.buffer1_65, g.buffer2_65); +} + void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint16_t length) { ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data(); cbipDecoder_t decoder; @@ -437,7 +452,7 @@ void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint1 } // RP & user decoded, we can store them into display buffer for future usage - ctap2_copy_info_on_buffers(); + copy_register_info_on_buffers(); // Handle cryptographic algorithms status = process_makeCred_authnr_keyCredParams(&decoder, &mapItem); diff --git a/src/ctap2/make_credential/make_credential_struct.h b/src/ctap2/make_credential/make_credential_struct.h new file mode 100644 index 00000000..40a6d2d9 --- /dev/null +++ b/src/ctap2/make_credential/make_credential_struct.h @@ -0,0 +1,40 @@ +/* +******************************************************************************* +* Ledger App Security Key +* (c) 2024 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#pragma once + +#include + +typedef struct ctap2_register_data_s { + uint8_t rpIdHash[CX_SHA256_SIZE]; + uint8_t *buffer; // pointer to the CBOR message in the APDU buffer + char *rpId; + uint32_t rpIdLen; + uint8_t *clientDataHash; + uint8_t *userId; + uint32_t userIdLen; + char *userStr; + uint32_t userStrLen; + int coseAlgorithm; // algorithm chosen following the request message + uint8_t pinRequired; // set if uv is set + uint8_t pinPresented; // set if the PIN request was acknowledged by the user + uint8_t + clientPinAuthenticated; // set if a standard FIDO client PIN authentication was performed + uint8_t residentKey; // set if the credential shall be created as a resident key + uint8_t extensions; // extensions flags as a bitmask +} ctap2_register_data_t; diff --git a/src/ctap2/make_credential/make_credential_utils.c b/src/ctap2/make_credential/make_credential_utils.c index cdf0a717..636d5e1c 100644 --- a/src/ctap2/make_credential/make_credential_utils.c +++ b/src/ctap2/make_credential/make_credential_utils.c @@ -25,6 +25,8 @@ #include "crypto_data.h" #include "globals.h" #include "rk_storage.h" +#include "ctap2_utils.h" +#include "ctap2.h" #include "make_credential_utils.h" @@ -318,7 +320,7 @@ void ctap2_make_credential_confirm() { exit: if (status == 0) { - send_cbor_response(&G_io_u2f, 1 + dataLen); + send_cbor_response(&G_io_u2f, 1 + dataLen, "Registration details\nsent"); } else { send_cbor_error(&G_io_u2f, status); } diff --git a/src/ctap2/make_credential/make_credential_utils.h b/src/ctap2/make_credential/make_credential_utils.h index 96f902c1..b8f38329 100644 --- a/src/ctap2/make_credential/make_credential_utils.h +++ b/src/ctap2/make_credential/make_credential_utils.h @@ -18,6 +18,8 @@ #pragma once +#include "make_credential_struct.h" + #define TAG_ALGORITHM "alg" #define TAG_SIGNATURE "sig" #define TAG_CERTIFICATE_X509 "x5c" @@ -27,3 +29,7 @@ void ctap2_make_credential_user_cancel(void); #ifdef HAVE_NFC void check_and_generate_new_pubkey(void); #endif + +static inline ctap2_register_data_t *globals_get_ctap2_register_data(void) { + return &shared_ctx.u.ctap2Data.u.ctap2RegisterData; +} diff --git a/src/ctap2/processing.c b/src/ctap2/processing.c index 1c4f9583..cddbad6a 100644 --- a/src/ctap2/processing.c +++ b/src/ctap2/processing.c @@ -23,18 +23,14 @@ #include "u2f_processing.h" #include "io.h" -#include "ctap2.h" #include "cbip_helper.h" #include "globals.h" #include "fido_known_apps.h" #include "ui_shared.h" #include "sw_code.h" #include "nfc_io.h" - -static uint8_t cmdType; - -#define RPID_FILTER "webctap." -#define RPID_FILTER_SIZE (sizeof(RPID_FILTER) - 1) +#include "ctap2_utils.h" +#include "ctap2.h" #define CBOR_MAKE_CREDENTIAL 0x01 #define CBOR_GET_ASSERTION 0x02 @@ -43,51 +39,6 @@ static uint8_t cmdType; #define CBOR_CLIENT_PIN 0x06 #define CBOR_RESET 0x07 -bool ctap2_check_rpid_filter(const char *rpId, uint32_t rpIdLen) { - if ((rpIdLen < RPID_FILTER_SIZE) || (memcmp(rpId, RPID_FILTER, RPID_FILTER_SIZE) != 0)) { - return true; - } else { - return false; - } -} - -void send_cbor_error(u2f_service_t *service, uint8_t error) { - if (CMD_IS_OVER_U2F_CMD) { - io_send_response_pointer((uint8_t *) &error, 1, SW_NO_ERROR); - } else { - u2f_message_reply(service, CTAP2_CMD_CBOR, (uint8_t *) &error, 1); - } -} - -void send_cbor_response(u2f_service_t *service, uint32_t length) { - if (CMD_IS_OVER_U2F_NFC) { - const char *status = NULL; - if (cmdType == CBOR_MAKE_CREDENTIAL) { - status = "Registration details\nsent"; - } else if (cmdType == CBOR_GET_ASSERTION) { - status = "Login request signed"; - } - nfc_io_set_response_ready(SW_NO_ERROR, length, status); - nfc_io_send_prepared_response(); - } else if (CMD_IS_OVER_U2F_CMD) { - io_send_response_pointer(responseBuffer, length, SW_NO_ERROR); - } else { - u2f_message_reply(service, CTAP2_CMD_CBOR, responseBuffer, length); - } -} - -void ctap2_send_keepalive_processing() { - if (CMD_IS_OVER_CTAP2_CBOR_CMD) { - u2f_transport_ctap2_send_keepalive(&G_io_u2f, KEEPALIVE_REASON_PROCESSING); - io_seproxyhal_io_heartbeat(); - } -} - -void performBuiltInUv(void) { - PRINTF("performBuiltInUv\n"); - // No-op as the user is verified through the session PIN. -} - void ctap2_handle_cmd_cbor(u2f_service_t *service, uint8_t *buffer, uint16_t length) { int status; // PRINTF("cmd_cbor %d %.*H\n", length, length, buffer); @@ -108,7 +59,6 @@ void ctap2_handle_cmd_cbor(u2f_service_t *service, uint8_t *buffer, uint16_t len send_cbor_error(service, ERROR_INVALID_CBOR); return; } - cmdType = buffer[0]; switch (buffer[0]) { case CBOR_MAKE_CREDENTIAL: diff --git a/src/ctap2/reset/reset.c b/src/ctap2/reset/reset.c index 8ce32fd5..1667d272 100644 --- a/src/ctap2/reset/reset.c +++ b/src/ctap2/reset/reset.c @@ -16,10 +16,11 @@ * limitations under the License. ********************************************************************************/ -#include "os.h" +#include #include "ctap2.h" #include "ui_shared.h" +#include "globals.h" #include "reset_utils.h" #include "reset_ui.h" diff --git a/src/ctap2/reset/reset_utils.c b/src/ctap2/reset/reset_utils.c index 2bf71ecc..f3c3c3cc 100644 --- a/src/ctap2/reset/reset_utils.c +++ b/src/ctap2/reset/reset_utils.c @@ -16,14 +16,17 @@ * limitations under the License. ********************************************************************************/ +#include + #include "config.h" #include "globals.h" +#include "ctap2_utils.h" void ctap2_reset_confirm() { config_process_ctap2_reset(); responseBuffer[0] = ERROR_NONE; - send_cbor_response(&G_io_u2f, 1); + send_cbor_response(&G_io_u2f, 1, NULL); } void ctap2_reset_cancel() { diff --git a/src/globals.c b/src/globals.c index 7b2e62d5..cab1bbad 100644 --- a/src/globals.c +++ b/src/globals.c @@ -51,27 +51,14 @@ static void copy_name_in_buffer65(char *buffer, const char *name, uint8_t nameLe } } -static void ctap2_display_copy_username(const char *name, uint8_t nameLength) { +void ctap2_display_copy_username(const char *name, uint8_t nameLength) { copy_name_in_buffer65(g.buffer2_65, name, nameLength); } -static void ctap2_display_copy_rp(const char *name, uint8_t nameLength) { +void ctap2_display_copy_rp(const char *name, uint8_t nameLength) { copy_name_in_buffer65(g.buffer1_65, name, nameLength); } -void ctap2_copy_info_on_buffers(void) { - ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data(); - - ctap2_display_copy_rp(ctap2RegisterData->rpId, ctap2RegisterData->rpIdLen); - - if (ctap2RegisterData->userStr) { - ctap2_display_copy_username(ctap2RegisterData->userStr, ctap2RegisterData->userStrLen); - } else { - uint8_t nameLength = MIN(ctap2RegisterData->userIdLen, (sizeof(g.buffer2_65) - 1) / 2); - format_hex(ctap2RegisterData->userId, nameLength, g.buffer2_65, sizeof(g.buffer2_65)); - } -} - void truncate_pairs_for_display(bool large) { /* truncate_for_nb_lines(g.buffer_20, large); */ /* PRINTF("buffer_20 after truncation: '%s'\n", g.buffer_20); */ diff --git a/src/u2f_processing.c b/src/u2f_processing.c index ed4964b7..0db6b6e7 100644 --- a/src/u2f_processing.c +++ b/src/u2f_processing.c @@ -408,7 +408,7 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) { return nfc_io_send_prepared_response(); default: - PRINTF("unsupported\n"); + PRINTF("FIDO default unsupported\n"); return io_send_sw(SW_INS_NOT_SUPPORTED); } } else if (CMD_IS_OVER_U2F_NFC && (rx[OFFSET_CLA] == FIDO2_NFC_CLA)) { @@ -422,14 +422,14 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) { return nfc_io_send_prepared_response(); case FIDO2_NFC_INS_APPLET_DESELECT: - PRINTF("unsupported\n"); + PRINTF("NFC APPLET unsupported\n"); return io_send_sw(SW_INS_NOT_SUPPORTED); case 0xc0: return nfc_io_send_prepared_response(); default: - PRINTF("unsupported\n"); + PRINTF("NFC default unsupported\n"); return io_send_sw(SW_INS_NOT_SUPPORTED); } } else if (CMD_IS_OVER_U2F_NFC && (rx[OFFSET_CLA] == FIDO2_NFC_CHAINING_CLA)) { @@ -441,7 +441,7 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) { return io_send_sw(0x9000); default: - PRINTF("unsupported\n"); + PRINTF("Default unsupported\n"); return io_send_sw(SW_INS_NOT_SUPPORTED); } } else { diff --git a/tests/unit-tests/Makefile b/tests/unit-tests/Makefile index 0f9d0a09..678b91c8 100644 --- a/tests/unit-tests/Makefile +++ b/tests/unit-tests/Makefile @@ -4,7 +4,7 @@ RM ?= rm -f CFLAGS ?= -O2 -Wall -Wextra -Wformat=2 -Wp,-MT,$@ -Wp,-MD,$(dir $@).$(notdir $@).d -fstack-protector CFLAGS += -DPRINTF=printf CFLAGS += -DUNIT_TESTS -CFLAGS += -I. -I../../include -I../../cbor-src +CFLAGS += -I. -I../../include -I../../cbor-src -I../../src/ctap2/ LDFLAGS ?= -Wl,-O1,-as-needed,-no-undefined,-z,relro,-z,now,--fatal-warnings -fstack-protector