Skip to content

Commit

Permalink
[clean] Trying to simplify higher-level, global interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
lpascal-ledger committed Nov 18, 2024
1 parent d83258e commit f8dfba7
Show file tree
Hide file tree
Showing 19 changed files with 316 additions and 191 deletions.
95 changes: 1 addition & 94 deletions include/ctap2.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#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
Expand Down Expand Up @@ -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);

Expand Down
41 changes: 31 additions & 10 deletions include/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@

#pragma once

#include "u2f_service.h"
#include <u2f_service.h>

#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)
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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` .
Expand All @@ -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);
15 changes: 8 additions & 7 deletions src/ctap2/client_pin.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
* limitations under the License.
********************************************************************************/

#include "os.h"
#include "cx.h"
#include "ledger_assert.h"
#include <os.h>
#include <cx.h>
#include <ledger_assert.h>

#include "ctap2.h"
#include "ctap2_utils.h"
#include "config.h"
#include "cbip_helper.h"
#include "cose_keys.h"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}

/******************************************/
Expand Down
68 changes: 68 additions & 0 deletions src/ctap2/ctap2_utils.c
Original file line number Diff line number Diff line change
@@ -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 <lib_standard_app/io.h>
#include <lib_u2f/include/u2f_processing.h>

#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.
}
33 changes: 33 additions & 0 deletions src/ctap2/ctap2_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
*******************************************************************************
* 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 <u2f_service.h>

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);
17 changes: 16 additions & 1 deletion src/ctap2/get_assertion/get_assertion.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
********************************************************************************/

#include <string.h>
#include <lib_standard_app/format.h>

#include "ctap2.h"
#include "config.h"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(); */
Expand Down
Loading

0 comments on commit f8dfba7

Please sign in to comment.