Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nfc implementation #40

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ DEFINES += HAVE_DEBUG_THROWS

#DEFINES += HAVE_CBOR_DEBUG


ENABLE_NFC = 1

##############
# Compiler #
##############
Expand Down
2 changes: 1 addition & 1 deletion attestations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ You can start from a copy of an other model and should update:

## Device private key and certificate generation

Then you can run `./createKeyAndCert.sh <env> <version> <model>` to generate the device key and certificate.
Then you can run `./createDeviceKeyAndCert.sh <env> <version> <model>` to generate the device key and certificate.
It takes three parameters:
- `<env>`: an env (`test`, `prod`, ...) that is used when retrieving the CA inputs and generating the outputs.
- `<version>`: either `U2F` or `FIDO2`
Expand Down
2 changes: 1 addition & 1 deletion attestations/cnf/U2F/openssl_cert_stax.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ CN = Ledger Stax FIDO 1 Attestation Batch 1
[v3_req]
subjectKeyIdentifier = none
authorityKeyIdentifier = none
1.3.6.1.4.1.45724.2.1.1=DER:03:02:05:20 # USB
1.3.6.1.4.1.45724.2.1.1=DER:03:02:04:30 # USB + NFC
Binary file modified attestations/data/test/U2F/stax-cert.der
Binary file not shown.
26 changes: 13 additions & 13 deletions include/crypto_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,16 +562,16 @@ static const uint8_t TEST_U2F_STAX_ATTESTATION_KEY[] = {
0xaf, 0xb8, 0x18, 0x41, 0xc4, 0xf2, 0x12, 0x69, 0x62, 0xf6, 0x74, 0x4e, 0xc1, 0x7f, 0x38, 0x61,
0xda, 0xa9, 0x39, 0x28, 0x4b, 0x39, 0x78, 0xf1, 0x86, 0x00, 0xab, 0xf4, 0x4a, 0xb4, 0x3a, 0x5e};
static const uint8_t TEST_U2F_STAX_ATTESTATION_CERT[] = {
0x30, 0x82, 0x01, 0xcf, 0x30, 0x82, 0x01, 0x75, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x0c,
0x20, 0x10, 0x9d, 0x50, 0xe9, 0xa0, 0x63, 0x59, 0xa6, 0xf1, 0x03, 0xe4, 0x83, 0x5e, 0xbb, 0xd5,
0x3b, 0x10, 0xcd, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
0x30, 0x82, 0x01, 0xd0, 0x30, 0x82, 0x01, 0x75, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x0d,
0x17, 0x66, 0x8e, 0x42, 0xc3, 0x06, 0x06, 0x39, 0x13, 0x35, 0x1b, 0xbd, 0x07, 0x9e, 0x1b, 0x91,
0x77, 0x08, 0xda, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
0x43, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x0f,
0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x31,
0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72,
0x20, 0x46, 0x49, 0x44, 0x4f, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x32, 0x32, 0x30, 0x31, 0x33,
0x35, 0x34, 0x35, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x33, 0x30, 0x32, 0x31, 0x37, 0x31, 0x33, 0x35,
0x34, 0x35, 0x30, 0x5a, 0x30, 0x73, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x6e, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x30, 0x34, 0x31, 0x35, 0x31, 0x33,
0x32, 0x38, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x34, 0x31, 0x33, 0x31, 0x33, 0x32,
0x38, 0x30, 0x37, 0x5a, 0x30, 0x73, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x46, 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4c, 0x65,
0x64, 0x67, 0x65, 0x72, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74,
Expand All @@ -585,13 +585,13 @@ static const uint8_t TEST_U2F_STAX_ATTESTATION_CERT[] = {
0x16, 0xb9, 0x32, 0xf4, 0x20, 0x31, 0x0a, 0x8d, 0xaa, 0x5c, 0xae, 0x09, 0xb3, 0xed, 0x69, 0xe1,
0xe7, 0xd3, 0x5b, 0x4f, 0x5f, 0x4d, 0xd3, 0xce, 0x4d, 0x78, 0x7c, 0xcb, 0xe0, 0x45, 0x2c, 0xe5,
0xa6, 0x12, 0x77, 0xbd, 0xa3, 0x17, 0x30, 0x15, 0x30, 0x13, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x05, 0x20, 0x30, 0x0a, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21,
0x00, 0xc5, 0xf3, 0xf8, 0xcc, 0xc4, 0xc0, 0x76, 0x68, 0x72, 0x3e, 0x21, 0xa9, 0x88, 0x5a, 0x6a,
0x18, 0x94, 0xfb, 0xc8, 0x5c, 0x55, 0xfa, 0x6e, 0x28, 0xf6, 0x44, 0x23, 0x9d, 0xaf, 0x4a, 0x29,
0x43, 0x02, 0x20, 0x62, 0x6e, 0x27, 0x1e, 0x27, 0x2f, 0x76, 0x92, 0x8b, 0x44, 0xd6, 0x6d, 0x21,
0xdb, 0xe9, 0x94, 0x87, 0x4e, 0x79, 0xc2, 0x0a, 0xfc, 0x74, 0x5f, 0xf4, 0x8c, 0x11, 0x0a, 0xb1,
0x15, 0xd0, 0x94};
0x01, 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30, 0x0a, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21,
0x00, 0xc1, 0x99, 0x89, 0xaf, 0x18, 0x56, 0x45, 0x6d, 0xbf, 0x25, 0x16, 0x68, 0xf7, 0xeb, 0xc1,
0xf8, 0xec, 0xc4, 0xbb, 0x0d, 0x4d, 0x8a, 0xdc, 0xd8, 0xf7, 0xa5, 0x84, 0x39, 0xc0, 0xed, 0x01,
0xac, 0x02, 0x21, 0x00, 0x9f, 0xef, 0x7b, 0xbd, 0x8f, 0x2f, 0x0f, 0xcd, 0x58, 0x69, 0xb9, 0xac,
0x09, 0x77, 0x0c, 0xbe, 0x8d, 0xca, 0x69, 0x97, 0x3c, 0xb8, 0x6a, 0x62, 0x25, 0x59, 0xb1, 0x46,
0xe8, 0x23, 0x94, 0x5e};

