From b4dbb7635c8b931dd47c2b0f48cc9e8bb1e8c461 Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Mon, 15 Apr 2024 17:32:58 +0200 Subject: [PATCH] src: Add support for NFC over U2F and FIDO2 Tested with Android on Pixel 5 and iOS. Some todo remains. --- Makefile | 3 + include/ctap2.h | 14 +- include/nfc_io.h | 44 ++++ include/u2f_process.h | 6 +- src/app_main.c | 4 + src/ctap2_get_assertion.c | 14 +- src/ctap2_make_credential.c | 102 +++++++- src/ctap2_processing.c | 39 ++- src/ctap2_reset.c | 6 + src/nfc_io.c | 91 +++++++ src/u2f_processing.c | 181 ++++++++++++- src/ui_shared.c | 12 +- tests/nfc_test_u2f.py | 238 ++++++++++++++++++ .../stax/test_fido_screens_settings/00000.png | Bin 12565 -> 9571 bytes .../stax/test_fido_screens_settings/00007.png | Bin 12565 -> 9571 bytes .../stax/test_u2f_screens_idle/00000.png | Bin 12565 -> 9571 bytes .../stax/test_u2f_screens_idle/00003.png | Bin 12565 -> 9571 bytes tests/speculos/u2f/test_cmd.py | 57 +++-- 18 files changed, 757 insertions(+), 54 deletions(-) create mode 100644 include/nfc_io.h create mode 100644 src/nfc_io.c create mode 100755 tests/nfc_test_u2f.py diff --git a/Makefile b/Makefile index 57a79db3..9a7c2254 100644 --- a/Makefile +++ b/Makefile @@ -146,6 +146,9 @@ DEFINES += HAVE_DEBUG_THROWS #DEFINES += HAVE_CBOR_DEBUG + +ENABLE_NFC = 1 + ############## # Compiler # ############## diff --git a/include/ctap2.h b/include/ctap2.h index b79db1f8..cd8b5507 100644 --- a/include/ctap2.h +++ b/include/ctap2.h @@ -103,6 +103,15 @@ #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 { @@ -177,7 +186,10 @@ void ctap2_send_keepalive_processing(void); // Correspond to FIDO2.1 spec performBuiltInUv() operation void performBuiltInUv(void); -void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint16_t length); +void ctap2_make_credential_handle(u2f_service_t *service, + uint8_t *buffer, + uint16_t length, + bool *immediateReply); void ctap2_get_assertion_handle(u2f_service_t *service, uint8_t *buffer, uint16_t length, diff --git a/include/nfc_io.h b/include/nfc_io.h new file mode 100644 index 00000000..6000ef38 --- /dev/null +++ b/include/nfc_io.h @@ -0,0 +1,44 @@ +/* +******************************************************************************* +* 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. +********************************************************************************/ + +#ifdef HAVE_NFC +void nfc_io_set_le(uint32_t le); +void nfc_io_set_response_ready(uint16_t sw, uint16_t len, const char *status); +bool nfc_io_is_response_pending(void); +int nfc_io_send_prepared_response(void); + +#else +static inline void nfc_io_set_le(uint32_t le __attribute__((unused))) { + return; +} + +static inline void nfc_io_set_response_ready(uint16_t sw, uint16_t len, const char *status) { + UNUSED(sw); + UNUSED(len); + UNUSED(status); + return; +} + +static inline bool nfc_io_is_response_pending(void) { + return false; +} + +static inline int nfc_io_send_prepared_response(void) { + return -1; +} +#endif diff --git a/include/u2f_process.h b/include/u2f_process.h index 40d1def5..25c854e8 100644 --- a/include/u2f_process.h +++ b/include/u2f_process.h @@ -30,4 +30,8 @@ typedef struct u2f_data_t { int u2f_handle_apdu(uint8_t *rx, int length); -#endif +#ifdef HAVE_NFC +void nfc_idle_work(void); +#endif // HAVE_NFC + +#endif // __U2F_PROCESS_H__ diff --git a/src/app_main.c b/src/app_main.c index fb28ed96..65dc7c3d 100644 --- a/src/app_main.c +++ b/src/app_main.c @@ -35,6 +35,10 @@ void app_ticker_event_callback(void) { if (ctap2UxState != CTAP2_UX_STATE_NONE) { u2f_transport_ctap2_send_keepalive(&G_io_u2f, KEEPALIVE_REASON_TUP_NEEDED); } +#ifdef HAVE_NFC + nfc_idle_work(); + nfc_idle_work2(); +#endif } /** diff --git a/src/ctap2_get_assertion.c b/src/ctap2_get_assertion.c index 9ba999d8..925d9de0 100644 --- a/src/ctap2_get_assertion.c +++ b/src/ctap2_get_assertion.c @@ -57,7 +57,7 @@ static int parse_getAssert_authnr_rpid(cbipDecoder_t *decoder, cbipItem_t *mapIt } #ifdef HAVE_FIDO2_RPID_FILTER - if (CMD_IS_OVER_U2F_CMD) { + if (CMD_IS_OVER_U2F_CMD && !CMD_IS_OVER_U2F_NFC) { if (ctap2_check_rpid_filter(ctap2AssertData->rpId, ctap2AssertData->rpIdLen)) { PRINTF("rpId denied by filter\n"); return ERROR_PROP_RPID_MEDIA_DENIED; @@ -380,7 +380,17 @@ void ctap2_get_assertion_handle(u2f_service_t *service, goto exit; } - if (!ctap2AssertData->userPresenceRequired && !ctap2AssertData->pinRequired) { + if (CMD_IS_OVER_U2F_NFC) { + // No up nor uv requested, skip UX and reply immediately + // TODO: is this what we want? + // TODO: Handle cases where availableCredentials is != 1 + // -> which credentials should be chosen? + // -> when credentials comes from allowListPresent, I think the spec allow to choose for + // the user + // -> when credentials comes from rk, the spec ask to use authenticatorGetNextAssertion + // features + *immediateReply = true; + } else if (!ctap2AssertData->userPresenceRequired && !ctap2AssertData->pinRequired) { // No up nor uv required, skip UX and reply immediately *immediateReply = true; } else { diff --git a/src/ctap2_make_credential.c b/src/ctap2_make_credential.c index d4e329ac..49a065fc 100644 --- a/src/ctap2_make_credential.c +++ b/src/ctap2_make_credential.c @@ -93,7 +93,7 @@ static int parse_makeCred_authnr_rp(cbipDecoder_t *decoder, cbipItem_t *mapItem) } #ifdef HAVE_FIDO2_RPID_FILTER - if (CMD_IS_OVER_U2F_CMD) { + if (CMD_IS_OVER_U2F_CMD && !CMD_IS_OVER_U2F_NFC) { if (ctap2_check_rpid_filter(ctap2RegisterData->rpId, ctap2RegisterData->rpIdLen)) { PRINTF("rpId denied by filter\n"); return ERROR_PROP_RPID_MEDIA_DENIED; @@ -409,7 +409,10 @@ static int process_makeCred_authnr_pin(cbipDecoder_t *decoder, cbipItem_t *mapIt return 0; } -void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint16_t length) { +void ctap2_make_credential_handle(u2f_service_t *service, + uint8_t *buffer, + uint16_t length, + bool *immediateReply) { ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data(); cbipDecoder_t decoder; cbipItem_t mapItem; @@ -417,6 +420,7 @@ void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint1 PRINTF("ctap2_make_credential_handle\n"); + *immediateReply = false; memset(ctap2RegisterData, 0, sizeof(ctap2_register_data_t)); ctap2RegisterData->buffer = buffer; @@ -482,7 +486,13 @@ void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint1 goto exit; } - ctap2_make_credential_ux(); + if (CMD_IS_OVER_U2F_NFC) { + // No up nor uv requested, skip UX and reply immediately + // TODO: is this what we want? + *immediateReply = true; + } else { + ctap2_make_credential_ux(); + } exit: if (status != 0) { @@ -492,23 +502,83 @@ void ctap2_make_credential_handle(u2f_service_t *service, uint8_t *buffer, uint1 return; } +static int generate_pubkey(const uint8_t *nonce, int coseAlgorithm, cx_ecfp_public_key_t *pubkey) { + cx_ecfp_private_key_t privateKey; + cx_curve_t bolosCurve = cose_alg_to_cx(coseAlgorithm); + + if (crypto_generate_private_key(nonce, &privateKey, bolosCurve) != 0) { + return -1; + } + if (cx_ecfp_generate_pair_no_throw(bolosCurve, pubkey, &privateKey, 1) != CX_OK) { + return -1; + } + + return 0; +} + +#ifdef HAVE_NFC +static bool nfc_nonce_and_pubkey_ready; +static uint8_t nfc_nonce[CREDENTIAL_NONCE_SIZE]; +static cx_ecfp_public_key_t nfc_pubkey_ES256; +static cx_ecfp_public_key_t nfc_pubkey_ES256K; +static cx_ecfp_public_key_t nfc_pubkey_EDDSA; + +void nfc_idle_work2(void) { + // Generate a new nonce/pubkey pair only if not already available and in idle + if (nfc_nonce_and_pubkey_ready) { + return; + } + + cx_rng_no_throw(nfc_nonce, CREDENTIAL_NONCE_SIZE); + + if (generate_pubkey(nfc_nonce, COSE_ALG_ES256, &nfc_pubkey_ES256) != 0) { + return; + } + + if (generate_pubkey(nfc_nonce, COSE_ALG_ES256K, &nfc_pubkey_ES256K) != 0) { + return; + } + + if (generate_pubkey(nfc_nonce, COSE_ALG_EDDSA, &nfc_pubkey_EDDSA) != 0) { + return; + } + + nfc_nonce_and_pubkey_ready = true; +} +#endif + static int encode_makeCred_public_key(const uint8_t *nonce, int coseAlgorithm, uint8_t *buffer, uint32_t bufferLength) { cbipEncoder_t encoder; - cx_ecfp_private_key_t privateKey; cx_ecfp_public_key_t publicKey; - cx_curve_t bolosCurve; int status; - bolosCurve = cose_alg_to_cx(coseAlgorithm); +#ifdef HAVE_NFC + // Spare response time by pre-generating part of the answer + if (nfc_nonce_and_pubkey_ready) { + switch (coseAlgorithm) { + case COSE_ALG_ES256: + memcpy(&publicKey, &nfc_pubkey_ES256, sizeof(publicKey)); + break; + case COSE_ALG_ES256K: + memcpy(&publicKey, &nfc_pubkey_ES256K, sizeof(publicKey)); + break; + case COSE_ALG_EDDSA: + memcpy(&publicKey, &nfc_pubkey_EDDSA, sizeof(publicKey)); + break; + default: + return -1; + } - if (crypto_generate_private_key(nonce, &privateKey, bolosCurve) != 0) { - return -1; - } - if (cx_ecfp_generate_pair_no_throw(bolosCurve, &publicKey, &privateKey, 1) != CX_OK) { - return -1; + nfc_nonce_and_pubkey_ready = false; + } else +#endif + { + if (generate_pubkey(nonce, coseAlgorithm, &publicKey) != 0) { + return -1; + } } cbip_encoder_init(&encoder, buffer, bufferLength); @@ -672,7 +742,15 @@ void ctap2_make_credential_confirm() { ctap2_send_keepalive_processing(); // Generate nonce - cx_rng_no_throw(nonce, CREDENTIAL_NONCE_SIZE); +#ifdef HAVE_NFC + // Spare response time by pre-generating part of the answer + if (nfc_nonce_and_pubkey_ready) { + memcpy(nonce, nfc_nonce, CREDENTIAL_NONCE_SIZE); + } else +#endif + { + cx_rng_no_throw(nonce, CREDENTIAL_NONCE_SIZE); + } // Build auth data status = diff --git a/src/ctap2_processing.c b/src/ctap2_processing.c index 9dbb3568..c680299b 100644 --- a/src/ctap2_processing.c +++ b/src/ctap2_processing.c @@ -29,10 +29,20 @@ #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) +#define CBOR_MAKE_CREDENTIAL 0x01 +#define CBOR_GET_ASSERTION 0x02 +#define CBOR_GET_NEXT_ASSERTION 0x08 +#define CBOR_GET_INFO 0x04 +#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; @@ -50,7 +60,16 @@ void send_cbor_error(u2f_service_t *service, uint8_t error) { } void send_cbor_response(u2f_service_t *service, uint32_t length) { - if (CMD_IS_OVER_U2F_CMD) { + 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); @@ -69,13 +88,6 @@ void performBuiltInUv(void) { // No-op as the user is verified through the session PIN. } -#define CBOR_MAKE_CREDENTIAL 0x01 -#define CBOR_GET_ASSERTION 0x02 -#define CBOR_GET_NEXT_ASSERTION 0x08 -#define CBOR_GET_INFO 0x04 -#define CBOR_CLIENT_PIN 0x06 -#define CBOR_RESET 0x07 - 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); @@ -96,11 +108,16 @@ 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: - ctap2_make_credential_handle(service, buffer + 1, length - 1); - break; + case CBOR_MAKE_CREDENTIAL: { + bool immediateReply; + ctap2_make_credential_handle(service, buffer + 1, length - 1, &immediateReply); + if (immediateReply) { + ctap2_make_credential_confirm(); + } + } break; case CBOR_GET_ASSERTION: { bool immediateReply; ctap2_get_assertion_handle(service, buffer + 1, length - 1, &immediateReply); diff --git a/src/ctap2_reset.c b/src/ctap2_reset.c index 283722ed..dc20100e 100644 --- a/src/ctap2_reset.c +++ b/src/ctap2_reset.c @@ -28,6 +28,12 @@ void ctap2_reset_handle(u2f_service_t *service, uint8_t *buffer, uint16_t length UNUSED(buffer); UNUSED(length); + if (CMD_IS_OVER_U2F_NFC) { + // Denied authenticatorReset over NFC as it can't be approved by the user. + // Note, this is a behavior allowed by the FIDO spec. + send_cbor_error(&G_io_u2f, ERROR_OPERATION_DENIED); + } + PRINTF("ctap2_reset_handle\n"); ctap2_reset_ux(); } diff --git a/src/nfc_io.c b/src/nfc_io.c new file mode 100644 index 00000000..e45df41d --- /dev/null +++ b/src/nfc_io.c @@ -0,0 +1,91 @@ +/* +******************************************************************************* +* 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. +********************************************************************************/ + +#ifdef HAVE_NFC +#include +#include + +#include "os_math.h" +#include "io.h" +#include "sw_code.h" +#include "globals.h" +#include "nfc_io.h" +#include "ui_shared.h" + +static bool nfc_data_ready; +static uint16_t nfc_sw; +static uint16_t nfc_buffer_len; +static uint16_t nfc_buffer_offset; +static uint32_t nfc_le; +static const char *nfc_status; + +void nfc_io_set_le(uint32_t le) { + nfc_le = le; +} + +void nfc_io_set_response_ready(uint16_t sw, uint16_t len, const char *status) { + nfc_sw = sw; + nfc_buffer_len = len; + nfc_status = status; + nfc_buffer_offset = 0; + nfc_data_ready = true; +} + +bool nfc_io_is_response_pending(void) { + return nfc_data_ready; +} + +int nfc_io_send_prepared_response(void) { + if (!nfc_data_ready) { + return io_send_sw(SW_WRONG_DATA); + } + + if (nfc_sw != SW_NO_ERROR) { + nfc_data_ready = false; + return io_send_sw(nfc_sw); + } + + if (nfc_buffer_offset >= nfc_buffer_len) { + nfc_data_ready = false; + return io_send_sw(SW_WRONG_DATA); + } + + uint16_t size = MIN(nfc_le, nfc_buffer_len - nfc_buffer_offset); + uint16_t start = nfc_buffer_offset; + + nfc_buffer_offset += size; + + uint16_t sw; + if ((nfc_buffer_len - nfc_buffer_offset) >= 256) { + sw = SW_MORE_DATA; + } else if (nfc_buffer_len == nfc_buffer_offset) { + nfc_data_ready = false; + sw = SW_NO_ERROR; + } else { + sw = SW_MORE_DATA + (nfc_buffer_len - nfc_buffer_offset); + } + + int ret = io_send_response_pointer(responseBuffer + start, size, sw); + if (sw == SW_NO_ERROR && nfc_status != NULL) { + app_nbgl_status(nfc_status, true, ui_idle, TUNE_SUCCESS); + } + + return ret; +} + +#endif diff --git a/src/u2f_processing.c b/src/u2f_processing.c index bac82690..b7c1033c 100644 --- a/src/u2f_processing.c +++ b/src/u2f_processing.c @@ -39,21 +39,34 @@ #include "globals.h" #include "fido_known_apps.h" #include "ctap2.h" +#include "nfc_io.h" #include "sw_code.h" #define U2F_VERSION "U2F_V2" #define U2F_VERSION_SIZE (sizeof(U2F_VERSION) - 1) +#define FIDO2_VERSION "FIDO_2_0" +#define FIDO2_VERSION_SIZE (sizeof(FIDO2_VERSION) - 1) + +#define FIDO_AID_SIZE 8 +static const uint8_t FIDO_AID[FIDO_AID_SIZE] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; + #define OFFSET_CLA 0 #define OFFSET_INS 1 #define OFFSET_P1 2 #define OFFSET_P2 3 -#define FIDO_CLA 0x00 -#define FIDO_INS_ENROLL 0x01 -#define FIDO_INS_SIGN 0x02 -#define FIDO_INS_GET_VERSION 0x03 -#define FIDO_INS_CTAP2_PROXY 0x10 +#define FIDO_CLA 0x00 +#define FIDO_INS_ENROLL 0x01 +#define FIDO_INS_SIGN 0x02 +#define FIDO_INS_GET_VERSION 0x03 +#define FIDO_INS_CTAP2_PROXY 0x10 +#define FIDO_INS_APPLET_SELECT 0xA4 + +#define FIDO2_NFC_CLA 0x80 +#define FIDO2_NFC_CHAINING_CLA 0x90 +#define FIDO2_NFC_INS_CTAP2_PROXY 0x10 +#define FIDO2_NFC_INS_APPLET_DESELECT 0x12 #define P1_U2F_CHECK_IS_REGISTERED 0x07 #define P1_U2F_REQUEST_USER_PRESENCE 0x03 @@ -75,7 +88,11 @@ static const uint8_t DUMMY_USER_PRESENCE[] = {SIGN_USER_PRESENCE_MASK}; #define SHORT_ENC_DATA_OFFSET 5 #define EXT_ENC_DATA_OFFSET 7 -int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16_t *le) { +#define SHORT_ENC_DEFAULT_LE \ + 253 // Should be 256, stax-rc4 MCU only support 255, so use 253 + 2 for now here +#define EXT_ENC_DEFAULT_LE 65536 + +static int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint32_t *le) { uint32_t data_length; /* Parse buffer to retrieve the data length. Both Short and Extended encodings are supported */ @@ -88,7 +105,8 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 } if (rx_length == APDU_MIN_HEADER) { - // Either short or extended encoding with Lc and Le omitted + // Short encoding with Lc and Le omitted + *le = SHORT_ENC_DEFAULT_LE; return 0; } @@ -104,6 +122,9 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 *le = rx[APDU_MIN_HEADER]; } + if (*le == 0) { + *le = SHORT_ENC_DEFAULT_LE; + } return 0; } @@ -118,6 +139,11 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 } else { return -1; } + + if (*le == 0) { + *le = SHORT_ENC_DEFAULT_LE; + } + return data_length; } if (rx_length == APDU_MIN_HEADER + 3) { @@ -137,6 +163,10 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 } else { return -1; } + + if (*le == 0) { + *le = SHORT_ENC_DEFAULT_LE; + } return data_length; } else { // Can't be short encoding as Lc = 0x00 would lead to invalid length @@ -145,6 +175,12 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 // - Lc omitted and Le = 0x00 0xyy 0xzz // so no way to check the value // but anyway the data length is 0 + *le = (rx[APDU_MIN_HEADER + 1] << 8) + rx[APDU_MIN_HEADER + 2]; + + if (*le == 0) { + *le = EXT_ENC_DEFAULT_LE; + } + return 0; } } @@ -163,6 +199,10 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 } else { return -1; } + + if (*le == 0) { + *le = SHORT_ENC_DEFAULT_LE; + } return data_length; } else { // Can't be short encoding as Lc = 0 would lead to invalid length @@ -176,10 +216,13 @@ int u2f_get_cmd_msg_data(uint8_t *rx, uint16_t rx_length, uint8_t **data, uint16 } else if (APDU_MIN_HEADER + EXT_ENC_LC_SIZE + data_length + EXT_ENC_LE_SIZE == rx_length) { /* Le is present*/ *le = (rx[EXT_ENC_DATA_OFFSET + data_length] << 8) + - rx[EXT_ENC_DATA_OFFSET + data_length]; + rx[EXT_ENC_DATA_OFFSET + data_length + 1]; } else { return -1; } + if (*le == 0) { + *le = EXT_ENC_DEFAULT_LE; + } return data_length; } } @@ -298,6 +341,26 @@ static int u2f_generate_pubkey(const uint8_t *nonce, return 0; } +#ifdef HAVE_NFC +static bool nfc_nonce_and_pubkey_ready; +static uint8_t nfc_nonce[CREDENTIAL_NONCE_SIZE]; +static uint8_t nfc_pubkey[U2F_ENROLL_USER_KEY_SIZE]; + +void nfc_idle_work(void) { + // Generate a new nonce/pubkey pair only if not already available and in idle + if (nfc_nonce_and_pubkey_ready || nfc_io_is_response_pending()) { + return; + } + + cx_rng_no_throw(nfc_nonce, CREDENTIAL_NONCE_SIZE); + if (u2f_generate_pubkey(nfc_nonce, nfc_pubkey) != 0) { + return; + } + + nfc_nonce_and_pubkey_ready = true; +} +#endif + static uint16_t u2f_prepare_enroll_response(uint8_t *buffer, uint16_t *length) { int offset = 0; int result; @@ -311,6 +374,14 @@ static uint16_t u2f_prepare_enroll_response(uint8_t *buffer, uint16_t *length) { // Fill reserved byte reg_resp_base->reserved_byte = U2F_ENROLL_RESERVED; +#ifdef HAVE_NFC + // Spare response time by pre-generating part of the answer + if (nfc_nonce_and_pubkey_ready) { + memcpy(globals_get_u2f_data()->nonce, nfc_nonce, CREDENTIAL_NONCE_SIZE); + memcpy(reg_resp_base->user_key, nfc_pubkey, U2F_ENROLL_USER_KEY_SIZE); + nfc_nonce_and_pubkey_ready = false; + } else +#endif { // Generate nonce cx_rng_no_throw(globals_get_u2f_data()->nonce, CREDENTIAL_NONCE_SIZE); @@ -617,7 +688,14 @@ static int u2f_handle_apdu_enroll(const uint8_t *rx, uint32_t data_length, const reg_req->application_param, sizeof(reg_req->application_param)); - if (G_io_u2f.media == U2F_MEDIA_USB) { + if (CMD_IS_OVER_U2F_NFC) { + uint16_t length = 0; + uint16_t sw = u2f_prepare_enroll_response(responseBuffer, &length); + + nfc_io_set_response_ready(sw, length, "Registration details\nsent"); + + return nfc_io_send_prepared_response(); + } else if (CMD_IS_OVER_U2F_USB) { u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, true); } u2f_prompt_user_presence(true, globals_get_u2f_data()->application_param); @@ -682,11 +760,30 @@ static int u2f_handle_apdu_sign(const uint8_t *rx, uint32_t data_length, uint8_t auth_req_base->application_param, sizeof(auth_req_base->application_param)); - if (G_io_u2f.media == U2F_MEDIA_USB) { + // clang-format off + // following macros + `else if` was messing with clang until the `return` +#ifdef HAVE_NFC + if (CMD_IS_OVER_U2F_NFC) { + // Android doesn't support answering SW_MORE_DATA here... + // so compute the real answer as fast as possible + uint16_t length = 0; + uint16_t sw = u2f_prepare_sign_response(responseBuffer, &length); + + // Message fit in a single response, answer directly without nfc_io features + io_send_response_pointer(responseBuffer, length, sw); + + app_nbgl_status("Login request signed", true, ui_idle, TUNE_SUCCESS); + return 0; + } else +#endif // HAVE_NFC + if (CMD_IS_OVER_U2F_USB) { u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, true); } + u2f_prompt_user_presence(false, globals_get_u2f_data()->application_param); return 0; + + // clang-format on } static int u2f_handle_apdu_get_version(const uint8_t *rx, @@ -713,9 +810,23 @@ static int u2f_handle_apdu_ctap2_proxy(uint8_t *rx, int data_length, uint8_t *da return 0; } +static int u2f_handle_apdu_applet_select(uint8_t *rx, int data_length, const uint8_t *data) { + if ((rx[OFFSET_P1] != 0x04) || (rx[OFFSET_P2] != 0)) { + return io_send_sw(SW_INCORRECT_P1P2); + } + + if ((data_length != FIDO_AID_SIZE) || (memcmp(data, FIDO_AID, FIDO_AID_SIZE) != 0)) { + return io_send_sw(SW_WRONG_DATA); + } + + return io_send_response_pointer((const uint8_t *) U2F_VERSION, U2F_VERSION_SIZE, SW_NO_ERROR); +} + int u2f_handle_apdu(uint8_t *rx, int rx_length) { + // PRINTF("=> RAW=%.*H\n", rx_length, rx); + uint8_t *data = NULL; - uint16_t le = 0; + uint32_t le = 0; // PRINTF("Media handleApdu %d\n", G_io_app.apdu_state); // Make sure cmd is detected as over U2F_CMD and not as CMD_IS_OVER_CTAP2_CBOR_CMD @@ -728,6 +839,10 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) { return io_send_sw(SW_WRONG_LENGTH); } + if (CMD_IS_OVER_U2F_NFC) { + nfc_io_set_le(le); + } + PRINTF("INS %d, P1 %d P2 %d L %d\n", rx[OFFSET_INS], rx[OFFSET_P1], rx[OFFSET_P2], data_length); if (rx[OFFSET_CLA] == FIDO_CLA) { @@ -748,6 +863,50 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) { PRINTF("ctap2_proxy\n"); return u2f_handle_apdu_ctap2_proxy(rx, data_length, data); + case FIDO_INS_APPLET_SELECT: + PRINTF("applet_select\n"); + // return io_send_sw(SW_INS_NOT_SUPPORTED); + return u2f_handle_apdu_applet_select(rx, data_length, data); + + case 0xc0: + if (!CMD_IS_OVER_U2F_NFC) { + return io_send_sw(SW_INS_NOT_SUPPORTED); + } + return nfc_io_send_prepared_response(); + + default: + PRINTF("unsupported\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + } + } else if (CMD_IS_OVER_U2F_NFC && (rx[OFFSET_CLA] == FIDO2_NFC_CLA)) { + switch (rx[OFFSET_INS]) { + case FIDO2_NFC_INS_CTAP2_PROXY: + PRINTF("ctap2_proxy\n"); + return u2f_handle_apdu_ctap2_proxy(rx, data_length, data); + + case 0x11: + PRINTF("NFCCTAP_GETRESPONSE\n"); + return nfc_io_send_prepared_response(); + + case FIDO2_NFC_INS_APPLET_DESELECT: + PRINTF("unsupported\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + + case 0xc0: + return nfc_io_send_prepared_response(); + + default: + PRINTF("unsupported\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + } + } else if (CMD_IS_OVER_U2F_NFC && (rx[OFFSET_CLA] == FIDO2_NFC_CHAINING_CLA)) { + // TODO but as of now it's not used neither on: + // - iOS: using extended encoding + // - Android: using U2F only + switch (rx[OFFSET_INS]) { + case 0x60: + return io_send_sw(0x9000); + default: PRINTF("unsupported\n"); return io_send_sw(SW_INS_NOT_SUPPORTED); diff --git a/src/ui_shared.c b/src/ui_shared.c index 15a93165..e84862cd 100644 --- a/src/ui_shared.c +++ b/src/ui_shared.c @@ -269,9 +269,19 @@ static void ui_menu_settings_page(void) { } void ui_idle(void) { + const char *txt = "Use this app for two-factor\nauthentication and\npassword-less log ins."; +#ifdef HAVE_NFC + bool nfc_enabled; + + nfc_enabled = os_setting_get(OS_SETTING_FEATURES, NULL, 0) & OS_SETTING_FEATURES_NFC_ENABLED; + if (!nfc_enabled) { + txt = "\n\n/!\\ NFC is disabled /!\\"; + } +#endif + nbgl_useCaseHome(APPNAME, &C_icon_security_key_64px, - "Use this app for two-factor\nauthentication and\npassword-less log ins.", + txt, #ifdef HAVE_RK_SUPPORT_SETTING true, #else diff --git a/tests/nfc_test_u2f.py b/tests/nfc_test_u2f.py new file mode 100755 index 00000000..366571e8 --- /dev/null +++ b/tests/nfc_test_u2f.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 + +import nfc +from time import sleep +from datetime import datetime +from fido2 import cbor +from fido2.ctap2.base import Ctap2, Info, args, AttestationResponse, AssertionResponse +from fido2.ctap1 import Ctap1, RegistrationData, SignatureData +from fido2.webauthn import AttestedCredentialData +from fido2.cose import ES256 + +import struct +import secrets +import random +import string + + +FIDO_CLA = 0x00 +FIDO_AID = bytearray.fromhex("A0000006472F0001") + + +def generate_random_bytes(length): + return secrets.token_bytes(length) + + +def generate_random_string(length): + return "".join(random.choice(string.ascii_lowercase) for _ in range(length)) + + +def generate_make_credentials_params(): + rp_base = generate_random_string(20) + rp_id = "webctap.{}.com".format(rp_base) + user_id = generate_random_bytes(64) + user_name = "vgfjbdeskjgbrsbvgsb" + + client_data_hash = generate_random_bytes(32) + rp = {"id": rp_id} + user = {"id": user_id} + if user_name: + user["name"] = user_name + key_params = [{"type": "public-key", "alg": ES256.ALGORITHM}] + return client_data_hash, rp, user, key_params + + +class DongleNFC(): + def __init__(self, debug=False): + self.waitImpl = self + self.opened = True + self.debug = debug + self.clf = nfc.ContactlessFrontend('usb') + self.tag = self.clf.connect(rdwr={'on-connect': lambda tag: False}) + + def exchange(self, apdu): + if self.debug: + print(f"[NFC] => {apdu.hex()}") + response = self.tag.transceive(apdu, 5.0) + if self.debug: + print(f"[NFC] <= {response.hex()}") + return response + + def parse_u2f_response(self, response): + return response[-2:].hex(), response[:-2] + + def send_u2f_apdu(self, apdu): + t1 = datetime.now() + response = self.exchange(apdu) + t2 = datetime.now() + if self.debug: + print((t2 - t1).microseconds // 1000, "ms", len(response), "bytes") + return self.parse_u2f_response(response) + + def craft_apdu(self, cla, ins, p1=0, p2=0, data=None, le=0, short_encoding=True): + apdu = struct.pack(">BBBB", cla, ins, p1, p2) + if short_encoding: + if data: + lc = len(data) + assert lc < 256 + apdu += struct.pack(">B", lc) + apdu += data + apdu += struct.pack(">B", le) + else: + apdu += struct.pack(">B", 0) + if data: + lc = len(data) + apdu += struct.pack(">H", lc) + apdu += data + apdu += struct.pack(">H", le) + return apdu + + def send_u2f_cmd(self, cla, ins, p1=0, p2=0, data=None, le=0, short_encoding=True): + apdu = self.craft_apdu(cla, ins, p1, p2, data, le, short_encoding) + + sw, rx = self.send_u2f_apdu(apdu) + response = rx + if short_encoding: + while sw.startswith("61"): + apdu = self.craft_apdu(cla, 0xC0) + sw, rx = self.send_u2f_apdu(apdu) + response += rx + + return sw, response + + def parse_fido2_response(self, sw, response): + assert sw == "9000" + assert response[0] == 0 + + response = response[1:] + decoded = cbor.decode(response) + return decoded + + def send_fido2_cbor(self, cmd, data=None, short_encoding=True): + request = struct.pack(">B", cmd) + if data is not None: + request += cbor.encode(data) + + if short_encoding: + while request: + more = False + if len(request) > 255: + more = True + cla = 0x90 + else: + cla = 0x80 + + lc = min(255, len(request)) + data = request[:lc] + + request = request[lc:] + sw, rx = self.send_u2f_cmd(cla=cla, ins=0x10, data=data, short_encoding=True) + + if more: + assert sw == "9000" + assert not rx + else: + break + else: + sw, rx = self.send_u2f_cmd(cla=0x0, ins=0x10, data=request, short_encoding=False) + + return self.parse_fido2_response(sw, rx) + + def close(self): + self.clf.close() + + +def test_u2f(short_encoding): + challenge_param = generate_random_bytes(32) + app_param = generate_random_bytes(32) + + dongle = DongleNFC(True) + + # APPLET_SELECT + sw, resp = dongle.send_u2f_cmd(cla=FIDO_CLA, ins=0xA4, p1=0x04, data=FIDO_AID, short_encoding=short_encoding) + assert sw == "9000" + assert resp.decode() == "U2F_V2" + + # U2F_VERSION + sw, resp = dongle.send_u2f_cmd(cla=FIDO_CLA, ins=Ctap1.INS.VERSION, short_encoding=short_encoding) + assert sw == "9000" + assert resp.decode() == "U2F_V2" + + # U2F_REGISTER + data = challenge_param + app_param + sw, resp = dongle.send_u2f_cmd(cla=FIDO_CLA, ins=Ctap1.INS.REGISTER, data=data, short_encoding=short_encoding) + assert sw == "9000" + registration_data = RegistrationData(resp) + registration_data.verify(app_param, challenge_param) + + # U2F_AUTHENTICATE + challenge_param = generate_random_bytes(32) + data = challenge_param + app_param + data += struct.pack(">B", len(registration_data.key_handle)) + data += registration_data.key_handle + sw, resp = dongle.send_u2f_cmd(cla=FIDO_CLA, ins=Ctap1.INS.AUTHENTICATE, p1=3, data=data, short_encoding=short_encoding) + assert sw == "9000" + auth_data = SignatureData(resp) + auth_data.verify(app_param, challenge_param, registration_data.public_key) + + dongle.close() + + +def test_fido2(short_encoding): + + dongle = DongleNFC(True) + + # APPLET_SELECT + sw, resp = dongle.send_u2f_cmd(cla=FIDO_CLA, ins=0xA4, p1=0x04, data=FIDO_AID, short_encoding=short_encoding) + assert sw == "9000" + assert resp.decode() == "U2F_V2" + + # U2F_VERSION + sw, resp = dongle.send_u2f_cmd(cla=FIDO_CLA, ins=Ctap1.INS.VERSION, short_encoding=short_encoding) + assert sw == "9000" + assert resp.decode() == "U2F_V2" + + # GET INFO + decoded = dongle.send_fido2_cbor(Ctap2.CMD.GET_INFO, short_encoding=short_encoding) + Info.from_dict(decoded) + + client_data_hash, rp, user, key_params = generate_make_credentials_params() + + # MAKE_CREDENTIAL + data = args(client_data_hash, + rp, + user, + key_params, + None, + None, + None, + None, + None, + None) + decoded = dongle.send_fido2_cbor(Ctap2.CMD.MAKE_CREDENTIAL, data, short_encoding=short_encoding) + attestation = AttestationResponse.from_dict(decoded) + + # GET_ASSERTION + credential_data = AttestedCredentialData(attestation.auth_data.credential_data) + client_data_hash = generate_random_bytes(32) + allow_list = [ + {"id": credential_data.credential_id, "type": "public-key"}, + {"id": credential_data.credential_id, "type": "public-key"} # to increase the cmd size so that is above 255bytes + ] + data = args(rp["id"], + client_data_hash, + allow_list, + None, + None, + None, + None) + decoded = dongle.send_fido2_cbor(Ctap2.CMD.GET_ASSERTION, data, short_encoding=short_encoding) + assertion = AssertionResponse.from_dict(decoded) + + assertion.verify(client_data_hash, credential_data.public_key) + + +#test_u2f(True) +#test_u2f(False) +#test_fido2(True) +test_fido2(False) diff --git a/tests/speculos/snapshots/stax/test_fido_screens_settings/00000.png b/tests/speculos/snapshots/stax/test_fido_screens_settings/00000.png index 3b0c2b11cb4d7ca6fc15dcef5a615692b78b7f83..efc4f221583dc297b52e5dd3de9c9a3014780d10 100644 GIT binary patch literal 9571 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 d(qUI{* literal 12565 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 d(qUI{* literal 12565 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 d(qUI{* literal 12565 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 d(qUI{* literal 12565 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", cla, ins, p1, p2, 0, nc, ne) - client.ctap1.send_raw_apdu(apdu) + result = client.ctap1.send_raw_apdu(apdu) # Extended encoding, explicit Lc and no Le apdu = struct.pack(">BBBBBH", cla, ins, p1, p2, 0, nc) - client.ctap1.send_raw_apdu(apdu) + assert result == client.ctap1.send_raw_apdu(apdu) # Test errors @@ -95,23 +96,49 @@ def test_cmd_no_data_encoding(client): client.ctap1.send_raw_apdu(apdu) assert e.value.code == APDU.SW_WRONG_LENGTH + +@pytest.mark.skip_endpoint("u2f") +def test_cmd_no_data_extended_encoding_hid_only(client): + cla = 0x00 + ins = Ctap1.INS.VERSION + p1 = 0x00 + p2 = 0x00 + ne = 0xaabb # Can be quite anything + + # Extended encoding, no Lc and explicit Le + apdu = struct.pack(">BBBBBH", cla, ins, p1, p2, 0, ne) + result = client.ctap1.send_raw_apdu(apdu) + + # Extended encoding, no Lc and no Le + apdu = struct.pack(">BBBB", cla, ins, p1, p2) + assert result == client.ctap1.send_raw_apdu(apdu) + + +@pytest.mark.skip_endpoint("hid") +def test_cmd_no_data_short_encoding_u2f_only(client): + cla = 0x00 + ins = Ctap1.INS.VERSION + p1 = 0x00 + p2 = 0x00 + # Short encoding (not supported), Lc and Le apdu = struct.pack(">BBBBBB", cla, ins, p1, p2, 0, 0xaa) with pytest.raises(ApduError) as e: client.ctap1.send_raw_apdu(apdu) assert e.value.code == APDU.SW_WRONG_LENGTH - # Next tests only work over raw§HID until all sdk u2f_impl.c are updated - if client.use_U2F_endpoint: - pytest.skip("Does not work with this transport until SDK patch") - # Extended encoding, no Lc and explicit Le - apdu = struct.pack(">BBBBBH", cla, ins, p1, p2, 0, ne) - client.ctap1.send_raw_apdu(apdu) +@pytest.mark.skip_endpoint("u2f") +def test_cmd_no_data_short_encoding_hid_only(client): + cla = 0x00 + ins = Ctap1.INS.VERSION + p1 = 0x00 + p2 = 0x00 + nc = 0 - # Extended encoding, no Lc and no Le - apdu = struct.pack(">BBBB", cla, ins, p1, p2) - client.ctap1.send_raw_apdu(apdu) + # Short encoding Lc and Le + apdu = struct.pack(">BBBBBB", cla, ins, p1, p2, 0, 0xaa) + result = client.ctap1.send_raw_apdu(apdu) # Short encoding, Lc and no Le # This should not be supported as spec requires that messages over HID @@ -120,4 +147,4 @@ def test_cmd_no_data_encoding(client): # However, it is not respected on v1.7.0 even after an issue was raised: # https://github.com/fido-alliance/conformance-test-tools-resources/issues/614 apdu = struct.pack(">BBBBB", cla, ins, p1, p2, nc) - client.ctap1.send_raw_apdu(apdu) + assert result == client.ctap1.send_raw_apdu(apdu)