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

Add NFC reader mode support #777

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions Makefile.standard_app
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME), TARGET_STAX TARGET_FLEX))
endif
endif

ifeq ($(ENABLE_NFC_READER), 1)
ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME), TARGET_STAX TARGET_FLEX))
DEFINES += HAVE_NFC_READER
endif
endif

#####################################################################
# SWAP #
#####################################################################
Expand Down
69 changes: 69 additions & 0 deletions include/os_io_nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,77 @@
#ifndef OS_IO_NFC_H
#define OS_IO_NFC_H

#include "arch.h"

#include "os_io_seproxyhal.h"

/* Public API for reader application --------------------------------------- */
#ifdef HAVE_NFC_READER

enum card_tech {
NFC_A,
NFC_B
};

struct card_info {
enum card_tech tech;
uint8_t nfcid[7];
size_t nfcid_len;
};

enum nfc_event {
CARD_DETECTED,
CARD_REMOVED,
};

typedef void (*nfc_evt_callback_t)(enum nfc_event event, struct card_info *info);
typedef void (*nfc_resp_callback_t)(bool error, bool timeout, uint8_t *resp_data, size_t resp_len);

/* Functions */

/* return false in case of error
in that case, callback will not be called */
bool io_nfc_reader_send(const uint8_t *cmd_data,
size_t cmd_len,
nfc_resp_callback_t callback,
int timeout_ms);

/* Return false if nfc reader can not be started in current conditions */
bool io_nfc_reader_start(nfc_evt_callback_t callback);
void io_nfc_reader_stop(void);
bool io_nfc_is_reader(void);

#endif // HAVE_NFC_READER

/* SDK internal API --------------------------------------- */

#ifdef HAVE_NFC_READER

struct nfc_reader_context {
nfc_resp_callback_t resp_callback;
nfc_evt_callback_t evt_callback;
bool reader_mode;
bool event_happened;
bool response_received;
unsigned int remaining_ms;
enum nfc_event last_event;
struct card_info card;
uint8_t *apdu_rx;
size_t apdu_rx_len; // Used length
size_t apdu_rx_max_size; // Max size of buffer
};

extern struct nfc_reader_context G_io_reader_ctx;
#endif // HAVE_NFC_READER

void io_nfc_init(void);
void io_nfc_recv_event(void);
void io_nfc_send_response(const uint8_t *packet, uint16_t packet_length);

#ifdef HAVE_NFC_READER
void io_nfc_event(void);
void io_nfc_ticker(void);
void io_nfc_process_events(void);
#endif // HAVE_NFC_READER

#endif
14 changes: 11 additions & 3 deletions include/seproxyhal_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@
#define SEPROXYHAL_TAG_BOOTLOADER_RAPDU_EVENT 0x19 // <RAPDU from the bootloader>
#define SEPROXYHAL_TAG_UX_EVENT 0x1A //
#ifdef HAVE_NFC
#define SEPROXYHAL_TAG_NFC_APDU_EVENT 0x1C
#define SEPROXYHAL_TAG_NFC_APDU_EVENT 0x1C
#define SEPROXYHAL_TAG_NFC_EVENT 0x1E
#define SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED 0x01 // card_detected + type a/b + nfcid[max 7]
#define SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_A 0x01
#define SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_B 0x02
#define SEPROXYHAL_TAG_NFC_EVENT_CARD_LOST 0x02 // card lost
#endif

#define SEPH_PROTOCOL_EVT_POWER_BUTTON_EVENT 0x1B
Expand Down Expand Up @@ -166,8 +171,11 @@
// #define SEPROXYHAL_TAG_SCREEN_DISPLAY 0x4A // wait for display_event after sent

#ifdef HAVE_NFC
#define SEPROXYHAL_TAG_NFC_RAPDU 0x4A
#define SEPROXYHAL_TAG_NFC_POWER 0x34
#define SEPROXYHAL_TAG_NFC_RAPDU 0x4A
#define SEPROXYHAL_TAG_NFC_POWER 0x34
#define SEPROXYHAL_TAG_NFC_POWER_OFF 0x00
#define SEPROXYHAL_TAG_NFC_POWER_ON_CE 0x01
#define SEPROXYHAL_TAG_NFC_POWER_ON_READER 0x02
#endif

#define SEPROXYHAL_TAG_DEVICE_OFF 0x4B
Expand Down
12 changes: 12 additions & 0 deletions lib_standard_app/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,21 @@
#include "swap.h"
#endif

#ifdef HAVE_NFC_READER
#include "os_io_nfc.h"
#endif // HAVE_NFC_READER

