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

Fix the processing of apdus across multiple sources #451

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 20 additions & 1 deletion include/os_io_seproxyhal.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ typedef struct io_seph_s {
unsigned short apdu_length; // total length to be received
unsigned short io_flags; // flags to be set when calling io_exchange
io_apdu_media_t apdu_media;
io_apdu_media_t apdu_media_lock;

unsigned int ms;

Expand Down Expand Up @@ -272,11 +273,29 @@ extern io_seph_app_t G_io_app;
*/
void io_task(void);
/**
* IO task initializez
* IO task initialize
*/
void io_start(void);
#endif // HAVE_IO_TASK

/**
* Lock apdu source to a media
* After this function is called, all subsequent apdus
* that come from any other media will be refused
*/
void io_apdu_media_lock(io_apdu_media_t media);
/**
* Unlock apdu source.
* After this function is called, apdus any media will be processed
*/
void io_apdu_media_unlock(void);
/**
* Check if an Apdu media shall be accepted.
* Return true if source media is not locked or if the media corresponds to the current lock
* Return false if media doesn't correspond to the current lock
*/
bool io_apdu_is_media_accepted(io_apdu_media_t media);

void io_seproxyhal_setup_ticker(unsigned int interval_ms);
void io_seproxyhal_power_off(bool criticalBattery);
void io_seproxyhal_se_reset(void);
Expand Down
7 changes: 7 additions & 0 deletions include/os_io_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ io_usb_hid_receive_status_t io_usb_hid_receive(io_send_t sndfct,
unsigned short l,
apdu_buffer_t *apdu_buffer);

/**
* Read next HID transport packet, keep track of received APDU but discard content.
* Return true when an apdu is fully received (and discarded)
* To be called typically upon USB OUT event while an other apdu is being processed
*/
bool io_usb_hid_discard(unsigned char *buffer, unsigned short l);

/**
* Mark the last chunk transmitted as sent.
* To be called typically upon USB IN ACK event
Expand Down
75 changes: 64 additions & 11 deletions lib_blewbxx_impl/src/ledger_ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,11 @@ static void init_mngr(uint16_t opcode, const uint8_t *buffer, uint16_t length)
ledger_ble_data.hci_cmd_opcode = 0xfc0f;
aci_hal_set_tx_power_level(1, // High power (ignored)
#ifdef TARGET_STAX
0x19); // 0 dBm
#else // !TARGET_STAX
0x07); // -14.1 dBm
#endif // !TARGET_STAX
0x19 // 0 dBm
#else // !TARGET_STAX
0x07 // -14.1 dBm
#endif // !TARGET_STAX
);
break;

case BLE_INIT_STEP_CONFIGURE_ADVERTISING:
Expand Down Expand Up @@ -510,7 +511,19 @@ static void hci_evt_cmd_complete(const uint8_t *buffer, uint16_t length)
if (ledger_ble_data.transfer_mode_enable) {
if ((ledger_protocol_data.rx_apdu_length)
&& (ledger_protocol_data.rx_apdu_status == APDU_STATUS_COMPLETE)) {
copy_apdu_to_app(false);
if (G_io_app.apdu_state == APDU_IDLE
&& io_apdu_is_media_accepted(IO_APDU_MEDIA_BLE)) {
copy_apdu_to_app(false);
}
else {
// Discard received APDU and respond with error
ledger_protocol_data.rx_apdu_length = 0;
ledger_protocol_data.rx_apdu_status = APDU_STATUS_WAITING;
uint8_t resp[2];
U2BE_ENCODE(resp, 0, SWO_IOL_STA_02);
LEDGER_PROTOCOL_tx(resp, 2);
notify_chunk();
}
}
}
else {
Expand All @@ -521,7 +534,9 @@ static void hci_evt_cmd_complete(const uint8_t *buffer, uint16_t length)
if (!ledger_protocol_data.tx_apdu_buffer) {
ledger_protocol_data.tx_chunk_length = 0;
G_io_app.ble_xfer_timeout = 0;
G_io_app.apdu_state = APDU_IDLE;
if (G_io_app.apdu_state == APDU_BLE) {
G_io_app.apdu_state = APDU_IDLE;
}
if ((!ledger_ble_data.connection_updated)
&& (ledger_ble_data.connection.conn_interval > BLE_SLAVE_CONN_INTERVAL_MIN)) {
ledger_ble_data.connection_updated = 1;
Expand Down Expand Up @@ -872,7 +887,19 @@ static void attribute_modified(const uint8_t *buffer, uint16_t length)
LOG_BLE("Transfer failed 0x%04x\n", U2BE(ledger_ble_data.resp, 0));
G_io_app.transfer_mode = 0;
check_transfer_mode(G_io_app.transfer_mode);
copy_apdu_to_app(true);
if (G_io_app.apdu_state == APDU_IDLE
&& io_apdu_is_media_accepted(IO_APDU_MEDIA_BLE)) {
copy_apdu_to_app(true);
}
else {
// Discard received APDU and respond with error
ledger_protocol_data.rx_apdu_length = 0;
ledger_protocol_data.rx_apdu_status = APDU_STATUS_WAITING;
uint8_t resp[2];
U2BE_ENCODE(resp, 0, SWO_IOL_STA_02);
LEDGER_PROTOCOL_tx(resp, 2);
notify_chunk();
}
}
else if (ledger_ble_data.resp_length) {
LEDGER_PROTOCOL_tx(ledger_ble_data.resp, ledger_ble_data.resp_length);
Expand All @@ -881,13 +908,26 @@ static void attribute_modified(const uint8_t *buffer, uint16_t length)
}
}
else {
copy_apdu_to_app(true);
// Nominal case for apdu reception
if (G_io_app.apdu_state == APDU_IDLE
&& io_apdu_is_media_accepted(IO_APDU_MEDIA_BLE)) {
copy_apdu_to_app(true);
}
else {
// Discard received APDU and respond with error
ledger_protocol_data.rx_apdu_length = 0;
ledger_protocol_data.rx_apdu_status = APDU_STATUS_WAITING;
uint8_t resp[2];
U2BE_ENCODE(resp, 0, SWO_IOL_STA_02);
LEDGER_PROTOCOL_tx(resp, 2);
notify_chunk();
}
}
}
else if (ledger_protocol_data.tx_chunk_length >= 2) {
// apdu not complete yet
G_io_app.ble_xfer_timeout = 2000;
notify_chunk();
G_io_app.apdu_state = APDU_BLE;
}
}
else {
Expand Down Expand Up @@ -917,7 +957,18 @@ static void write_permit_request(const uint8_t *buffer, uint16_t length)
data_length,
&buffer[3]);
if (ledger_protocol_data.rx_apdu_status == APDU_STATUS_COMPLETE) {
copy_apdu_to_app(true);
if (G_io_app.apdu_state == APDU_IDLE && io_apdu_is_media_accepted(IO_APDU_MEDIA_BLE)) {
copy_apdu_to_app(true);
}
else {
// Discard received APDU and respond with error
ledger_protocol_data.rx_apdu_length = 0;
ledger_protocol_data.rx_apdu_status = APDU_STATUS_WAITING;
uint8_t resp[2];
U2BE_ENCODE(resp, 0, SWO_IOL_STA_02);
LEDGER_PROTOCOL_tx(resp, 2);
notify_chunk();
}
}
}
else {
Expand Down Expand Up @@ -1040,7 +1091,9 @@ void LEDGER_BLE_set_recv_buffer(uint8_t *buffer, uint16_t buffer_length)
void LEDGER_BLE_send(const uint8_t *packet, uint16_t packet_length)
{
if ((ledger_ble_data.transfer_mode_enable != 0) && (packet_length == 2)) {
G_io_app.apdu_state = APDU_IDLE;
if (G_io_app.apdu_state == APDU_BLE) {
G_io_app.apdu_state = APDU_IDLE;
}
ledger_ble_data.resp_length = 2;
ledger_ble_data.resp[0] = packet[0];
ledger_ble_data.resp[1] = packet[1];
Expand Down
6 changes: 3 additions & 3 deletions lib_standard_app/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ WEAK uint8_t io_event(uint8_t channel)
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break;
case SEPROXYHAL_TAG_STATUS_EVENT:
if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && //
!(U4BE(G_io_seproxyhal_spi_buffer, 3) & //
SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID
&& !(U4BE(G_io_seproxyhal_spi_buffer, 3)
& SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
THROW(EXCEPTION_IO_RESET);
}
__attribute__((fallthrough));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ void CCID_BulkMessage_In (USBD_HandleTypeDef *pdev,
// not timeout compliant // USBD_LL_PrepareReceive(pdev, CCID_BULK_OUT_EP, CCID_BULK_EPOUT_SIZE);

// mark transfer as completed
G_io_app.apdu_state = APDU_IDLE;
if (G_io_app.apdu_state == APDU_USB_CCID){
G_io_app.apdu_state = APDU_IDLE;
}
}

// if remaining length is < EPIN_SIZE: send packet and prepare to receive a new command
Expand Down
22 changes: 20 additions & 2 deletions lib_stusb_impl/usbd_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,8 @@ uint8_t USBD_HID_DataOut_impl(USBD_HandleTypeDef *pdev,

#ifndef HAVE_USB_HIDKBD
// avoid troubles when an apdu has not been replied yet
if (G_io_app.apdu_media == IO_APDU_MEDIA_NONE) {
if (G_io_app.apdu_state == APDU_IDLE
&& io_apdu_is_media_accepted(IO_APDU_MEDIA_USB_HID)) {
// add to the hid transport
switch (io_usb_hid_receive(io_usb_send_apdu_data,
buffer,
Expand All @@ -1098,6 +1099,14 @@ uint8_t USBD_HID_DataOut_impl(USBD_HandleTypeDef *pdev,
break;
}
}
else {
if (io_usb_hid_discard(buffer, io_seproxyhal_get_ep_rx_size(HID_EPOUT_ADDR))) {
// Discarded new APDU, send error response
unsigned char resp_apdu[2] = {};
U2BE_ENCODE(resp_apdu, 0, SWO_IOL_STA_02);
io_usb_hid_send(io_usb_send_apdu_data, 2, resp_apdu);
}
}
#endif // HAVE_USB_HIDKBD
break;
}
Expand Down Expand Up @@ -1162,7 +1171,8 @@ uint8_t USBD_WEBUSB_DataOut(USBD_HandleTypeDef *pdev,
USBD_LL_PrepareReceive(pdev, WEBUSB_EPOUT_ADDR, WEBUSB_EPOUT_SIZE);

// avoid troubles when an apdu has not been replied yet
if (G_io_app.apdu_media == IO_APDU_MEDIA_NONE) {
if (G_io_app.apdu_state == APDU_IDLE
&& io_apdu_is_media_accepted(IO_APDU_MEDIA_USB_WEBUSB)) {
// add to the hid transport
switch (io_usb_hid_receive(io_usb_send_apdu_data_ep0x83,
buffer,
Expand All @@ -1178,6 +1188,14 @@ uint8_t USBD_WEBUSB_DataOut(USBD_HandleTypeDef *pdev,
break;
}
}
else {
if (io_usb_hid_discard(buffer, io_seproxyhal_get_ep_rx_size(WEBUSB_EPOUT_ADDR))) {
// Discarded new APDU, send error response
unsigned char resp_apdu[2] = {};
U2BE_ENCODE(resp_apdu, 0, SWO_IOL_STA_02);
io_usb_hid_send(io_usb_send_apdu_data_ep0x83, 2, resp_apdu);
}
}
break;
}

Expand Down
4 changes: 3 additions & 1 deletion lib_u2f/src/u2f_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ void u2f_transport_sent(u2f_service_t *service, u2f_transport_media_t media)
u2f_transport_reset(service);
// we sent the whole response (even if we haven't yet received the ack for the last sent usb
// in packet)
G_io_app.apdu_state = APDU_IDLE;
if (G_io_app.apdu_state == APDU_U2F) {
G_io_app.apdu_state = APDU_IDLE;
}
}
}

Expand Down
48 changes: 41 additions & 7 deletions src/os_io_seproxyhal.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ void io_usb_send_apdu_data_ep0x83(unsigned char *buffer, unsigned short length)

void io_seproxyhal_handle_capdu_event(void)
{
if (G_io_app.apdu_state == APDU_IDLE) {
if (G_io_app.apdu_state == APDU_IDLE && io_apdu_is_media_accepted(IO_APDU_MEDIA_RAW)) {
size_t max = MIN(sizeof(G_io_apdu_buffer) - 3, sizeof(G_io_seproxyhal_spi_buffer) - 3);
size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);

Expand All @@ -241,12 +241,20 @@ void io_seproxyhal_handle_capdu_event(void)
// copy apdu to apdu buffer
memcpy(G_io_apdu_buffer, G_io_seproxyhal_spi_buffer + 3, G_io_app.apdu_length);
}
else {
// Refuse APDU, send error reply
G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_RAPDU;
G_io_seproxyhal_spi_buffer[1] = 0;
G_io_seproxyhal_spi_buffer[2] = 2;
U2BE_ENCODE(G_io_seproxyhal_spi_buffer, 3, SWO_IOL_STA_02);
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 5);
}
}

#ifdef HAVE_NFC
void io_seproxyhal_handle_nfc_recv_event(void)
{
if (G_io_app.apdu_state == APDU_IDLE) {
if (G_io_app.apdu_state == APDU_IDLE && io_apdu_is_media_accepted(IO_APDU_MEDIA_NFC)) {
size_t max = MIN(sizeof(G_io_apdu_buffer), sizeof(G_io_seproxyhal_spi_buffer) - 3);
size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);

Expand All @@ -256,6 +264,14 @@ void io_seproxyhal_handle_nfc_recv_event(void)

memcpy(G_io_apdu_buffer, &G_io_seproxyhal_spi_buffer[3], G_io_app.apdu_length);
}
else {
// Refuse APDU, send error reply
G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_NFC_RAPDU;
G_io_seproxyhal_spi_buffer[1] = 0;
G_io_seproxyhal_spi_buffer[2] = 2;
U2BE_ENCODE(G_io_seproxyhal_spi_buffer, 3, SWO_IOL_STA_02);
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 5);
}
}
#endif
unsigned int io_seproxyhal_handle_event(void)
Expand Down Expand Up @@ -448,9 +464,10 @@ void io_seproxyhal_init(void)
G_io_app.plane_mode = plane;
#endif // HAVE_BLE

G_io_app.apdu_state = APDU_IDLE;
G_io_app.apdu_length = 0;
G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
G_io_app.apdu_state = APDU_IDLE;
G_io_app.apdu_length = 0;
G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
G_io_app.apdu_media_lock = IO_APDU_MEDIA_NONE;

G_io_app.ms = 0;

Expand All @@ -473,6 +490,22 @@ void io_seproxyhal_init(void)
#endif // !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
}

void io_apdu_media_lock(io_apdu_media_t media)
{
G_io_app.apdu_media_lock = media;
}
void io_apdu_media_unlock(void)
{
G_io_app.apdu_media_lock = IO_APDU_MEDIA_NONE;
}
bool io_apdu_is_media_accepted(io_apdu_media_t media)
{
if (G_io_app.apdu_media_lock == IO_APDU_MEDIA_NONE) {
return true;
}
return (G_io_app.apdu_media_lock == media);
}

#ifdef HAVE_PIEZO_SOUND
void io_seproxyhal_play_tune(tune_index_e tune_index)
{
Expand Down Expand Up @@ -1344,7 +1377,7 @@ unsigned short io_exchange(unsigned char channel, unsigned short tx_len)
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3);
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);

// isngle packet reply, mark immediate idle
// single packet reply, mark immediate idle
G_io_app.apdu_state = APDU_IDLE;
G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
goto break_send;
Expand All @@ -1361,8 +1394,9 @@ unsigned short io_exchange(unsigned char channel, unsigned short tx_len)
io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3);
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);

// isngle packet reply, mark immediate idle
// single packet reply, mark immediate idle
G_io_app.apdu_state = APDU_IDLE;
G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
// finished, no chunking
goto break_send;

Expand Down