Skip to content

Commit

Permalink
[ui][add] Displaying RP/user information on ctap2+NFC registration & …
Browse files Browse the repository at this point in the history
…authentication
  • Loading branch information
lpascal-ledger committed Sep 19, 2024
1 parent 335f3e8 commit c97e96f
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 58 deletions.
28 changes: 26 additions & 2 deletions include/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,29 @@ static inline ctap2_assert_data_t *globals_get_ctap2_assert_data(void) {
return &shared_ctx.u.ctap2Data.u.ctap2AssertData;
}

void truncate_pairs_for_display(void);
void prepare_display_status(void);
/*
* 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` .
* - on status screens (buffer display when NFC transport is used), the police is smaller, argument
* `large` should be `false`.
*/
void truncate_pairs_for_display(bool large);

/*
* Formats strings stored in global buffers into a single global buffer
*
* This functions copies the global buffers `g.buffer1_65` and `g.buffer2_65` into
* `g.display_status`. This `g.display_status` is used by `app_nbgl_status` to display
* additional informations (RP name, username, ...).
* These information are copied only if:
* - the current transport is NFC
* - AND `clean_buffer` is `false`.
* In this case, the formatting is the following: `<g.buffer1_65>\n<g.buffer2_65>`.
* Else, '\0' is inserted at the beginning of the buffer.
* The input buffers should have been previously truncated to fit the NBGL page width.
*
* @param clean_buffer: always insert a '\0' character at the beginning of the buffer
*/
void prepare_display_status(bool clean_buffer);

void ctap2_copy_info_on_buffers(void);
10 changes: 9 additions & 1 deletion include/nfc_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@
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);

/*
* Sends a previously prepared response through NFC, then (if successful) displays a status screen
* (usgin app_nbgl_status). Depending on `display_infos`, this screen will contain additional
* information such as the relying party name and/or the user credential.
*
* @param display_infos If the displayed status screen should contain RP/user information or not.
*/
int nfc_io_send_prepared_response(bool display_infos);

