From 27ed83643806f0914c3752582c3ffd3c7fae7c12 Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Fri, 3 May 2024 09:57:18 -0500 Subject: [PATCH 1/3] Add initial ISO7816 support --- applications/debug/ccid_test/ccid_test_app.c | 124 +++++++++++++----- applications/debug/ccid_test/iso7816_atr.h | 9 ++ .../debug/ccid_test/iso7816_callbacks.c | 71 ++++++++++ .../debug/ccid_test/iso7816_callbacks.h | 28 ++++ .../debug/ccid_test/iso7816_t0_apdu.c | 45 ++++--- .../debug/ccid_test/iso7816_t0_apdu.h | 10 +- targets/f7/api_symbols.csv | 2 +- targets/f7/furi_hal/furi_hal_usb_ccid.c | 8 +- targets/furi_hal_include/furi_hal_usb_ccid.h | 10 +- 9 files changed, 245 insertions(+), 62 deletions(-) create mode 100644 applications/debug/ccid_test/iso7816_atr.h create mode 100644 applications/debug/ccid_test/iso7816_callbacks.c create mode 100644 applications/debug/ccid_test/iso7816_callbacks.h diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index 50b356696c5..71e90dc785c 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -6,8 +6,9 @@ #include #include #include - +#include "iso7816_callbacks.h" #include "iso7816_t0_apdu.h" +#include "iso7816_atr.h" typedef enum { EventTypeInput, @@ -33,37 +34,6 @@ typedef enum { CcidTestSubmenuIndexInsertSmartcardReader } SubmenuIndex; -void icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen, void* context) { - UNUSED(context); - - iso7816_answer_to_reset(atrBuffer, atrlen); -} - -//dataBlock points to the buffer -//dataBlockLen tells reader how nany bytes should be read -void xfr_datablock_callback( - const uint8_t* dataBlock, - uint32_t dataBlockLen, - uint8_t* responseDataBlock, - uint32_t* responseDataBlockLen, - void* context) { - UNUSED(context); - - struct ISO7816_Command_APDU commandAPDU; - iso7816_read_command_apdu(&commandAPDU, dataBlock, dataBlockLen); - - struct ISO7816_Response_APDU responseAPDU; - //class not supported - responseAPDU.SW1 = 0x6E; - responseAPDU.SW2 = 0x00; - - iso7816_write_response_apdu(&responseAPDU, responseDataBlock, responseDataBlockLen); -} - -static const CcidCallbacks ccid_cb = { - icc_power_on_callback, - xfr_datablock_callback, -}; static void ccid_test_app_render_callback(Canvas* canvas, void* ctx) { UNUSED(ctx); @@ -127,6 +97,88 @@ void ccid_test_app_free(CcidTestApp* app) { 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, +}; + +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 struct ISO7816_Command_APDU* commandAPDU, + struct ISO7816_Response_APDU* responseAPDU, + const uint8_t* commandApduDataBuffer, + uint8_t commandApduDataBufferLen, + uint8_t* responseApduDataBuffer, + uint8_t* responseApduDataBufferLen) { + + //example 1: sends a command with no body, receives a response with no body + //sends APDU 0x01:0x02:0x00:0x00 + //receives SW1=0x90, SW2=0x00 + if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) { + responseAPDU->SW1=0x90; + responseAPDU->SW2=0x00; + } + //example 2: sends a command with no body, receives a response with a body with two bytes + //sends APDU 0x01:0x02:0x00:0x00 + //receives 'bc' (0x62, 0x63) SW1=0x80, SW2=0x10 + else if (commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x02) { + + responseApduDataBuffer[0] = 0x62; + responseApduDataBuffer[1] = 0x63; + + *responseApduDataBufferLen = 2; + + responseAPDU->SW1=0x90; + responseAPDU->SW2=0x00; + } + //example 3: ends a command with a body with two bytes, receives a response with a body with two bytes + //sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE + //receives (0xCA, 0xFE) SW1=0x90, SW2=0x02 + else if (commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 && commandAPDU->Lc == 2) { + + //echo command body to response body + responseApduDataBuffer[0] = commandApduDataBuffer[0]; + responseApduDataBuffer[1] = commandApduDataBuffer[1]; + + *responseApduDataBufferLen = 2; + + responseAPDU->SW1=0x90; + responseAPDU->SW2=0x00; + } else { + responseAPDU->SW1=0x6A; + responseAPDU->SW2=0x00; + } +} + +static const Iso7816Callbacks iso87816_cb = { + iso7816_answer_to_reset, + iso7816_process_command, +}; + + int32_t ccid_test_app(void* p) { UNUSED(p); @@ -140,9 +192,11 @@ int32_t ccid_test_app(void* p) { FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); - furi_hal_ccid_set_callbacks((CcidCallbacks*)&ccid_cb); + furi_hal_ccid_set_callbacks((CcidCallbacks*)&ccid_cb, NULL); furi_check(furi_hal_usb_set_config(&usb_ccid, &app->ccid_cfg) == true); + iso7816_set_callbacks((Iso7816Callbacks*)&iso87816_cb); + //handle button events CcidTestAppEvent event; while(1) { @@ -161,7 +215,9 @@ int32_t ccid_test_app(void* p) { //tear down USB furi_hal_usb_set_config(usb_mode_prev, NULL); - furi_hal_ccid_set_callbacks(NULL); + furi_hal_ccid_set_callbacks(NULL, NULL); + + iso7816_set_callbacks(NULL); //teardown view ccid_test_app_free(app); diff --git a/applications/debug/ccid_test/iso7816_atr.h b/applications/debug/ccid_test/iso7816_atr.h new file mode 100644 index 00000000000..050457f8c19 --- /dev/null +++ b/applications/debug/ccid_test/iso7816_atr.h @@ -0,0 +1,9 @@ +#ifndef _ISO7816_ATR_H_ +#define _ISO7816_ATR_H_ + +typedef struct { + uint8_t TS; + uint8_t T0; +} Iso7816Atr; + +#endif //_ISO7816_ATR_H_ diff --git a/applications/debug/ccid_test/iso7816_callbacks.c b/applications/debug/ccid_test/iso7816_callbacks.c new file mode 100644 index 00000000000..f56a1e55aca --- /dev/null +++ b/applications/debug/ccid_test/iso7816_callbacks.c @@ -0,0 +1,71 @@ +// 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 "iso7816_t0_apdu.h" +#include "iso7816_atr.h" +#include "iso7816_callbacks.h" +#include +#include +#include + +#define ISO7816_RESPONSE_BUFFER_SIZE 255 + +static Iso7816Callbacks* callbacks = NULL; + +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) { + + struct ISO7816_Response_APDU responseAPDU; + uint8_t responseApduDataBuffer[ISO7816_RESPONSE_BUFFER_SIZE]; + uint8_t responseApduDataBufferLen = 0; + + if(callbacks != NULL) { + struct ISO7816_Command_APDU commandAPDU; + + const uint8_t* commandApduDataBuffer = NULL; + uint8_t commandApduDataBufferLen = 0; + + iso7816_read_command_apdu(&commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen); + + if(commandAPDU.Lc > 0) { + commandApduDataBufferLen = commandAPDU.Lc; + commandApduDataBuffer = &pcToReaderDataBlock[5]; + } + + callbacks->iso7816_process_command(&commandAPDU, &responseAPDU, commandApduDataBuffer, commandApduDataBufferLen, responseApduDataBuffer, &responseApduDataBufferLen); + + } else { + //class not supported + responseAPDU.SW1 = 0x6E; + responseAPDU.SW2 = 0x00; + } + + iso7816_write_response_apdu(&responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen, responseApduDataBuffer, responseApduDataBufferLen); + +} diff --git a/applications/debug/ccid_test/iso7816_callbacks.h b/applications/debug/ccid_test/iso7816_callbacks.h new file mode 100644 index 00000000000..690954da4c4 --- /dev/null +++ b/applications/debug/ccid_test/iso7816_callbacks.h @@ -0,0 +1,28 @@ +#ifndef _ISO7816_CALLBACKS_H_ +#define _ISO7816_CALLBACKS_H_ + +#include +#include "iso7816_atr.h" +#include "iso7816_t0_apdu.h" + +typedef struct { + void (*iso7816_answer_to_reset)(Iso7816Atr* atr); + void (*iso7816_process_command)( + const struct ISO7816_Command_APDU* command, + struct ISO7816_Response_APDU* response, + const uint8_t* commandApduDataBuffer, + uint8_t commandApduDataBufferLen, + uint8_t* responseApduDataBuffer, + uint8_t* responseApduDataBufferLen); +} 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); + +#endif //_ISO7816_CALLBACKS_H_ \ No newline at end of file diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.c b/applications/debug/ccid_test/iso7816_t0_apdu.c index 7c690a6944e..884930fa19c 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.c +++ b/applications/debug/ccid_test/iso7816_t0_apdu.c @@ -4,34 +4,47 @@ #include #include "iso7816_t0_apdu.h" -void iso7816_answer_to_reset(uint8_t* dataBuffer, uint32_t* atrlen) { - //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00 - uint8_t AtrBuffer[2] = { - 0x3B, //TS (direct convention) - 0x00 // T0 (Y(1): b0000, K: 0 (historical bytes)) - }; - *atrlen = 2; - - memcpy(dataBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen)); -} - +//reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type +//extra data will be pointed to commandDataBuffer void iso7816_read_command_apdu( struct ISO7816_Command_APDU* command, const uint8_t* dataBuffer, uint32_t dataLen) { + UNUSED(dataLen); + command->CLA = dataBuffer[0]; command->INS = dataBuffer[1]; command->P1 = dataBuffer[2]; command->P2 = dataBuffer[3]; command->Lc = dataBuffer[4]; + } +//data buffer countains the whole APU response (response + trailer (SW1+SW2)) void iso7816_write_response_apdu( const struct ISO7816_Response_APDU* response, - uint8_t* dataBuffer, - uint32_t* dataLen) { - dataBuffer[0] = response->SW1; - dataBuffer[1] = response->SW2; - *dataLen = 2; + uint8_t* readerToPcDataBlock, + uint32_t* readerToPcDataBlockLen, + uint8_t* responseDataBuffer, + uint32_t responseDataLen) { + + uint32_t responseDataBufferIndex=0; + + //response body + if(responseDataLen > 0) { + while(responseDataBufferIndex < responseDataLen){ + readerToPcDataBlock[responseDataBufferIndex] = responseDataBuffer[responseDataBufferIndex]; + responseDataBufferIndex++; + } + } + + //trailer + readerToPcDataBlock[responseDataBufferIndex] = response->SW1; + responseDataBufferIndex++; + + readerToPcDataBlock[responseDataBufferIndex] = response->SW2; + responseDataBufferIndex++; + + *readerToPcDataBlockLen = responseDataBufferIndex; } \ No newline at end of file diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816_t0_apdu.h index 5ca13eb6041..eb3a9cc1e51 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816_t0_apdu.h @@ -2,6 +2,8 @@ #define _ISO7816_T0_APDU_H_ #include +#include "iso7816_atr.h" +#include "core/common_defines.h" struct ISO7816_Command_APDU { //header @@ -20,13 +22,15 @@ struct ISO7816_Response_APDU { uint8_t SW2; } FURI_PACKED; -void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen); +void iso7816_answer_to_reset(Iso7816Atr * atr); void iso7816_read_command_apdu( struct ISO7816_Command_APDU* command, const uint8_t* dataBuffer, uint32_t dataLen); void iso7816_write_response_apdu( const struct ISO7816_Response_APDU* response, - uint8_t* dataBuffer, - uint32_t* dataLen); + uint8_t* readerToPcDataBlock, + uint32_t* readerToPcDataBlockLen, + uint8_t* responseDataBuffer, + uint32_t responseDataLen); #endif //_ISO7816_T0_APDU_H_ diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index e7a97aff95c..bfd42bf3259 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1256,7 +1256,7 @@ Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus Function,+,furi_hal_bus_reset,void,FuriHalBus Function,+,furi_hal_ccid_ccid_insert_smartcard,void, Function,+,furi_hal_ccid_ccid_remove_smartcard,void, -Function,+,furi_hal_ccid_set_callbacks,void,CcidCallbacks* +Function,+,furi_hal_ccid_set_callbacks,void,"CcidCallbacks*, void*" Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" diff --git a/targets/f7/furi_hal/furi_hal_usb_ccid.c b/targets/f7/furi_hal/furi_hal_usb_ccid.c index d8b43fc6c7b..38143136880 100644 --- a/targets/f7/furi_hal/furi_hal_usb_ccid.c +++ b/targets/f7/furi_hal/furi_hal_usb_ccid.c @@ -184,6 +184,7 @@ static usbd_device* usb_dev; static bool connected = false; static bool smartcard_inserted = true; static CcidCallbacks* callbacks[CCID_TOTAL_SLOTS] = {NULL}; +static void* cb_ctx[CCID_TOTAL_SLOTS]; static void* ccid_set_string_descr(char* str) { furi_check(str); @@ -330,7 +331,7 @@ void CALLBACK_CCID_IccPowerOn( if(smartcard_inserted) { if(callbacks[CCID_SLOT_INDEX] != NULL) { callbacks[CCID_SLOT_INDEX]->icc_power_on_callback( - responseDataBlock->abData, &responseDataBlock->dwLength, NULL); + responseDataBlock->abData, &responseDataBlock->dwLength, cb_ctx[CCID_SLOT_INDEX]); responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } else { @@ -364,7 +365,7 @@ void CALLBACK_CCID_XfrBlock( receivedXfrBlock->dwLength, responseDataBlock->abData, &responseDataBlock->dwLength, - NULL); + cb_ctx[CCID_SLOT_INDEX]); responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } else { @@ -389,8 +390,9 @@ void furi_hal_ccid_ccid_remove_smartcard(void) { smartcard_inserted = false; } -void furi_hal_ccid_set_callbacks(CcidCallbacks* cb) { +void furi_hal_ccid_set_callbacks(CcidCallbacks* cb, void* context) { callbacks[CCID_SLOT_INDEX] = cb; + cb_ctx[CCID_SLOT_INDEX] = context; } static void ccid_rx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) { diff --git a/targets/furi_hal_include/furi_hal_usb_ccid.h b/targets/furi_hal_include/furi_hal_usb_ccid.h index 500bafa3dfd..cbd0bf092b9 100644 --- a/targets/furi_hal_include/furi_hal_usb_ccid.h +++ b/targets/furi_hal_include/furi_hal_usb_ccid.h @@ -19,14 +19,14 @@ typedef struct { typedef struct { void (*icc_power_on_callback)(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context); void (*xfr_datablock_callback)( - const uint8_t* dataBlock, - uint32_t dataBlockLen, - uint8_t* responseDataBlock, - uint32_t* responseDataBlockLen, + const uint8_t* pcToReaderDataBlock, + uint32_t pcToReaderDataBlockLen, + uint8_t* readerToPcDataBlock, + uint32_t* readerToPcDataBlockLen, void* context); } CcidCallbacks; -void furi_hal_ccid_set_callbacks(CcidCallbacks* cb); +void furi_hal_ccid_set_callbacks(CcidCallbacks* cb, void* context); void furi_hal_ccid_ccid_insert_smartcard(void); void furi_hal_ccid_ccid_remove_smartcard(void); From c06ee9cd4ea000b9d84b2bfa3903f95fff46da3d Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Sat, 1 Jun 2024 16:37:03 +0100 Subject: [PATCH 2/3] Format sources and sync API Symbols version --- applications/debug/ccid_test/ccid_test_app.c | 77 +++++++++---------- .../debug/ccid_test/iso7816_callbacks.c | 25 +++--- .../debug/ccid_test/iso7816_callbacks.h | 12 +-- .../debug/ccid_test/iso7816_t0_apdu.c | 10 +-- .../debug/ccid_test/iso7816_t0_apdu.h | 2 +- targets/f18/api_symbols.csv | 4 +- targets/f7/api_symbols.csv | 2 +- targets/f7/furi_hal/furi_hal_usb_ccid.c | 4 +- 8 files changed, 69 insertions(+), 67 deletions(-) diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index 71e90dc785c..b360144d303 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -34,7 +34,6 @@ typedef enum { CcidTestSubmenuIndexInsertSmartcardReader } SubmenuIndex; - static void ccid_test_app_render_callback(Canvas* canvas, void* ctx) { UNUSED(ctx); canvas_clear(canvas); @@ -111,8 +110,8 @@ void ccid_xfr_datablock_callback( void* context) { UNUSED(context); - iso7816_xfr_datablock_callback(pcToReaderDataBlock, pcToReaderDataBlockLen, readerToPcDataBlock, readerToPcDataBlockLen); - + iso7816_xfr_datablock_callback( + pcToReaderDataBlock, pcToReaderDataBlockLen, readerToPcDataBlock, readerToPcDataBlockLen); } static const CcidCallbacks ccid_cb = { @@ -133,44 +132,43 @@ void iso7816_process_command( uint8_t commandApduDataBufferLen, uint8_t* responseApduDataBuffer, uint8_t* responseApduDataBufferLen) { + //example 1: sends a command with no body, receives a response with no body + //sends APDU 0x01:0x02:0x00:0x00 + //receives SW1=0x90, SW2=0x00 + if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) { + responseAPDU->SW1 = 0x90; + responseAPDU->SW2 = 0x00; + } + //example 2: sends a command with no body, receives a response with a body with two bytes + //sends APDU 0x01:0x02:0x00:0x00 + //receives 'bc' (0x62, 0x63) SW1=0x80, SW2=0x10 + else if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x02) { + responseApduDataBuffer[0] = 0x62; + responseApduDataBuffer[1] = 0x63; - //example 1: sends a command with no body, receives a response with no body - //sends APDU 0x01:0x02:0x00:0x00 - //receives SW1=0x90, SW2=0x00 - if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) { - responseAPDU->SW1=0x90; - responseAPDU->SW2=0x00; - } - //example 2: sends a command with no body, receives a response with a body with two bytes - //sends APDU 0x01:0x02:0x00:0x00 - //receives 'bc' (0x62, 0x63) SW1=0x80, SW2=0x10 - else if (commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x02) { - - responseApduDataBuffer[0] = 0x62; - responseApduDataBuffer[1] = 0x63; - - *responseApduDataBufferLen = 2; + *responseApduDataBufferLen = 2; - responseAPDU->SW1=0x90; - responseAPDU->SW2=0x00; - } - //example 3: ends a command with a body with two bytes, receives a response with a body with two bytes - //sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE - //receives (0xCA, 0xFE) SW1=0x90, SW2=0x02 - else if (commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 && commandAPDU->Lc == 2) { - - //echo command body to response body - responseApduDataBuffer[0] = commandApduDataBuffer[0]; - responseApduDataBuffer[1] = commandApduDataBuffer[1]; - - *responseApduDataBufferLen = 2; - - responseAPDU->SW1=0x90; - responseAPDU->SW2=0x00; - } else { - responseAPDU->SW1=0x6A; - responseAPDU->SW2=0x00; - } + responseAPDU->SW1 = 0x90; + responseAPDU->SW2 = 0x00; + } + //example 3: ends a command with a body with two bytes, receives a response with a body with two bytes + //sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE + //receives (0xCA, 0xFE) SW1=0x90, SW2=0x02 + else if( + commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 && + commandAPDU->Lc == 2) { + //echo command body to response body + responseApduDataBuffer[0] = commandApduDataBuffer[0]; + responseApduDataBuffer[1] = commandApduDataBuffer[1]; + + *responseApduDataBufferLen = 2; + + responseAPDU->SW1 = 0x90; + responseAPDU->SW2 = 0x00; + } else { + responseAPDU->SW1 = 0x6A; + responseAPDU->SW2 = 0x00; + } } static const Iso7816Callbacks iso87816_cb = { @@ -178,7 +176,6 @@ static const Iso7816Callbacks iso87816_cb = { iso7816_process_command, }; - int32_t ccid_test_app(void* p) { UNUSED(p); diff --git a/applications/debug/ccid_test/iso7816_callbacks.c b/applications/debug/ccid_test/iso7816_callbacks.c index f56a1e55aca..1a66fa7755d 100644 --- a/applications/debug/ccid_test/iso7816_callbacks.c +++ b/applications/debug/ccid_test/iso7816_callbacks.c @@ -17,16 +17,12 @@ void iso7816_set_callbacks(Iso7816Callbacks* 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 - }; + uint8_t AtrBuffer[2] = {atr.TS, atr.T0}; *atrlen = 2; @@ -40,14 +36,13 @@ void iso7816_xfr_datablock_callback( uint32_t pcToReaderDataBlockLen, uint8_t* readerToPcDataBlock, uint32_t* readerToPcDataBlockLen) { - struct ISO7816_Response_APDU responseAPDU; uint8_t responseApduDataBuffer[ISO7816_RESPONSE_BUFFER_SIZE]; uint8_t responseApduDataBufferLen = 0; if(callbacks != NULL) { struct ISO7816_Command_APDU commandAPDU; - + const uint8_t* commandApduDataBuffer = NULL; uint8_t commandApduDataBufferLen = 0; @@ -58,7 +53,13 @@ void iso7816_xfr_datablock_callback( commandApduDataBuffer = &pcToReaderDataBlock[5]; } - callbacks->iso7816_process_command(&commandAPDU, &responseAPDU, commandApduDataBuffer, commandApduDataBufferLen, responseApduDataBuffer, &responseApduDataBufferLen); + callbacks->iso7816_process_command( + &commandAPDU, + &responseAPDU, + commandApduDataBuffer, + commandApduDataBufferLen, + responseApduDataBuffer, + &responseApduDataBufferLen); } else { //class not supported @@ -66,6 +67,10 @@ void iso7816_xfr_datablock_callback( responseAPDU.SW2 = 0x00; } - iso7816_write_response_apdu(&responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen, responseApduDataBuffer, responseApduDataBufferLen); - + iso7816_write_response_apdu( + &responseAPDU, + readerToPcDataBlock, + readerToPcDataBlockLen, + responseApduDataBuffer, + responseApduDataBufferLen); } diff --git a/applications/debug/ccid_test/iso7816_callbacks.h b/applications/debug/ccid_test/iso7816_callbacks.h index 690954da4c4..3d337d23a0b 100644 --- a/applications/debug/ccid_test/iso7816_callbacks.h +++ b/applications/debug/ccid_test/iso7816_callbacks.h @@ -8,12 +8,12 @@ typedef struct { void (*iso7816_answer_to_reset)(Iso7816Atr* atr); void (*iso7816_process_command)( - const struct ISO7816_Command_APDU* command, - struct ISO7816_Response_APDU* response, - const uint8_t* commandApduDataBuffer, - uint8_t commandApduDataBufferLen, - uint8_t* responseApduDataBuffer, - uint8_t* responseApduDataBufferLen); + const struct ISO7816_Command_APDU* command, + struct ISO7816_Response_APDU* response, + const uint8_t* commandApduDataBuffer, + uint8_t commandApduDataBufferLen, + uint8_t* responseApduDataBuffer, + uint8_t* responseApduDataBufferLen); } Iso7816Callbacks; void iso7816_set_callbacks(Iso7816Callbacks* cb); diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.c b/applications/debug/ccid_test/iso7816_t0_apdu.c index 884930fa19c..5fb695af193 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.c +++ b/applications/debug/ccid_test/iso7816_t0_apdu.c @@ -10,7 +10,6 @@ void iso7816_read_command_apdu( struct ISO7816_Command_APDU* command, const uint8_t* dataBuffer, uint32_t dataLen) { - UNUSED(dataLen); command->CLA = dataBuffer[0]; @@ -18,7 +17,6 @@ void iso7816_read_command_apdu( command->P1 = dataBuffer[2]; command->P2 = dataBuffer[3]; command->Lc = dataBuffer[4]; - } //data buffer countains the whole APU response (response + trailer (SW1+SW2)) @@ -28,13 +26,13 @@ void iso7816_write_response_apdu( uint32_t* readerToPcDataBlockLen, uint8_t* responseDataBuffer, uint32_t responseDataLen) { - - uint32_t responseDataBufferIndex=0; + uint32_t responseDataBufferIndex = 0; //response body if(responseDataLen > 0) { - while(responseDataBufferIndex < responseDataLen){ - readerToPcDataBlock[responseDataBufferIndex] = responseDataBuffer[responseDataBufferIndex]; + while(responseDataBufferIndex < responseDataLen) { + readerToPcDataBlock[responseDataBufferIndex] = + responseDataBuffer[responseDataBufferIndex]; responseDataBufferIndex++; } } diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816_t0_apdu.h index eb3a9cc1e51..48a18944067 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816_t0_apdu.h @@ -22,7 +22,7 @@ struct ISO7816_Response_APDU { uint8_t SW2; } FURI_PACKED; -void iso7816_answer_to_reset(Iso7816Atr * atr); +void iso7816_answer_to_reset(Iso7816Atr* atr); void iso7816_read_command_apdu( struct ISO7816_Command_APDU* command, const uint8_t* dataBuffer, diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 04ceb928cbc..7eda316759b 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,62.3,, +Version,+,63.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -1157,7 +1157,7 @@ Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus Function,+,furi_hal_bus_reset,void,FuriHalBus Function,+,furi_hal_ccid_ccid_insert_smartcard,void, Function,+,furi_hal_ccid_ccid_remove_smartcard,void, -Function,+,furi_hal_ccid_set_callbacks,void,CcidCallbacks* +Function,+,furi_hal_ccid_set_callbacks,void,"CcidCallbacks*, void*" Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index bfd42bf3259..e2e94d06396 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,62.3,, +Version,+,63.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, diff --git a/targets/f7/furi_hal/furi_hal_usb_ccid.c b/targets/f7/furi_hal/furi_hal_usb_ccid.c index 38143136880..f7ab2365d53 100644 --- a/targets/f7/furi_hal/furi_hal_usb_ccid.c +++ b/targets/f7/furi_hal/furi_hal_usb_ccid.c @@ -331,7 +331,9 @@ void CALLBACK_CCID_IccPowerOn( if(smartcard_inserted) { if(callbacks[CCID_SLOT_INDEX] != NULL) { callbacks[CCID_SLOT_INDEX]->icc_power_on_callback( - responseDataBlock->abData, &responseDataBlock->dwLength, cb_ctx[CCID_SLOT_INDEX]); + responseDataBlock->abData, + &responseDataBlock->dwLength, + cb_ctx[CCID_SLOT_INDEX]); responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } else { From 8080807a4c0c013fb6a14721558a6f0b564d6cbe Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Sat, 1 Jun 2024 17:26:56 +0100 Subject: [PATCH 3/3] Debug: change VID/PID in ccid test app to opensc detectable generic one --- applications/debug/ccid_test/ccid_test_app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index b360144d303..be7f7f9e6e3 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -184,8 +184,8 @@ int32_t ccid_test_app(void* p) { //setup CCID USB // On linux: set VID PID using: /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist - app->ccid_cfg.vid = 0x1234; - app->ccid_cfg.pid = 0x5678; + app->ccid_cfg.vid = 0x076B; + app->ccid_cfg.pid = 0x3A21; FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock();