From 4308a5e377deb979154fcb046286a9ea84a65207 Mon Sep 17 00:00:00 2001 From: Filipe Paz Rodrigues Date: Mon, 9 Oct 2023 11:48:37 -0700 Subject: [PATCH] CCID: Support PC To Reader Transfer Block data (#3126) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CCID: Support PC To Reader Transfer Block data * Format sources Co-authored-by: あく --- applications/debug/ccid_test/ccid_test_app.c | 18 +- .../debug/ccid_test/iso7816_t0_apdu.c | 7 +- .../debug/ccid_test/iso7816_t0_apdu.h | 8 +- .../targets/f7/furi_hal/furi_hal_usb_ccid.c | 282 ++++++++++-------- .../furi_hal_include/furi_hal_usb_ccid.h | 7 +- 5 files changed, 189 insertions(+), 133 deletions(-) diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index a2f936d742..3d7fba39de 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -39,15 +39,25 @@ void icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen, void* context) iso7816_answer_to_reset(atrBuffer, atrlen); } -void xfr_datablock_callback(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context) { +//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, dataBlock, dataBlockLen); + iso7816_write_response_apdu(&responseAPDU, responseDataBlock, responseDataBlockLen); } static const CcidCallbacks ccid_cb = { @@ -66,7 +76,7 @@ static void ccid_test_app_render_callback(Canvas* canvas, void* ctx) { canvas_draw_str(canvas, 0, 63, "Hold [back] to exit"); } -static void ccid_test_app__input_callback(InputEvent* input_event, void* ctx) { +static void ccid_test_app_input_callback(InputEvent* input_event, void* ctx) { FuriMessageQueue* event_queue = ctx; CcidTestAppEvent event; @@ -94,7 +104,7 @@ CcidTestApp* ccid_test_app_alloc() { //message queue app->event_queue = furi_message_queue_alloc(8, sizeof(CcidTestAppEvent)); furi_check(app->event_queue); - view_port_input_callback_set(app->view_port, ccid_test_app__input_callback, app->event_queue); + view_port_input_callback_set(app->view_port, ccid_test_app_input_callback, app->event_queue); return app; } diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.c b/applications/debug/ccid_test/iso7816_t0_apdu.c index 29f5f7a86c..7c690a6944 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.c +++ b/applications/debug/ccid_test/iso7816_t0_apdu.c @@ -4,7 +4,7 @@ #include #include "iso7816_t0_apdu.h" -void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen) { +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) @@ -12,18 +12,19 @@ void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen) { }; *atrlen = 2; - memcpy(atrBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen)); + memcpy(dataBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen)); } void iso7816_read_command_apdu( struct ISO7816_Command_APDU* command, const uint8_t* dataBuffer, uint32_t dataLen) { - furi_assert(dataLen <= 4); + UNUSED(dataLen); command->CLA = dataBuffer[0]; command->INS = dataBuffer[1]; command->P1 = dataBuffer[2]; command->P2 = dataBuffer[3]; + command->Lc = dataBuffer[4]; } void iso7816_write_response_apdu( diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816_t0_apdu.h index 8a8c99f85d..b66d66054d 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816_t0_apdu.h @@ -6,18 +6,18 @@ struct ISO7816_Command_APDU { //header uint8_t CLA; - uint32_t INS; + uint8_t INS; uint8_t P1; uint8_t P2; //body - uint8_t Nc; - uint8_t Ne; + uint8_t Lc; + uint8_t Le; } __attribute__((packed)); struct ISO7816_Response_APDU { uint8_t SW1; - uint32_t SW2; + uint8_t SW2; } __attribute__((packed)); void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c index 559713d015..e9906fed46 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c @@ -250,76 +250,136 @@ static void ccid_on_suspend(usbd_device* dev) { connected = false; } -struct ccid_bulk_message_header { +typedef struct ccid_bulk_message_header { uint8_t bMessageType; uint32_t dwLength; uint8_t bSlot; uint8_t bSeq; -} __attribute__((packed)); +} __attribute__((packed)) ccid_bulk_message_header_t; + +uint8_t SendBuffer[sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE]; + +//stores the data p +uint8_t ReceiveBuffer[sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE]; + +void CALLBACK_CCID_GetSlotStatus( + uint8_t slot, + uint8_t seq, + struct rdr_to_pc_slot_status* responseSlotStatus) { + responseSlotStatus->bMessageType = RDR_TO_PC_SLOTSTATUS; -static struct rdr_to_pc_slot_status responseSlotStatus; -static struct rdr_to_pc_data_block responseDataBlock; -static struct rdr_to_pc_parameters_t0 responseParameters; -uint8_t SendDataBlock[CCID_DATABLOCK_SIZE]; + responseSlotStatus->bSlot = slot; + responseSlotStatus->bSeq = seq; + responseSlotStatus->bClockStatus = 0; -uint8_t CALLBACK_CCID_GetSlotStatus(uint8_t slot, uint8_t* error) { - if(slot == CCID_SLOT_INDEX) { - *error = CCID_ERROR_NOERROR; + responseSlotStatus->dwLength = 0; + + if(responseSlotStatus->bSlot == CCID_SLOT_INDEX) { + responseSlotStatus->bError = CCID_ERROR_NOERROR; if(smartcard_inserted) { - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; + responseSlotStatus->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_PRESENTANDACTIVE; } else { - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT; + responseSlotStatus->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_NOICCPRESENT; } } else { - *error = CCID_ERROR_SLOTNOTFOUND; - return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + responseSlotStatus->bError = CCID_ERROR_SLOTNOTFOUND; + responseSlotStatus->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } } -uint8_t - CALLBACK_CCID_IccPowerOn(uint8_t slot, uint8_t* atrBuffer, uint32_t* atrlen, uint8_t* error) { - if(slot == CCID_SLOT_INDEX) { - *error = CCID_ERROR_NOERROR; +void CALLBACK_CCID_SetParametersT0( + struct pc_to_rdr_set_parameters_t0* requestSetParametersT0, + struct rdr_to_pc_parameters_t0* responseSetParametersT0) { + furi_assert(requestSetParametersT0->bProtocolNum == 0x00); //T0 + responseSetParametersT0->bMessageType = RDR_TO_PC_PARAMETERS; + responseSetParametersT0->bSlot = requestSetParametersT0->bSlot; + responseSetParametersT0->bSeq = requestSetParametersT0->bSeq; + + responseSetParametersT0->dwLength = + sizeof(struct pc_to_rdr_set_parameters_t0) - sizeof(ccid_bulk_message_header_t); + + if(responseSetParametersT0->bSlot == CCID_SLOT_INDEX) { + responseSetParametersT0->bError = CCID_ERROR_NOERROR; + if(smartcard_inserted) { + responseSetParametersT0->bProtocolNum = requestSetParametersT0->bProtocolNum; + responseSetParametersT0->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_PRESENTANDACTIVE; + } else { + responseSetParametersT0->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_NOICCPRESENT; + } + } else { + responseSetParametersT0->bError = CCID_ERROR_SLOTNOTFOUND; + responseSetParametersT0->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + } +} + +void CALLBACK_CCID_IccPowerOn( + uint8_t slot, + uint8_t seq, + struct rdr_to_pc_data_block* responseDataBlock) { + responseDataBlock->bMessageType = RDR_TO_PC_DATABLOCK; + responseDataBlock->dwLength = 0; + responseDataBlock->bSlot = slot; + responseDataBlock->bSeq = seq; + + if(responseDataBlock->bSlot == CCID_SLOT_INDEX) { + responseDataBlock->bError = CCID_ERROR_NOERROR; if(smartcard_inserted) { if(callbacks[CCID_SLOT_INDEX] != NULL) { - callbacks[CCID_SLOT_INDEX]->icc_power_on_callback(atrBuffer, atrlen, NULL); + callbacks[CCID_SLOT_INDEX]->icc_power_on_callback( + responseDataBlock->abData, &responseDataBlock->dwLength, NULL); } else { - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | - CCID_ICCSTATUS_PRESENTANDINACTIVE; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_PRESENTANDINACTIVE; } - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_PRESENTANDACTIVE; } else { - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_NOICCPRESENT; } } else { - *error = CCID_ERROR_SLOTNOTFOUND; - return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + responseDataBlock->bError = CCID_ERROR_SLOTNOTFOUND; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } } -uint8_t CALLBACK_CCID_XfrBlock( - uint8_t slot, - uint8_t* dataBlock, - uint32_t* dataBlockLen, - uint8_t* error) { - if(slot == CCID_SLOT_INDEX) { - *error = CCID_ERROR_NOERROR; +void CALLBACK_CCID_XfrBlock( + struct pc_to_rdr_xfr_block* receivedXfrBlock, + struct rdr_to_pc_data_block* responseDataBlock) { + responseDataBlock->bMessageType = RDR_TO_PC_DATABLOCK; + responseDataBlock->bSlot = receivedXfrBlock->bSlot; + responseDataBlock->bSeq = receivedXfrBlock->bSeq; + responseDataBlock->bChainParameter = 0; + + if(responseDataBlock->bSlot == CCID_SLOT_INDEX) { + responseDataBlock->bError = CCID_ERROR_NOERROR; if(smartcard_inserted) { if(callbacks[CCID_SLOT_INDEX] != NULL) { - callbacks[CCID_SLOT_INDEX]->xfr_datablock_callback(dataBlock, dataBlockLen, NULL); + callbacks[CCID_SLOT_INDEX]->xfr_datablock_callback( + (const uint8_t*)receivedXfrBlock->abData, + receivedXfrBlock->dwLength, + responseDataBlock->abData, + &responseDataBlock->dwLength, + NULL); } else { - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | - CCID_ICCSTATUS_PRESENTANDINACTIVE; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_PRESENTANDINACTIVE; } - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_PRESENTANDACTIVE; } else { - return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | + CCID_ICCSTATUS_NOICCPRESENT; } } else { - *error = CCID_ERROR_SLOTNOTFOUND; - return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + responseDataBlock->bError = CCID_ERROR_SLOTNOTFOUND; + responseDataBlock->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } } @@ -347,109 +407,89 @@ static void ccid_tx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) { if(event == usbd_evt_eprx) { if(connected == false) return; - struct ccid_bulk_message_header message; - usbd_ep_read(usb_dev, ep, &message, sizeof(message)); - - uint8_t Status; - uint8_t Error = CCID_ERROR_NOERROR; - - uint32_t dataBlockLen = 0; - uint8_t* dataBlockBuffer = NULL; - - if(message.bMessageType == PC_TO_RDR_GETSLOTSTATUS) { - responseSlotStatus.bMessageType = RDR_TO_PC_SLOTSTATUS; - responseSlotStatus.dwLength = 0; - responseSlotStatus.bSlot = message.bSlot; - responseSlotStatus.bSeq = message.bSeq; - - responseSlotStatus.bClockStatus = 0; - - Status = CALLBACK_CCID_GetSlotStatus(message.bSlot, &Error); - - responseSlotStatus.bStatus = Status; - responseSlotStatus.bError = Error; - - usbd_ep_write( - usb_dev, CCID_IN_EPADDR, &responseSlotStatus, sizeof(responseSlotStatus)); - } else if(message.bMessageType == PC_TO_RDR_ICCPOWERON) { - responseDataBlock.bMessageType = RDR_TO_PC_DATABLOCK; - responseDataBlock.bSlot = message.bSlot; - responseDataBlock.bSeq = message.bSeq; - responseDataBlock.bChainParameter = 0; + //read initial CCID message header - dataBlockLen = 0; - dataBlockBuffer = (uint8_t*)SendDataBlock; - Status = CALLBACK_CCID_IccPowerOn( - message.bSlot, (uint8_t*)dataBlockBuffer, &dataBlockLen, &Error); + int32_t bytes_read = usbd_ep_read( + usb_dev, ep, &ReceiveBuffer, sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE); + //minimum request size is header size + furi_assert((uint16_t)bytes_read >= sizeof(ccid_bulk_message_header_t)); + ccid_bulk_message_header_t* message = (ccid_bulk_message_header_t*)&ReceiveBuffer; - furi_assert(dataBlockLen < CCID_DATABLOCK_SIZE); - responseDataBlock.dwLength = dataBlockLen; + if(message->bMessageType == PC_TO_RDR_ICCPOWERON) { + struct pc_to_rdr_icc_power_on* requestDataBlock = + (struct pc_to_rdr_icc_power_on*)message; + struct rdr_to_pc_data_block* responseDataBlock = + (struct rdr_to_pc_data_block*)&SendBuffer; - responseSlotStatus.bStatus = Status; - responseSlotStatus.bError = Error; + CALLBACK_CCID_IccPowerOn( + requestDataBlock->bSlot, requestDataBlock->bSeq, responseDataBlock); - memcpy(responseDataBlock.abData, SendDataBlock, dataBlockLen); usbd_ep_write( usb_dev, CCID_IN_EPADDR, - &responseDataBlock, - sizeof(struct rdr_to_pc_data_block) + (sizeof(uint8_t) * dataBlockLen)); - } else if(message.bMessageType == PC_TO_RDR_ICCPOWEROFF) { - responseSlotStatus.bMessageType = RDR_TO_PC_SLOTSTATUS; - responseSlotStatus.dwLength = 0; - responseSlotStatus.bSlot = message.bSlot; - responseSlotStatus.bSeq = message.bSeq; - - responseSlotStatus.bClockStatus = 0; + responseDataBlock, + sizeof(struct rdr_to_pc_data_block) + + (sizeof(uint8_t) * responseDataBlock->dwLength)); + } else if(message->bMessageType == PC_TO_RDR_ICCPOWEROFF) { + struct pc_to_rdr_icc_power_off* requestIccPowerOff = + (struct pc_to_rdr_icc_power_off*)message; + struct rdr_to_pc_slot_status* responseSlotStatus = + (struct rdr_to_pc_slot_status*)&SendBuffer; + + CALLBACK_CCID_GetSlotStatus( + requestIccPowerOff->bSlot, requestIccPowerOff->bSeq, responseSlotStatus); - uint8_t Status; - uint8_t Error = CCID_ERROR_NOERROR; - Status = CALLBACK_CCID_GetSlotStatus(message.bSlot, &Error); + usbd_ep_write( + usb_dev, CCID_IN_EPADDR, responseSlotStatus, sizeof(struct rdr_to_pc_slot_status)); + } else if(message->bMessageType == PC_TO_RDR_GETSLOTSTATUS) { + struct pc_to_rdr_get_slot_status* requestSlotStatus = + (struct pc_to_rdr_get_slot_status*)message; + struct rdr_to_pc_slot_status* responseSlotStatus = + (struct rdr_to_pc_slot_status*)&SendBuffer; - responseSlotStatus.bStatus = Status; - responseSlotStatus.bError = Error; + CALLBACK_CCID_GetSlotStatus( + requestSlotStatus->bSlot, requestSlotStatus->bSeq, responseSlotStatus); usbd_ep_write( - usb_dev, CCID_IN_EPADDR, &responseSlotStatus, sizeof(responseSlotStatus)); - } else if(message.bMessageType == PC_TO_RDR_SETPARAMETERS) { - responseParameters.bMessageType = RDR_TO_PC_PARAMETERS; - responseParameters.bSlot = message.bSlot; - responseParameters.bSeq = message.bSeq; - responseParameters.bProtocolNum = 0; //T0 + usb_dev, CCID_IN_EPADDR, responseSlotStatus, sizeof(struct rdr_to_pc_slot_status)); + } else if(message->bMessageType == PC_TO_RDR_XFRBLOCK) { + struct pc_to_rdr_xfr_block* receivedXfrBlock = (struct pc_to_rdr_xfr_block*)message; + struct rdr_to_pc_data_block* responseDataBlock = + (struct rdr_to_pc_data_block*)&SendBuffer; - uint8_t Status = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR; - uint8_t Error = CCID_ERROR_NOERROR; + furi_assert(receivedXfrBlock->dwLength <= CCID_DATABLOCK_SIZE); + furi_assert( + (uint16_t)bytes_read >= + sizeof(ccid_bulk_message_header_t) + receivedXfrBlock->dwLength); - responseParameters.bStatus = Status; - responseParameters.bError = Error; + CALLBACK_CCID_XfrBlock(receivedXfrBlock, responseDataBlock); - responseParameters.dwLength = sizeof(struct rdr_to_pc_parameters_t0); + furi_assert(responseDataBlock->dwLength <= CCID_DATABLOCK_SIZE); usbd_ep_write( - usb_dev, CCID_IN_EPADDR, &responseParameters, sizeof(responseParameters)); - } else if(message.bMessageType == PC_TO_RDR_XFRBLOCK) { - responseDataBlock.bMessageType = RDR_TO_PC_DATABLOCK; - responseDataBlock.bSlot = message.bSlot; - responseDataBlock.bSeq = message.bSeq; - responseDataBlock.bChainParameter = 0; - - dataBlockLen = 0; - dataBlockBuffer = (uint8_t*)SendDataBlock; - Status = CALLBACK_CCID_XfrBlock( - message.bSlot, (uint8_t*)dataBlockBuffer, &dataBlockLen, &Error); - - furi_assert(dataBlockLen < CCID_DATABLOCK_SIZE); - responseDataBlock.dwLength = dataBlockLen; - - responseSlotStatus.bStatus = Status; - responseSlotStatus.bError = Error; + usb_dev, + CCID_IN_EPADDR, + responseDataBlock, + sizeof(struct rdr_to_pc_data_block) + + (sizeof(uint8_t) * responseDataBlock->dwLength)); + } else if(message->bMessageType == PC_TO_RDR_SETPARAMETERS) { + struct pc_to_rdr_set_parameters_t0* requestSetParametersT0 = + (struct pc_to_rdr_set_parameters_t0*)message; + struct rdr_to_pc_parameters_t0* responseSetParametersT0 = + (struct rdr_to_pc_parameters_t0*)&SendBuffer; + + furi_assert(requestSetParametersT0->dwLength <= CCID_DATABLOCK_SIZE); + furi_assert( + (uint16_t)bytes_read >= + sizeof(ccid_bulk_message_header_t) + requestSetParametersT0->dwLength); + + CALLBACK_CCID_SetParametersT0(requestSetParametersT0, responseSetParametersT0); - memcpy(responseDataBlock.abData, SendDataBlock, dataBlockLen); usbd_ep_write( usb_dev, CCID_IN_EPADDR, - &responseDataBlock, - sizeof(struct rdr_to_pc_data_block) + (sizeof(uint8_t) * dataBlockLen)); + responseSetParametersT0, + sizeof(struct rdr_to_pc_parameters_t0)); } } } diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_ccid.h b/firmware/targets/furi_hal_include/furi_hal_usb_ccid.h index e3ee0dfc38..a4880e4b6c 100644 --- a/firmware/targets/furi_hal_include/furi_hal_usb_ccid.h +++ b/firmware/targets/furi_hal_include/furi_hal_usb_ccid.h @@ -18,7 +18,12 @@ typedef struct { typedef struct { void (*icc_power_on_callback)(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context); - void (*xfr_datablock_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, + void* context); } CcidCallbacks; void furi_hal_ccid_set_callbacks(CcidCallbacks* cb);