diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f44eb5c..f6775ff57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - Seader: Remove some optional asn1 fields (by @bettse) - NFC Playlist: Fix extension check and error messages (by @acegoal07) - Various app fixes for `-Wundef` option (by @Willy-JL) +- OFW: NFC: Refactor detected protocols list (by @Astrrra) +- OFW: CCID: App refactor (by @kidbomb) - OFW: Furi: Update string documentation (by @skotopes) - OFW: FBT: Toolchain v39 (by @hedger) diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index 46a1237f9..abb8ad3dd 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -6,10 +6,13 @@ #include #include #include -#include "iso7816_callbacks.h" -#include "iso7816_t0_apdu.h" -#include "iso7816_atr.h" -#include "iso7816_response.h" + +#include "iso7816/iso7816_handler.h" +#include "iso7816/iso7816_t0_apdu.h" +#include "iso7816/iso7816_atr.h" +#include "iso7816/iso7816_response.h" + +#include "ccid_test_app_commands.h" typedef enum { EventTypeInput, @@ -20,6 +23,7 @@ typedef struct { ViewPort* view_port; FuriMessageQueue* event_queue; FuriHalUsbCcidConfig ccid_cfg; + Iso7816Handler* iso7816_handler; } CcidTestApp; typedef struct { @@ -63,6 +67,15 @@ uint32_t ccid_test_exit(void* context) { CcidTestApp* ccid_test_app_alloc(void) { CcidTestApp* app = malloc(sizeof(CcidTestApp)); + //setup CCID USB + // On linux: set VID PID using: /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist + app->ccid_cfg.vid = 0x076B; + app->ccid_cfg.pid = 0x3A21; + + app->iso7816_handler = iso7816_handler_alloc(); + app->iso7816_handler->iso7816_answer_to_reset = iso7816_answer_to_reset; + app->iso7816_handler->iso7816_process_command = iso7816_process_command; + // Gui app->gui = furi_record_open(RECORD_GUI); @@ -92,174 +105,26 @@ void ccid_test_app_free(CcidTestApp* app) { furi_record_close(RECORD_GUI); app->gui = NULL; + free(app->iso7816_handler); + // Free rest free(app); } -void ccid_icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen, void* context) { - UNUSED(context); - - iso7816_icc_power_on_callback(atrBuffer, atrlen); -} - -void ccid_xfr_datablock_callback( - const uint8_t* pcToReaderDataBlock, - uint32_t pcToReaderDataBlockLen, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen, - void* context) { - UNUSED(context); - - iso7816_xfr_datablock_callback( - pcToReaderDataBlock, pcToReaderDataBlockLen, readerToPcDataBlock, readerToPcDataBlockLen); -} - -static const CcidCallbacks ccid_cb = { - ccid_icc_power_on_callback, - ccid_xfr_datablock_callback, -}; - -//Instruction 1: returns an OK response unconditionally -//APDU example: 0x01:0x01:0x00:0x00 -//response: SW1=0x90, SW2=0x00 -void handle_instruction_01(ISO7816_Response_APDU* responseAPDU) { - responseAPDU->DataLen = 0; - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); -} - -//Instruction 2: expect command with no body, replies wit with a body with two bytes -//APDU example: 0x01:0x02:0x00:0x00:0x02 -//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00 -void handle_instruction_02( - uint8_t p1, - uint8_t p2, - uint16_t lc, - uint16_t le, - ISO7816_Response_APDU* responseAPDU) { - if(p1 == 0 && p2 == 0 && lc == 0 && le >= 2) { - responseAPDU->Data[0] = 0x62; - responseAPDU->Data[1] = 0x63; - - responseAPDU->DataLen = 2; - - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); - } else if(p1 != 0 || p2 != 0) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } -} - -//Instruction 3: sends a command with a body with two bytes, receives a response with no bytes -//APDU example: 0x01:0x03:0x00:0x00:0x02:CA:FE -//response SW1=0x90, SW2=0x00 -void handle_instruction_03( - uint8_t p1, - uint8_t p2, - uint16_t lc, - ISO7816_Response_APDU* responseAPDU) { - if(p1 == 0 && p2 == 0 && lc == 2) { - responseAPDU->DataLen = 0; - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); - } else if(p1 != 0 || p2 != 0) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } -} - -//instruction 4: sends a command with a body with 'n' bytes, receives a response with 'n' bytes -//APDU example: 0x01:0x04:0x00:0x00:0x04:0x01:0x02:0x03:0x04:0x04 -//receives (0x01, 0x02, 0x03, 0x04) SW1=0x90, SW2=0x00 -void handle_instruction_04( - uint8_t p1, - uint8_t p2, - uint16_t lc, - uint16_t le, - const uint8_t* commandApduDataBuffer, - ISO7816_Response_APDU* responseAPDU) { - if(p1 == 0 && p2 == 0 && lc > 0 && le > 0 && le >= lc) { - for(uint16_t i = 0; i < lc; i++) { - responseAPDU->Data[i] = commandApduDataBuffer[i]; - } - - responseAPDU->DataLen = lc; - - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK); - } else if(p1 != 0 || p2 != 0) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } -} - -void iso7816_answer_to_reset(Iso7816Atr* atr) { - //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00 - atr->TS = 0x3B; - atr->T0 = 0x00; -} - -void iso7816_process_command( - const ISO7816_Command_APDU* commandAPDU, - ISO7816_Response_APDU* responseAPDU) { - //example 1: sends a command with no body, receives a response with no body - //sends APDU 0x01:0x01:0x00:0x00 - //receives SW1=0x90, SW2=0x00 - - if(commandAPDU->CLA == 0x01) { - switch(commandAPDU->INS) { - case 0x01: - handle_instruction_01(responseAPDU); - break; - case 0x02: - handle_instruction_02( - commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU); - break; - case 0x03: - handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU); - break; - case 0x04: - handle_instruction_04( - commandAPDU->P1, - commandAPDU->P2, - commandAPDU->Lc, - commandAPDU->Le, - commandAPDU->Data, - responseAPDU); - break; - default: - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED); - } - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED); - } -} - -static const Iso7816Callbacks iso87816_cb = { - iso7816_answer_to_reset, - iso7816_process_command, -}; - int32_t ccid_test_app(void* p) { UNUSED(p); //setup view CcidTestApp* app = ccid_test_app_alloc(); - //setup CCID USB - // On linux: set VID PID using: /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist - app->ccid_cfg.vid = 0x076B; - app->ccid_cfg.pid = 0x3A21; - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); furi_check(furi_hal_usb_set_config(&usb_ccid, &app->ccid_cfg) == true); - furi_hal_usb_ccid_set_callbacks((CcidCallbacks*)&ccid_cb, NULL); + furi_hal_usb_ccid_set_callbacks( + (CcidCallbacks*)&app->iso7816_handler->ccid_callbacks, app->iso7816_handler); furi_hal_usb_ccid_insert_smartcard(); - iso7816_set_callbacks((Iso7816Callbacks*)&iso87816_cb); - //handle button events CcidTestAppEvent event; while(1) { @@ -280,8 +145,6 @@ int32_t ccid_test_app(void* p) { furi_hal_usb_ccid_set_callbacks(NULL, NULL); furi_hal_usb_set_config(usb_mode_prev, NULL); - iso7816_set_callbacks(NULL); - //teardown view ccid_test_app_free(app); return 0; diff --git a/applications/debug/ccid_test/ccid_test_app_commands.c b/applications/debug/ccid_test/ccid_test_app_commands.c new file mode 100644 index 000000000..1daaa70c3 --- /dev/null +++ b/applications/debug/ccid_test/ccid_test_app_commands.c @@ -0,0 +1,123 @@ +#include "iso7816/iso7816_t0_apdu.h" +#include "iso7816/iso7816_response.h" + +//Instruction 1: returns an OK response unconditionally +//APDU example: 0x01:0x01:0x00:0x00 +//response: SW1=0x90, SW2=0x00 +void handle_instruction_01(ISO7816_Response_APDU* response_apdu) { + response_apdu->DataLen = 0; + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); +} + +//Instruction 2: expect command with no body, replies wit with a body with two bytes +//APDU example: 0x01:0x02:0x00:0x00:0x02 +//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00 +void handle_instruction_02( + uint8_t p1, + uint8_t p2, + uint16_t lc, + uint16_t le, + ISO7816_Response_APDU* response_apdu) { + if(p1 == 0 && p2 == 0 && lc == 0 && le >= 2) { + response_apdu->Data[0] = 0x62; + response_apdu->Data[1] = 0x63; + + response_apdu->DataLen = 2; + + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); + } else if(p1 != 0 || p2 != 0) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } +} + +//Instruction 3: sends a command with a body with two bytes, receives a response with no bytes +//APDU example: 0x01:0x03:0x00:0x00:0x02:CA:FE +//response SW1=0x90, SW2=0x00 +void handle_instruction_03( + uint8_t p1, + uint8_t p2, + uint16_t lc, + ISO7816_Response_APDU* response_apdu) { + if(p1 == 0 && p2 == 0 && lc == 2) { + response_apdu->DataLen = 0; + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); + } else if(p1 != 0 || p2 != 0) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } +} + +//instruction 4: sends a command with a body with 'n' bytes, receives a response with 'n' bytes +//APDU example: 0x01:0x04:0x00:0x00:0x04:0x01:0x02:0x03:0x04:0x04 +//receives (0x01, 0x02, 0x03, 0x04) SW1=0x90, SW2=0x00 +void handle_instruction_04( + uint8_t p1, + uint8_t p2, + uint16_t lc, + uint16_t le, + const uint8_t* command_apdu_data_buffer, + ISO7816_Response_APDU* response_apdu) { + if(p1 == 0 && p2 == 0 && lc > 0 && le > 0 && le >= lc) { + for(uint16_t i = 0; i < lc; i++) { + response_apdu->Data[i] = command_apdu_data_buffer[i]; + } + + response_apdu->DataLen = lc; + + iso7816_set_response(response_apdu, ISO7816_RESPONSE_OK); + } else if(p1 != 0 || p2 != 0) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2); + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } +} + +void iso7816_answer_to_reset(Iso7816Atr* atr) { + //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00 + atr->TS = 0x3B; + atr->T0 = 0x00; +} + +void iso7816_process_command( + const ISO7816_Command_APDU* command_apdu, + ISO7816_Response_APDU* response_apdu) { + //example 1: sends a command with no body, receives a response with no body + //sends APDU 0x01:0x01:0x00:0x00 + //receives SW1=0x90, SW2=0x00 + + if(command_apdu->CLA == 0x01) { + switch(command_apdu->INS) { + case 0x01: + handle_instruction_01(response_apdu); + break; + case 0x02: + handle_instruction_02( + command_apdu->P1, + command_apdu->P2, + command_apdu->Lc, + command_apdu->Le, + response_apdu); + break; + case 0x03: + handle_instruction_03( + command_apdu->P1, command_apdu->P2, command_apdu->Lc, response_apdu); + break; + case 0x04: + handle_instruction_04( + command_apdu->P1, + command_apdu->P2, + command_apdu->Lc, + command_apdu->Le, + command_apdu->Data, + response_apdu); + break; + default: + iso7816_set_response(response_apdu, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED); + } + } else { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED); + } +} diff --git a/applications/debug/ccid_test/ccid_test_app_commands.h b/applications/debug/ccid_test/ccid_test_app_commands.h new file mode 100644 index 000000000..ca3275aec --- /dev/null +++ b/applications/debug/ccid_test/ccid_test_app_commands.h @@ -0,0 +1,7 @@ +#include "iso7816/iso7816_t0_apdu.h" + +void iso7816_answer_to_reset(Iso7816Atr* atr); + +void iso7816_process_command( + const ISO7816_Command_APDU* command_apdu, + ISO7816_Response_APDU* response_apdu); diff --git a/applications/debug/ccid_test/iso7816_atr.h b/applications/debug/ccid_test/iso7816/iso7816_atr.h similarity index 100% rename from applications/debug/ccid_test/iso7816_atr.h rename to applications/debug/ccid_test/iso7816/iso7816_atr.h diff --git a/applications/debug/ccid_test/iso7816/iso7816_handler.c b/applications/debug/ccid_test/iso7816/iso7816_handler.c new file mode 100644 index 000000000..97214d1b2 --- /dev/null +++ b/applications/debug/ccid_test/iso7816/iso7816_handler.c @@ -0,0 +1,68 @@ +// transforms low level calls such as XFRCallback or ICC Power on to a structured one +// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks + +#include +#include +#include +#include + +#include "iso7816_t0_apdu.h" +#include "iso7816_atr.h" +#include "iso7816_handler.h" +#include "iso7816_response.h" + +void iso7816_icc_power_on_callback(uint8_t* atr_data, uint32_t* atr_data_len, void* context) { + furi_check(context); + + Iso7816Handler* handler = (Iso7816Handler*)context; + + Iso7816Atr iso7816_atr; + handler->iso7816_answer_to_reset(&iso7816_atr); + + furi_assert(iso7816_atr.T0 == 0x00); + + uint8_t atr_buffer[2] = {iso7816_atr.TS, iso7816_atr.T0}; + + *atr_data_len = 2; + + memcpy(atr_data, atr_buffer, sizeof(uint8_t) * (*atr_data_len)); +} + +//dataBlock points to the buffer +//dataBlockLen tells reader how nany bytes should be read +void iso7816_xfr_datablock_callback( + const uint8_t* pc_to_reader_datablock, + uint32_t pc_to_reader_datablock_len, + uint8_t* reader_to_pc_datablock, + uint32_t* reader_to_pc_datablock_len, + void* context) { + furi_check(context); + + Iso7816Handler* handler = (Iso7816Handler*)context; + + ISO7816_Response_APDU* response_apdu = (ISO7816_Response_APDU*)&handler->response_apdu_buffer; + + ISO7816_Command_APDU* command_apdu = (ISO7816_Command_APDU*)&handler->command_apdu_buffer; + + uint8_t result = iso7816_read_command_apdu( + command_apdu, pc_to_reader_datablock, pc_to_reader_datablock_len); + + if(result == ISO7816_READ_COMMAND_APDU_OK) { + handler->iso7816_process_command(command_apdu, response_apdu); + + furi_assert(response_apdu->DataLen < CCID_SHORT_APDU_SIZE); + } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LE); + } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) { + iso7816_set_response(response_apdu, ISO7816_RESPONSE_WRONG_LENGTH); + } + + iso7816_write_response_apdu(response_apdu, reader_to_pc_datablock, reader_to_pc_datablock_len); +} + +Iso7816Handler* iso7816_handler_alloc() { + Iso7816Handler* handler = malloc(sizeof(Iso7816Handler)); + handler->ccid_callbacks.icc_power_on_callback = iso7816_icc_power_on_callback; + handler->ccid_callbacks.xfr_datablock_callback = iso7816_xfr_datablock_callback; + return handler; +} diff --git a/applications/debug/ccid_test/iso7816/iso7816_handler.h b/applications/debug/ccid_test/iso7816/iso7816_handler.h new file mode 100644 index 000000000..d67118ce6 --- /dev/null +++ b/applications/debug/ccid_test/iso7816/iso7816_handler.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "iso7816_atr.h" +#include "iso7816_t0_apdu.h" + +typedef struct { + CcidCallbacks ccid_callbacks; + void (*iso7816_answer_to_reset)(Iso7816Atr* atr); + void (*iso7816_process_command)( + const ISO7816_Command_APDU* command, + ISO7816_Response_APDU* response); + + uint8_t command_apdu_buffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE]; + uint8_t response_apdu_buffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE]; +} Iso7816Handler; + +Iso7816Handler* iso7816_handler_alloc(); diff --git a/applications/debug/ccid_test/iso7816_response.c b/applications/debug/ccid_test/iso7816/iso7816_response.c similarity index 100% rename from applications/debug/ccid_test/iso7816_response.c rename to applications/debug/ccid_test/iso7816/iso7816_response.c diff --git a/applications/debug/ccid_test/iso7816_response.h b/applications/debug/ccid_test/iso7816/iso7816_response.h similarity index 100% rename from applications/debug/ccid_test/iso7816_response.h rename to applications/debug/ccid_test/iso7816/iso7816_response.h diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.c b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c similarity index 85% rename from applications/debug/ccid_test/iso7816_t0_apdu.c rename to applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c index 3de5555f4..216f2582f 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.c +++ b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.c @@ -61,24 +61,25 @@ uint8_t iso7816_read_command_apdu( //data buffer contains the whole APU response (response + trailer (SW1+SW2)) void iso7816_write_response_apdu( const ISO7816_Response_APDU* response, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen) { + uint8_t* reader_to_pc_datablock, + uint32_t* reader_to_pc_datablock_len) { uint32_t responseDataBufferIndex = 0; //response body if(response->DataLen > 0) { while(responseDataBufferIndex < response->DataLen) { - readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex]; + reader_to_pc_datablock[responseDataBufferIndex] = + response->Data[responseDataBufferIndex]; responseDataBufferIndex++; } } //trailer - readerToPcDataBlock[responseDataBufferIndex] = response->SW1; + reader_to_pc_datablock[responseDataBufferIndex] = response->SW1; responseDataBufferIndex++; - readerToPcDataBlock[responseDataBufferIndex] = response->SW2; + reader_to_pc_datablock[responseDataBufferIndex] = response->SW2; responseDataBufferIndex++; - *readerToPcDataBlockLen = responseDataBufferIndex; + *reader_to_pc_datablock_len = responseDataBufferIndex; } diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h similarity index 81% rename from applications/debug/ccid_test/iso7816_t0_apdu.h rename to applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h index 50eb476a9..a21dfbafc 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816/iso7816_t0_apdu.h @@ -31,12 +31,11 @@ typedef struct { uint8_t Data[0]; } FURI_PACKED ISO7816_Response_APDU; -void iso7816_answer_to_reset(Iso7816Atr* atr); uint8_t iso7816_read_command_apdu( ISO7816_Command_APDU* command, - const uint8_t* pcToReaderDataBlock, - uint32_t pcToReaderDataBlockLen); + const uint8_t* pc_to_reader_datablock, + uint32_t pc_to_reader_datablock_len); void iso7816_write_response_apdu( const ISO7816_Response_APDU* response, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen); + uint8_t* reader_to_pc_datablock, + uint32_t* reader_to_pc_datablock_len); diff --git a/applications/debug/ccid_test/iso7816_callbacks.c b/applications/debug/ccid_test/iso7816_callbacks.c deleted file mode 100644 index 6c1bb106a..000000000 --- a/applications/debug/ccid_test/iso7816_callbacks.c +++ /dev/null @@ -1,65 +0,0 @@ -// transforms low level calls such as XFRCallback or ICC Power on to a structured one -// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks - -#include -#include -#include -#include - -#include "iso7816_t0_apdu.h" -#include "iso7816_atr.h" -#include "iso7816_callbacks.h" -#include "iso7816_response.h" - -static Iso7816Callbacks* callbacks = NULL; - -static uint8_t commandApduBuffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE]; -static uint8_t responseApduBuffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE]; - -void iso7816_set_callbacks(Iso7816Callbacks* cb) { - callbacks = cb; -} - -void iso7816_icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen) { - Iso7816Atr atr; - callbacks->iso7816_answer_to_reset(&atr); - - furi_assert(atr.T0 == 0x00); - - uint8_t AtrBuffer[2] = {atr.TS, atr.T0}; - - *atrlen = 2; - - memcpy(atrBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen)); -} - -//dataBlock points to the buffer -//dataBlockLen tells reader how nany bytes should be read -void iso7816_xfr_datablock_callback( - const uint8_t* pcToReaderDataBlock, - uint32_t pcToReaderDataBlockLen, - uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen) { - ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer; - - if(callbacks != NULL) { - ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer; - - uint8_t result = - iso7816_read_command_apdu(commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen); - - if(result == ISO7816_READ_COMMAND_APDU_OK) { - callbacks->iso7816_process_command(commandAPDU, responseAPDU); - - furi_assert(responseAPDU->DataLen < CCID_SHORT_APDU_SIZE); - } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LE); - } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH); - } - } else { - iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION); - } - - iso7816_write_response_apdu(responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen); -} diff --git a/applications/debug/ccid_test/iso7816_callbacks.h b/applications/debug/ccid_test/iso7816_callbacks.h deleted file mode 100644 index 6b408c7f5..000000000 --- a/applications/debug/ccid_test/iso7816_callbacks.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include "iso7816_atr.h" -#include "iso7816_t0_apdu.h" - -typedef struct { - void (*iso7816_answer_to_reset)(Iso7816Atr* atr); - void (*iso7816_process_command)( - const ISO7816_Command_APDU* command, - ISO7816_Response_APDU* response); -} Iso7816Callbacks; - -void iso7816_set_callbacks(Iso7816Callbacks* cb); - -void iso7816_icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen); -void iso7816_xfr_datablock_callback( - const uint8_t* dataBlock, - uint32_t dataBlockLen, - uint8_t* responseDataBlock, - uint32_t* responseDataBlockLen); diff --git a/applications/main/nfc/helpers/nfc_detected_protocols.c b/applications/main/nfc/helpers/nfc_detected_protocols.c new file mode 100644 index 000000000..339d4ddc2 --- /dev/null +++ b/applications/main/nfc/helpers/nfc_detected_protocols.c @@ -0,0 +1,85 @@ +#include "nfc_detected_protocols.h" + +#include + +struct NfcDetectedProtocols { + uint32_t protocols_detected_num; + NfcProtocol protocols_detected[NfcProtocolNum]; + uint32_t selected_idx; +}; + +NfcDetectedProtocols* nfc_detected_protocols_alloc(void) { + NfcDetectedProtocols* instance = malloc(sizeof(NfcDetectedProtocols)); + + instance->protocols_detected_num = 0; + instance->selected_idx = 0; + + return instance; +} + +void nfc_detected_protocols_free(NfcDetectedProtocols* instance) { + furi_assert(instance); + + free(instance); +} + +void nfc_detected_protocols_reset(NfcDetectedProtocols* instance) { + furi_assert(instance); + + instance->protocols_detected_num = 0; + memset(instance->protocols_detected, 0, sizeof(instance->protocols_detected)); + instance->selected_idx = 0; +} + +void nfc_detected_protocols_select(NfcDetectedProtocols* instance, uint32_t idx) { + furi_assert(instance); + + instance->selected_idx = idx; +} + +void nfc_detected_protocols_set( + NfcDetectedProtocols* instance, + const NfcProtocol* types, + uint32_t count) { + furi_assert(instance); + furi_assert(types); + furi_assert(count < NfcProtocolNum); + + memcpy(instance->protocols_detected, types, count); + instance->protocols_detected_num = count; + instance->selected_idx = 0; +} + +uint32_t nfc_detected_protocols_get_num(NfcDetectedProtocols* instance) { + furi_assert(instance); + + return instance->protocols_detected_num; +} + +NfcProtocol nfc_detected_protocols_get_protocol(NfcDetectedProtocols* instance, uint32_t idx) { + furi_assert(instance); + furi_assert(idx < instance->protocols_detected_num); + + return instance->protocols_detected[idx]; +} + +void nfc_detected_protocols_fill_all_protocols(NfcDetectedProtocols* instance) { + furi_assert(instance); + + instance->protocols_detected_num = NfcProtocolNum; + for(uint32_t i = 0; i < NfcProtocolNum; i++) { + instance->protocols_detected[i] = i; + } +} + +NfcProtocol nfc_detected_protocols_get_selected(NfcDetectedProtocols* instance) { + furi_assert(instance); + + return instance->protocols_detected[instance->selected_idx]; +} + +uint32_t nfc_detected_protocols_get_selected_idx(NfcDetectedProtocols* instance) { + furi_assert(instance); + + return instance->selected_idx; +} diff --git a/applications/main/nfc/helpers/nfc_detected_protocols.h b/applications/main/nfc/helpers/nfc_detected_protocols.h new file mode 100644 index 000000000..2ab46add3 --- /dev/null +++ b/applications/main/nfc/helpers/nfc_detected_protocols.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +typedef struct NfcDetectedProtocols NfcDetectedProtocols; + +NfcDetectedProtocols* nfc_detected_protocols_alloc(void); + +void nfc_detected_protocols_free(NfcDetectedProtocols* instance); + +void nfc_detected_protocols_reset(NfcDetectedProtocols* instance); + +void nfc_detected_protocols_select(NfcDetectedProtocols* instance, uint32_t idx); + +void nfc_detected_protocols_set( + NfcDetectedProtocols* instance, + const NfcProtocol* types, + uint32_t count); + +uint32_t nfc_detected_protocols_get_num(NfcDetectedProtocols* instance); + +NfcProtocol nfc_detected_protocols_get_protocol(NfcDetectedProtocols* instance, uint32_t idx); + +void nfc_detected_protocols_fill_all_protocols(NfcDetectedProtocols* instance); + +NfcProtocol nfc_detected_protocols_get_selected(NfcDetectedProtocols* instance); + +uint32_t nfc_detected_protocols_get_selected_idx(NfcDetectedProtocols* instance); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 7e0ff1b90..072e8d7ef 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -150,8 +150,7 @@ static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - const NfcProtocol protocol = - instance->protocols_detected[instance->protocols_detected_selected_idx]; + const NfcProtocol protocol = nfc_detected_protocols_get_selected(instance->detected_protocols); instance->poller = nfc_poller_alloc(instance->nfc, protocol); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); @@ -186,7 +185,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana consumed = true; } else { const NfcProtocol protocol = - instance->protocols_detected[instance->protocols_detected_selected_idx]; + nfc_detected_protocols_get_selected(instance->detected_protocols); consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event); } } else if(event.event == NfcCustomEventPollerFailure) { @@ -199,7 +198,7 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana consumed = true; } else if(event.event == NfcCustomEventCardDetected) { const NfcProtocol protocol = - instance->protocols_detected[instance->protocols_detected_selected_idx]; + nfc_detected_protocols_get_selected(instance->detected_protocols); consumed = nfc_protocol_support[protocol]->scene_read.on_event(instance, event); } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index b93b9ab5d..483d63c14 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -51,6 +51,7 @@ NfcApp* nfc_app_alloc(void) { instance->nfc = nfc_alloc(); + instance->detected_protocols = nfc_detected_protocols_alloc(); instance->felica_auth = felica_auth_alloc(); instance->mf_ul_auth = mf_ultralight_auth_alloc(); instance->slix_unlock = slix_unlock_alloc(); @@ -143,6 +144,7 @@ void nfc_app_free(NfcApp* instance) { nfc_free(instance->nfc); + nfc_detected_protocols_free(instance->detected_protocols); felica_auth_free(instance->felica_auth); mf_ultralight_auth_free(instance->mf_ul_auth); slix_unlock_free(instance->slix_unlock); @@ -434,23 +436,6 @@ void nfc_show_loading_popup(void* context, bool show) { } } -void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count) { - furi_assert(instance); - furi_assert(types); - furi_assert(count < NfcProtocolNum); - - memcpy(instance->protocols_detected, types, count); - instance->protocols_detected_num = count; - instance->protocols_detected_selected_idx = 0; -} - -void nfc_app_reset_detected_protocols(NfcApp* instance) { - furi_assert(instance); - - instance->protocols_detected_selected_idx = 0; - instance->protocols_detected_num = 0; -} - void nfc_append_filename_string_when_present(NfcApp* instance, FuriString* string) { furi_assert(instance); furi_assert(string); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index a1c136f22..62917ad1d 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -26,6 +26,7 @@ #include "views/dict_attack.h" #include +#include "helpers/nfc_detected_protocols.h" #include "helpers/nfc_custom_event.h" #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_user_dict.h" @@ -107,9 +108,7 @@ struct NfcApp { FuriString* text_box_store; uint8_t byte_input_store[NFC_BYTE_INPUT_STORE_SIZE]; - uint32_t protocols_detected_num; - NfcProtocol protocols_detected[NfcProtocolNum]; - uint32_t protocols_detected_selected_idx; + NfcDetectedProtocols* detected_protocols; RpcAppSystem* rpc_ctx; NfcRpcState rpc_state; @@ -196,8 +195,4 @@ bool nfc_save_file(NfcApp* instance, FuriString* path); void nfc_make_app_folder(NfcApp* instance); -void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count); - -void nfc_app_reset_detected_protocols(NfcApp* instance); - void nfc_append_filename_string_when_present(NfcApp* instance, FuriString* string); diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 3ef153657..7ef3f9d87 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -7,7 +7,8 @@ void nfc_scene_detect_scan_callback(NfcScannerEvent event, void* context) { NfcApp* instance = context; if(event.type == NfcScannerEventTypeDetected) { - nfc_app_set_detected_protocols(instance, event.data.protocols, event.data.protocol_num); + nfc_detected_protocols_set( + instance->detected_protocols, event.data.protocols, event.data.protocol_num); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWorkerExit); } } @@ -23,7 +24,7 @@ void nfc_scene_detect_on_enter(void* context) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - nfc_app_reset_detected_protocols(instance); + nfc_detected_protocols_reset(instance->detected_protocols); instance->scanner = nfc_scanner_alloc(instance->nfc); nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance); @@ -37,7 +38,7 @@ bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { - if(instance->protocols_detected_num > 1) { + if(nfc_detected_protocols_get_num(instance->detected_protocols) > 1) { notification_message(instance->notifications, &sequence_single_vibro); scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 4df8a6289..a0b6986d1 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -57,7 +57,8 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; - nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); + nfc_detected_protocols_set( + nfc->detected_protocols, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; @@ -77,7 +78,8 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; - nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); + nfc_detected_protocols_set( + nfc->detected_protocols, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index af644035e..f2c92b631 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -14,21 +14,19 @@ void nfc_scene_select_protocol_on_enter(void* context) { const char* prefix; if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneExtraActions)) { prefix = "Read"; - instance->protocols_detected_num = NfcProtocolNum; - for(uint32_t i = 0; i < NfcProtocolNum; i++) { - instance->protocols_detected[i] = i; - } + nfc_detected_protocols_fill_all_protocols(instance->detected_protocols); } else { prefix = "Read as"; submenu_set_header(submenu, "Multi-protocol card"); } - for(uint32_t i = 0; i < instance->protocols_detected_num; i++) { + for(uint32_t i = 0; i < nfc_detected_protocols_get_num(instance->detected_protocols); i++) { furi_string_printf( temp_str, "%s %s", prefix, - nfc_device_get_protocol_name(instance->protocols_detected[i])); + nfc_device_get_protocol_name( + nfc_detected_protocols_get_protocol(instance->detected_protocols, i))); furi_string_replace_str(temp_str, "Mifare", "MIFARE"); submenu_add_item( @@ -40,9 +38,8 @@ void nfc_scene_select_protocol_on_enter(void* context) { } furi_string_free(temp_str); - const uint32_t state = - scene_manager_get_scene_state(instance->scene_manager, NfcSceneSelectProtocol); - submenu_set_selected_item(submenu, state); + submenu_set_selected_item( + submenu, nfc_detected_protocols_get_selected_idx(instance->detected_protocols)); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } @@ -52,10 +49,8 @@ bool nfc_scene_select_protocol_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - instance->protocols_detected_selected_idx = event.event; + nfc_detected_protocols_select(instance->detected_protocols, event.event); scene_manager_next_scene(instance->scene_manager, NfcSceneRead); - scene_manager_set_scene_state( - instance->scene_manager, NfcSceneSelectProtocol, event.event); consumed = true; } else if(event.type == SceneManagerEventTypeBack) { if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 48c5759a5..70f726acf 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -25,7 +25,7 @@ void nfc_scene_start_on_enter(void* context) { nfc_device_clear(nfc->nfc_device); iso14443_3a_reset(nfc->iso14443_3a_edit_data); // Reset detected protocols list - nfc_app_reset_detected_protocols(nfc); + nfc_detected_protocols_reset(nfc->detected_protocols); submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); submenu_add_item(