// TODO: Temporary workaround, at some point all status words should be defined by the SDK and
// removed from the application
#define SW_OK 0x9000
#define SW_WRONG_RESPONSE_LENGTH 0xB000

uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];

#ifdef HAVE_NFC_READER
struct nfc_reader_context G_io_reader_ctx;
#endif

/**
* Variable containing the length of the APDU response to send back.
*/
Expand Down Expand Up @@ -83,6 +91,10 @@ WEAK uint8_t io_event(uint8_t channel)
case SEPROXYHAL_TAG_TICKER_EVENT:
app_ticker_event_callback();
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {});
#ifdef HAVE_NFC_READER
io_nfc_ticker();
io_nfc_process_events();
#endif // HAVE_NFC_READER
break;
default:
UX_DEFAULT_EVENT();
Expand Down
159 changes: 151 additions & 8 deletions src/os_io_nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include "bolos_target.h"

#include "os.h"
#include "os_settings.h"
#include "os_io_seproxyhal.h"

#include "errors.h"
#include "exceptions.h"
#ifdef HAVE_NFC
Expand All @@ -25,17 +29,11 @@
#endif // DEBUG_OS_STACK_CONSUMPTION

#include "os_io.h"
#include "os_io_nfc.h"
#include "os_utils.h"
#include "os_io_seproxyhal.h"
#include <string.h>

#ifdef DEBUG
#define LOG printf
#else
#define LOG(...)
#endif

#include "os.h"
#include "ledger_protocol.h"

static uint8_t rx_apdu_buffer[IO_APDU_BUFFER_SIZE];
Expand All @@ -55,6 +53,11 @@ void io_nfc_init(void)
ledger_protocol_data.rx_dst_buffer = G_io_apdu_buffer;
#endif
LEDGER_PROTOCOL_init(&ledger_protocol_data);
#ifdef HAVE_NFC_READER
memset((void *) &G_io_reader_ctx, 0, sizeof(G_io_reader_ctx));
G_io_reader_ctx.apdu_rx = rx_apdu_buffer;
G_io_reader_ctx.apdu_rx_max_size = sizeof(rx_apdu_buffer);
#endif // HAVE_NFC_READER
}

void io_nfc_recv_event(void)
Expand All @@ -65,6 +68,14 @@ void io_nfc_recv_event(void)

// Full apdu is received, copy it to global apdu buffer
if (ledger_protocol_data.rx_apdu_status == APDU_STATUS_COMPLETE) {
#ifdef HAVE_NFC_READER
if (G_io_reader_ctx.reader_mode) {
G_io_reader_ctx.response_received = true;
G_io_reader_ctx.apdu_rx_len = ledger_protocol_data.rx_apdu_length;
return;
}
#endif // HAVE_NFC_READER

memcpy(ledger_protocol_data.rx_dst_buffer,
ledger_protocol_data.rx_apdu_buffer,
ledger_protocol_data.rx_apdu_length);
Expand Down Expand Up @@ -106,4 +117,136 @@ void io_nfc_send_response(const uint8_t *packet, uint16_t packet_length)
}
}

#ifdef HAVE_NFC_READER

void io_nfc_event(void)
{
size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);

if (size >= 1) {
switch (G_io_seproxyhal_spi_buffer[3]) {
case SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED: {
G_io_reader_ctx.event_happened = true;
G_io_reader_ctx.last_event = CARD_DETECTED;
G_io_reader_ctx.card.tech
= (G_io_seproxyhal_spi_buffer[4] == SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_A)
? NFC_A
: NFC_B;
G_io_reader_ctx.card.nfcid_len = MIN(size - 2, sizeof(G_io_reader_ctx.card.nfcid));
memcpy((void *) G_io_reader_ctx.card.nfcid,
G_io_seproxyhal_spi_buffer + 5,
G_io_reader_ctx.card.nfcid_len);
} break;

case SEPROXYHAL_TAG_NFC_EVENT_CARD_LOST:
if (G_io_reader_ctx.evt_callback != NULL) {
G_io_reader_ctx.event_happened = true;
G_io_reader_ctx.last_event = CARD_REMOVED;
}
break;
}
}
}