/* FIDO2 TEST env */
static const uint8_t TEST_FIDO2_STAX_ATTESTATION_KEY[] = {
Expand Down
13 changes: 12 additions & 1 deletion include/ctap2.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@
#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)
#else
#define CMD_IS_OVER_U2F_NFC false
#endif

extern const uint8_t AAGUID[16];

typedef struct ctap2_register_data_s {
Expand Down Expand Up @@ -177,7 +185,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,
Expand Down
7 changes: 7 additions & 0 deletions include/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ extern char rpID[65];

extern u2f_service_t G_io_u2f;

#ifdef TARGET_NANOS
// Spare RAM on Nanos
#define responseBuffer G_io_apdu_buffer
#else
extern uint8_t responseBuffer[IO_APDU_BUFFER_SIZE];
#endif

typedef struct ctap2_data_t {
union ctap2_data_u {
ctap2_register_data_t ctap2RegisterData;
Expand Down
44 changes: 44 additions & 0 deletions include/nfc_io.h
Original file line number Diff line number Diff line change
@@ -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) {
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
27 changes: 27 additions & 0 deletions include/sw_code.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
*******************************************************************************
* 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.
********************************************************************************/

#define SW_NO_ERROR 0x9000
#define SW_MORE_DATA 0x6100
#define SW_WRONG_LENGTH 0x6700
#define SW_CONDITIONS_NOT_SATISFIED 0x6985
#define SW_WRONG_DATA 0x6A80
#define SW_INCORRECT_P1P2 0x6A86
#define SW_INS_NOT_SUPPORTED 0x6D00
#define SW_CLA_NOT_SUPPORTED 0x6E00
#define SW_PROPRIETARY_INTERNAL 0x6FFF
1 change: 1 addition & 0 deletions include/u2f_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define __U2F_PROCESS_H__

typedef struct u2f_data_t {
uint8_t ins;
uint8_t challenge_param[32];
uint8_t application_param[32];
uint8_t nonce[CREDENTIAL_NONCE_SIZE];
Expand Down
4 changes: 4 additions & 0 deletions src/app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/**
Expand Down
14 changes: 7 additions & 7 deletions src/ctap2_client_pin.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ static void handle_store_pin(u2f_service_t *service,
// Invalidate previous token and force the user to issue a GET_PIN_TOKEN command
authTokeninUse = false;

G_io_apdu_buffer[0] = ERROR_NONE;
responseBuffer[0] = ERROR_NONE;
send_cbor_response(&G_io_u2f, 1);
}

Expand Down Expand Up @@ -444,12 +444,12 @@ static void ctap2_handle_get_pin_retries(u2f_service_t *service,
PRINTF("ctap2_handle_get_pin_retries\n");
CHECK_PIN_SET();

cbip_encoder_init(&encoder, G_io_apdu_buffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_encoder_init(&encoder, responseBuffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_add_map_header(&encoder, 1);
cbip_add_int(&encoder, TAG_RESP_RETRIES);
cbip_add_int(&encoder, N_u2f.pinRetries);

G_io_apdu_buffer[0] = ERROR_NONE;
responseBuffer[0] = ERROR_NONE;
send_cbor_response(&G_io_u2f, 1 + encoder.offset);
}

Expand All @@ -473,7 +473,7 @@ static void ctap2_handle_get_key_agreement(u2f_service_t *service,
return;
}

cbip_encoder_init(&encoder, G_io_apdu_buffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_encoder_init(&encoder, responseBuffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_add_map_header(&encoder, 1);
cbip_add_int(&encoder, TAG_RESP_KEY_AGREEMENT);
status = encode_cose_key(&encoder, &publicKey, true);
Expand All @@ -482,7 +482,7 @@ static void ctap2_handle_get_key_agreement(u2f_service_t *service,
return;
}

G_io_apdu_buffer[0] = ERROR_NONE;
responseBuffer[0] = ERROR_NONE;
send_cbor_response(&G_io_u2f, 1 + encoder.offset);
}

Expand Down Expand Up @@ -658,12 +658,12 @@ static void ctap2_handle_get_pin_token(u2f_service_t *service,
&encryptedLength);

// Generate the response
cbip_encoder_init(&encoder, G_io_apdu_buffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_encoder_init(&encoder, responseBuffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_add_map_header(&encoder, 1);
cbip_add_int(&encoder, TAG_RESP_PIN_TOKEN);
cbip_add_byte_string(&encoder, tokenEnc, encryptedLength);

G_io_apdu_buffer[0] = ERROR_NONE;
responseBuffer[0] = ERROR_NONE;
send_cbor_response(&G_io_u2f, 1 + encoder.offset);
}

Expand Down
18 changes: 14 additions & 4 deletions src/ctap2_get_assertion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Comment on lines +385 to +386
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

// -> 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 {
Expand Down Expand Up @@ -881,7 +891,7 @@ void ctap2_get_assertion_confirm(uint16_t idx) {
// Build the response
status = sign_and_build_getAssert_authData(shared_ctx.sharedBuffer,
dataLen,
G_io_apdu_buffer + 1,
responseBuffer + 1,
CUSTOM_IO_APDU_BUFFER_SIZE - 1,
&credData);
if (status < 0) {
Expand All @@ -890,7 +900,7 @@ void ctap2_get_assertion_confirm(uint16_t idx) {
dataLen = status;
status = 0;

G_io_apdu_buffer[0] = ERROR_NONE;
responseBuffer[0] = ERROR_NONE;

exit:
if (status == 0) {
Expand Down
5 changes: 3 additions & 2 deletions src/ctap2_get_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "ctap2.h"
#include "cbip_encode.h"
#include "config.h"
#include "globals.h"

#define CTAP_HEADER_SIZE 7

Expand All @@ -45,7 +46,7 @@ void ctap2_get_info_handle(u2f_service_t *service, uint8_t *buffer, uint16_t len

PRINTF("ctap2_get_info_handle\n");

cbip_encoder_init(&encoder, G_io_apdu_buffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);
cbip_encoder_init(&encoder, responseBuffer + 1, CUSTOM_IO_APDU_BUFFER_SIZE - 1);

cbip_add_map_header(&encoder, 6);

Expand Down Expand Up @@ -95,6 +96,6 @@ void ctap2_get_info_handle(u2f_service_t *service, uint8_t *buffer, uint16_t len
cbip_add_array_header(&encoder, 1);
cbip_add_int(&encoder, PIN_PROTOCOL_VERSION_V1);

G_io_apdu_buffer[0] = ERROR_NONE;
responseBuffer[0] = ERROR_NONE;
send_cbor_response(service, 1 + encoder.offset);
}
Loading
Loading