#else
static inline void nfc_io_set_le(uint32_t le __attribute__((unused))) {
Expand Down
2 changes: 1 addition & 1 deletion include/u2f_processing_flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,4 @@ typedef struct u2f_auth_resp_base_t {

uint16_t u2f_prepare_enroll_response(uint8_t *buffer, uint16_t *length);
uint16_t u2f_prepare_sign_response(uint8_t *buffer, uint16_t *length);
void u2f_prompt_user_presence(bool enroll, uint8_t *applicationParameter);
void u2f_prompt_user_presence(bool enroll);
1 change: 1 addition & 0 deletions src/ctap2_get_assertion.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ void ctap2_get_assertion_handle(u2f_service_t *service, uint8_t *buffer, uint16_

if (CMD_IS_OVER_U2F_NFC) {
// No up nor uv requested, skip UX and reply immediately
ctap2_copy_info_on_buffers();
// TODO: is this what we want?
// TODO: Handle cases where availableCredentials is != 1
// -> which credentials should be chosen?
Expand Down
25 changes: 1 addition & 24 deletions src/ctap2_make_credential_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,11 @@

#include "os.h"
#include "ux.h"
#include "format.h"

#include "ctap2.h"
#include "globals.h"
#include "ui_shared.h"

static void ctap2_ux_get_display_user(void) {
ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data();

// TODO show that user.id is truncated if necessary
if (ctap2RegisterData->userStr) {
uint8_t nameLength = MIN(ctap2RegisterData->userStrLen, sizeof(g.buffer2_65) - 1);

memcpy(g.buffer2_65, ctap2RegisterData->userStr, nameLength);
g.buffer2_65[nameLength] = '\0';
} 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));
}
}

static void ctap_ux_on_user_choice(bool confirm) {
ctap2UxState = CTAP2_UX_STATE_NONE;

Expand Down Expand Up @@ -144,15 +127,9 @@ static const nbgl_layoutTagValue_t pairs[NB_OF_PAIRS] = {{

void ctap2_make_credential_ux(void) {
ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data();

ctap2UxState = CTAP2_UX_STATE_MAKE_CRED;

// TODO show that rp.id is truncated if necessary
uint8_t len = MIN(sizeof(g.buffer1_65) - 1, ctap2RegisterData->rpIdLen);
memcpy(g.buffer1_65, ctap2RegisterData->rpId, len);

g.buffer1_65[len] = '\0';
ctap2_ux_get_display_user();
ctap2_copy_info_on_buffers();

UX_WAKE_UP();

Expand Down
2 changes: 1 addition & 1 deletion src/ctap2_processing.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void send_cbor_response(u2f_service_t *service, uint32_t length) {
status = "Login request signed";
}
nfc_io_set_response_ready(SW_NO_ERROR, length, status);
nfc_io_send_prepared_response();
nfc_io_send_prepared_response(true);
} else if (CMD_IS_OVER_U2F_CMD) {
io_send_response_pointer(responseBuffer, length, SW_NO_ERROR);
} else {
Expand Down
42 changes: 31 additions & 11 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* limitations under the License.
********************************************************************************/

#include "format.h"
#include "os.h"
#include "os_io_seproxyhal.h"

Expand All @@ -34,25 +35,44 @@ uint8_t responseBuffer[IO_APDU_BUFFER_SIZE];

#include "string_utils.h"

void truncate_pairs_for_display() {
truncate_for_nb_lines(g.buffer_20);
PRINTF("buffer_20 after truncation: '%s'\n", g.buffer_20);
truncate_for_nb_lines(g.buffer1_65);
void ctap2_copy_info_on_buffers(void) {
ctap2_register_data_t *ctap2RegisterData = globals_get_ctap2_register_data();

// TODO show that rp.id is truncated if necessary
uint8_t len = MIN(sizeof(g.buffer1_65) - 1, ctap2RegisterData->rpIdLen);
memcpy(g.buffer1_65, ctap2RegisterData->rpId, len);
g.buffer1_65[len] = '\0';

// TODO show that user.id is truncated if necessary
if (ctap2RegisterData->userStr) {
uint8_t nameLength = MIN(ctap2RegisterData->userStrLen, sizeof(g.buffer2_65) - 1);

memcpy(g.buffer2_65, ctap2RegisterData->userStr, nameLength);
g.buffer2_65[nameLength] = '\0';
} 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); */
truncate_for_nb_lines(g.buffer1_65, large);
PRINTF("buffer1_65 after truncation: '%s'\n", g.buffer1_65);
truncate_for_nb_lines(g.buffer2_65);
truncate_for_nb_lines(g.buffer2_65, large);
PRINTF("buffer2_65 after truncation: '%s'\n", g.buffer2_65);
}

void prepare_display_status() {
if (!g.is_nfc) {
PRINTF("NOT NFC so no display status for buffer1_65 '%s' and buffer2_65 '%s'\n",
void prepare_display_status(bool clean_buffer) {
if (!g.is_nfc || clean_buffer) {
PRINTF("NO NFC or cleaning, so no display status for buffer1_65 '%s' and buffer2_65 '%s'\n",
g.buffer1_65,
g.buffer2_65);
g.display_status[0] = '\0';
return;
}
strncpy(g.display_status, g.buffer1_65, strlen(g.buffer1_65));
g.display_status[strlen(g.buffer1_65)] = '\n';
strncpy(g.display_status + strlen(g.buffer1_65) + 1, g.buffer2_65, strlen(g.buffer2_65));
snprintf(g.display_status, sizeof(g.display_status), "%s\n%s", g.buffer1_65, g.buffer2_65);
PRINTF("NFC so display status is: '%s'\n", g.display_status);
}
5 changes: 4 additions & 1 deletion src/nfc_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ bool nfc_io_is_response_pending(void) {
return nfc_data_ready;
}

int nfc_io_send_prepared_response(void) {
int nfc_io_send_prepared_response(bool display_infos) {
if (!nfc_data_ready) {
return io_send_sw(SW_WRONG_DATA);
}
Expand Down Expand Up @@ -82,6 +82,9 @@ int nfc_io_send_prepared_response(void) {

int ret = io_send_response_pointer(responseBuffer + start, size, sw);
if (sw == SW_NO_ERROR && nfc_status != NULL) {
if (display_infos) {
ctap2_copy_info_on_buffers();
}
app_nbgl_status(nfc_status, true, ui_idle);
}

Expand Down
8 changes: 5 additions & 3 deletions src/string_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <nbgl_layout.h>
#endif // defined(HAVE_NBGL)

void truncate_for_nb_lines(char *input) {
void truncate_for_nb_lines(char *input, bool large) {
#if !defined(HAVE_NBGL)
UNUSED(input);
return;
Expand All @@ -24,13 +24,15 @@ void truncate_for_nb_lines(char *input) {
uint8_t size = strlen(input);

do {
// Trying to keep as much of the string as possible (hence the `do...` while loop)
// 1. Trying to keep as much of the string as possible (hence the `do...` while loop)
// Ex: on Flex, with a single call, 'MMMMMMMMMMMMMMMMMMMMMMMMMMMM' would be reduced to
// 'MMMMMMMMMMMMMMMMMMMMMMM...', when it fact 'MMMMMMMMMMMMMMMMMMMMMMMM...' would fit.
// As the truncation could be severe (down to 24B in this example), I think this is worth
// the extra computation (in any case, this would take a maximum of 3 iterations into the
// loop)
nbgl_getTextMaxLenInNbLines(LARGE_MEDIUM_FONT,
// 2. 'large' is used on 'review' pages (needing user confirmation), while '!large' is used
// on 'status' pages (NFC: no confirmation but still credential display)
nbgl_getTextMaxLenInNbLines(large ? LARGE_MEDIUM_FONT : SMALL_REGULAR_1BPP_FONT,
input,
AVAILABLE_WIDTH,
line_nb,
Expand Down
2 changes: 1 addition & 1 deletion src/string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
* If not, the string is truncated to fit, and, the last 3 characters are
* replaced with dots ('...').
*/
void truncate_for_nb_lines(char *input);
void truncate_for_nb_lines(char *input, bool large);
12 changes: 6 additions & 6 deletions src/u2f_processing.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,11 @@ static int u2f_handle_apdu_enroll(const uint8_t *rx, uint32_t data_length, const

nfc_io_set_response_ready(sw, length, "Registration details\nsent");

return nfc_io_send_prepared_response();
return nfc_io_send_prepared_response(false);
} 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);
u2f_prompt_user_presence(true);
return 0;
}

Expand Down Expand Up @@ -289,7 +289,7 @@ static int u2f_handle_apdu_sign(const uint8_t *rx, uint32_t data_length, uint8_t
u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, true);
}

u2f_prompt_user_presence(false, globals_get_u2f_data()->application_param);
u2f_prompt_user_presence(false);
return 0;

// clang-format on
Expand Down Expand Up @@ -381,7 +381,7 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) {
if (!CMD_IS_OVER_U2F_NFC) {
return io_send_sw(SW_INS_NOT_SUPPORTED);
}
return nfc_io_send_prepared_response();
return nfc_io_send_prepared_response(false);

default:
PRINTF("unsupported\n");
Expand All @@ -395,14 +395,14 @@ int u2f_handle_apdu(uint8_t *rx, int rx_length) {

case 0x11:
PRINTF("NFCCTAP_GETRESPONSE\n");
return nfc_io_send_prepared_response();
return nfc_io_send_prepared_response(false);

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();
return nfc_io_send_prepared_response(false);

default:
PRINTF("unsupported\n");
Expand Down
10 changes: 5 additions & 5 deletions src/u2f_processing_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,15 +363,15 @@ static void on_login_choice(bool confirm) {

#endif

void u2f_prompt_user_presence(bool enroll, uint8_t *applicationParameter) {
void u2f_prompt_user_presence(bool enroll) {
UX_WAKE_UP();

format_hex(applicationParameter, 32, g.buffer2_65, sizeof(g.buffer2_65));
strcpy(g.buffer_20, "Unknown");

const char *name = fido_match_known_appid(applicationParameter);
format_hex(globals_get_u2f_data()->application_param, 32, g.buffer2_65, sizeof(g.buffer2_65));
const char *name = fido_match_known_appid(globals_get_u2f_data()->application_param);
if (name != NULL) {
strlcpy(g.buffer_20, name, sizeof(g.buffer_20));
} else {
strcpy(g.buffer_20, "Unknown");
}

#if defined(HAVE_BAGL)
Expand Down
12 changes: 10 additions & 2 deletions src/ui_shared_nbgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ void app_nbgl_start_review(uint8_t nb_pairs,
nbgl_choiceCallback_t on_choice,
nbgl_callback_t on_select) {
// only NBGL screens has such needs
truncate_pairs_for_display();
truncate_pairs_for_display(true);

nbgl_layoutDescription_t layoutDescription;
onChoice = on_choice;
Expand Down Expand Up @@ -281,6 +281,15 @@ static void tickerCallback(void) {
}

void app_nbgl_status(const char *message, bool is_success, nbgl_callback_t on_quit) {
if (is_success) {
// Truncate display buffers for small police (hence `false`) then format them into the
// display buffer (which is then used in `centeredInfo.text3`)
truncate_pairs_for_display(false);
prepare_display_status(false);
} else {
prepare_display_status(true);
}

if (is_success == true) {
io_seproxyhal_play_tune(TUNE_SUCCESS);
}
Expand All @@ -291,7 +300,6 @@ void app_nbgl_status(const char *message, bool is_success, nbgl_callback_t on_qu
.tickerValue = 3000 // 3 seconds
};
onQuit = on_quit;
prepare_display_status();
PRINTF("Will be displayed: '%s'\n", g.display_status);
nbgl_pageInfoDescription_t info = {
.bottomButtonStyle = NO_BUTTON_STYLE,
Expand Down

0 comments on commit c97e96f

Please sign in to comment.