void io_nfc_process_events(void)
{
if (G_io_reader_ctx.response_received) {
G_io_reader_ctx.response_received = false;
if (G_io_reader_ctx.resp_callback != NULL) {
nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback;
G_io_reader_ctx.resp_callback = NULL;
resp_cb(false, false, G_io_reader_ctx.apdu_rx, G_io_reader_ctx.apdu_rx_len);
}
}

if (G_io_reader_ctx.resp_callback != NULL && G_io_reader_ctx.remaining_ms == 0) {
nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback;
G_io_reader_ctx.resp_callback = NULL;
resp_cb(false, true, NULL, 0);
}

if (G_io_reader_ctx.event_happened) {
G_io_reader_ctx.event_happened = 0;

// If card is removed during an APDU processing, call the resp_callback with an error
if (G_io_reader_ctx.resp_callback != NULL && G_io_reader_ctx.last_event == CARD_REMOVED) {
nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback;
G_io_reader_ctx.resp_callback = NULL;
resp_cb(true, false, NULL, 0);
}

if (G_io_reader_ctx.evt_callback != NULL) {
G_io_reader_ctx.evt_callback(G_io_reader_ctx.last_event,
(struct card_info *) &G_io_reader_ctx.card);
}
if (G_io_reader_ctx.last_event == CARD_REMOVED) {
memset((void *) &G_io_reader_ctx.card, 0, sizeof(G_io_reader_ctx.card));
}
}
}

void io_nfc_ticker(void)
{
if (G_io_reader_ctx.resp_callback != NULL) {
if (G_io_reader_ctx.remaining_ms <= 100) {
G_io_reader_ctx.remaining_ms = 0;
}
else {
G_io_reader_ctx.remaining_ms -= 100;
}
}
}

bool io_nfc_reader_send(const uint8_t *cmd_data,
size_t cmd_len,
nfc_resp_callback_t callback,
int timeout_ms)
{
G_io_reader_ctx.resp_callback = PIC(callback);
io_nfc_send_response(PIC(cmd_data), cmd_len);

G_io_reader_ctx.response_received = false;
G_io_reader_ctx.remaining_ms = timeout_ms;

return true;
}

void io_nfc_reader_power(void)
{
uint8_t buffer[4];
buffer[0] = SEPROXYHAL_TAG_NFC_POWER;
buffer[1] = 0;
buffer[2] = 1;
buffer[3] = SEPROXYHAL_TAG_NFC_POWER_ON_READER;
io_seproxyhal_spi_send(buffer, 4);
}

bool io_nfc_reader_start(nfc_evt_callback_t callback)
{
G_io_reader_ctx.evt_callback = PIC(callback);
G_io_reader_ctx.reader_mode = true;
G_io_reader_ctx.event_happened = false;
G_io_reader_ctx.resp_callback = NULL;
G_io_reader_ctx.response_received = false;
io_nfc_reader_power();
return true;
}

void io_nfc_reader_stop()
{
G_io_reader_ctx.evt_callback = NULL;
G_io_reader_ctx.reader_mode = false;
G_io_reader_ctx.event_happened = false;
G_io_reader_ctx.resp_callback = NULL;
G_io_reader_ctx.response_received = false;
io_seproxyhal_nfc_power(false);
}

bool io_nfc_is_reader(void)
{
return G_io_reader_ctx.reader_mode;
}

#endif // HAVE_NFC_READER

#endif // HAVE_NFC
20 changes: 16 additions & 4 deletions src/os_io_seproxyhal.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,19 @@ unsigned int io_seproxyhal_handle_event(void)
#ifdef HAVE_NFC
case SEPROXYHAL_TAG_NFC_APDU_EVENT:
io_nfc_recv_event();
#if defined(HAVE_NFC_READER) && !defined(HAVE_BOLOS)
io_nfc_process_events();
#endif // HAVE_NFC_READER && !HAVE_BOLOS
return 1;
#endif
#ifdef HAVE_NFC_READER
case SEPROXYHAL_TAG_NFC_EVENT:
io_nfc_event();
#ifndef HAVE_BOLOS
io_nfc_process_events();
#endif // !HAVE_BOLOS
return 1;
#endif // HAVE_NFC_READER
#endif // HAVE_NFC

case SEPROXYHAL_TAG_UX_EVENT:
switch (G_io_seproxyhal_spi_buffer[3]) {
Expand Down Expand Up @@ -502,9 +513,10 @@ void io_seproxyhal_nfc_power(bool forceInit)
{
uint8_t buffer[4];
uint8_t power
= forceInit
? 1
: (os_setting_get(OS_SETTING_FEATURES, NULL, 0) & OS_SETTING_FEATURES_NFC_ENABLED);
= (forceInit
|| (os_setting_get(OS_SETTING_FEATURES, NULL, 0) & OS_SETTING_FEATURES_NFC_ENABLED))
? SEPROXYHAL_TAG_NFC_POWER_ON_CE
: SEPROXYHAL_TAG_NFC_POWER_OFF;
buffer[0] = SEPROXYHAL_TAG_NFC_POWER;
buffer[1] = 0;
buffer[2] = 1;
Expand Down
Loading
Loading