diff --git a/applications/debug/ccid_test/ccid_test_app.c b/applications/debug/ccid_test/ccid_test_app.c index 6993901d2..be6f631f4 100644 --- a/applications/debug/ccid_test/ccid_test_app.c +++ b/applications/debug/ccid_test/ccid_test_app.c @@ -9,6 +9,7 @@ #include "iso7816_callbacks.h" #include "iso7816_t0_apdu.h" #include "iso7816_atr.h" +#include "iso7816_response.h" typedef enum { EventTypeInput, @@ -118,6 +119,76 @@ static const CcidCallbacks ccid_cb = { 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, + uint8_t lc, + uint8_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, uint8_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, + uint8_t lc, + uint8_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; @@ -125,48 +196,38 @@ void iso7816_answer_to_reset(Iso7816Atr* atr) { } 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) { + 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:0x02:0x00:0x00 + //sends APDU 0x01:0x01: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; + 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 { - responseAPDU->SW1 = 0x6A; - responseAPDU->SW2 = 0x00; + iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED); } } diff --git a/applications/debug/ccid_test/client/ccid_client.py b/applications/debug/ccid_test/client/ccid_client.py new file mode 100644 index 000000000..5f43deb87 --- /dev/null +++ b/applications/debug/ccid_test/client/ccid_client.py @@ -0,0 +1,116 @@ +# pylint: disable=missing-module-docstring, too-many-arguments, consider-using-f-string, missing-function-docstring +from smartcard.System import readers + + +def test_apdu(connection, test_name, apdu, expected_sw1, expected_sw2, expected_data): + print("Running test: [%s]" % test_name) + data, sw1, sw2 = connection.transmit(apdu) + + failed = [] + + if sw1 != expected_sw1: + failed.append("SW1: Expected %x, actual %x" % (expected_sw1, sw1)) + + if sw2 != expected_sw2: + failed.append("SW2: Expected %x, actual %x" % (expected_sw2, sw2)) + + if len(data) != len(expected_data): + failed.append( + "Data: Sizes differ: Expected %x, actual %x" + % (len(expected_data), len(data)) + ) + print(data) + elif len(data) > 0: + data_matches = True + for i, _ in enumerate(data): + if data[i] != expected_data[i]: + data_matches = False + + if not data_matches: + failed.append("Data: Expected %s, actual %s" % (expected_data, data)) + + if len(failed) > 0: + print("Test failed: ") + for failure in failed: + print("- %s" % failure) + else: + print("Test passed!") + + +def main(): + r = readers() + print("Found following smartcard readers: ") + + for i, sc in enumerate(r): + print("[%d] %s" % (i, sc)) + + print("Select the smartcard reader you want to run tests against:") + + reader_index = int(input()) + + if reader_index < len(r): + connection = r[reader_index].createConnection() + + connection.connect() + + test_apdu( + connection, + "INS 0x01: No Lc, no Data, No Le. Expect no data in return", + [0x01, 0x01, 0x00, 0x00], + 0x90, + 0x00, + [], + ) + + test_apdu( + connection, + "INS 0x02: No Lc, no Data, Le=2. Expect 2 byte data in return", + [0x01, 0x02, 0x00, 0x00, 0x02], + 0x90, + 0x00, + [0x62, 0x63], + ) + + test_apdu( + connection, + "INS 0x03: Lc=2, data=[0xCA, 0xFE], No Le. Expect no data in return", + [0x01, 0x03, 0x00, 0x00, 0x02, 0xCA, 0xFE], + 0x90, + 0x00, + [], + ) + + test_apdu( + connection, + "INS 0x04: Lc=2, data=[0xCA, 0xFE], Le=2. Expect 1 byte data in return", + [0x01, 0x04, 0x00, 0x00, 0x02, 0xCA, 0xFE, 0x02], + 0x90, + 0x00, + [0xCA, 0xFE], + ) + + small_apdu = list(range(0, 0x0F)) + + test_apdu( + connection, + "INS 0x04: Lc=0x0F, data=small_apdu, Le=0x0F. Expect 14 bytes data in return", + [0x01, 0x04, 0x00, 0x00, 0x0F] + small_apdu + [0x0F], + 0x90, + 0x00, + small_apdu, + ) + + max_apdu = list(range(0, 0x30)) + + test_apdu( + connection, + "INS 0x04: Lc=0x30, data=max_apdu, Le=0x30. Expect 0x30 bytes data in return", + [0x01, 0x04, 0x00, 0x00, 0x30] + max_apdu + [0x30], + 0x90, + 0x00, + max_apdu, + ) + + +if __name__ == "__main__": + main() diff --git a/applications/debug/ccid_test/client/requirements.txt b/applications/debug/ccid_test/client/requirements.txt new file mode 100644 index 000000000..fe0a8e539 --- /dev/null +++ b/applications/debug/ccid_test/client/requirements.txt @@ -0,0 +1,2 @@ +pyscard +# or sudo apt install python3-pyscard \ No newline at end of file diff --git a/applications/debug/ccid_test/iso7816_atr.h b/applications/debug/ccid_test/iso7816_atr.h index 050457f8c..215ec60ee 100644 --- a/applications/debug/ccid_test/iso7816_atr.h +++ b/applications/debug/ccid_test/iso7816_atr.h @@ -1,9 +1,6 @@ -#ifndef _ISO7816_ATR_H_ -#define _ISO7816_ATR_H_ +#pragma once 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 index 1a66fa775..6c1bb106a 100644 --- a/applications/debug/ccid_test/iso7816_callbacks.c +++ b/applications/debug/ccid_test/iso7816_callbacks.c @@ -1,17 +1,21 @@ // 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 -#include -#include - -#define ISO7816_RESPONSE_BUFFER_SIZE 255 +#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; } @@ -36,41 +40,26 @@ 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; + ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer; if(callbacks != NULL) { - struct ISO7816_Command_APDU commandAPDU; + ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer; - const uint8_t* commandApduDataBuffer = NULL; - uint8_t commandApduDataBufferLen = 0; + uint8_t result = + iso7816_read_command_apdu(commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen); - iso7816_read_command_apdu(&commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen); + if(result == ISO7816_READ_COMMAND_APDU_OK) { + callbacks->iso7816_process_command(commandAPDU, responseAPDU); - if(commandAPDU.Lc > 0) { - commandApduDataBufferLen = commandAPDU.Lc; - commandApduDataBuffer = &pcToReaderDataBlock[5]; + 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); } - - callbacks->iso7816_process_command( - &commandAPDU, - &responseAPDU, - commandApduDataBuffer, - commandApduDataBufferLen, - responseApduDataBuffer, - &responseApduDataBufferLen); - } else { - //class not supported - responseAPDU.SW1 = 0x6E; - responseAPDU.SW2 = 0x00; + iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION); } - iso7816_write_response_apdu( - &responseAPDU, - readerToPcDataBlock, - readerToPcDataBlockLen, - responseApduDataBuffer, - responseApduDataBufferLen); + 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 index 3d337d23a..7288b021a 100644 --- a/applications/debug/ccid_test/iso7816_callbacks.h +++ b/applications/debug/ccid_test/iso7816_callbacks.h @@ -1,5 +1,4 @@ -#ifndef _ISO7816_CALLBACKS_H_ -#define _ISO7816_CALLBACKS_H_ +#pragma once #include #include "iso7816_atr.h" @@ -8,12 +7,8 @@ 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 ISO7816_Command_APDU* command, + ISO7816_Response_APDU* response); } Iso7816Callbacks; void iso7816_set_callbacks(Iso7816Callbacks* cb); @@ -23,6 +18,4 @@ 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 + uint32_t* responseDataBlockLen); \ No newline at end of file diff --git a/applications/debug/ccid_test/iso7816_response.c b/applications/debug/ccid_test/iso7816_response.c new file mode 100644 index 000000000..3a65486b6 --- /dev/null +++ b/applications/debug/ccid_test/iso7816_response.c @@ -0,0 +1,8 @@ +#include +#include "iso7816_t0_apdu.h" +#include "iso7816_response.h" + +void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode) { + responseAPDU->SW1 = (responseCode >> (8 * 1)) & 0xff; + responseAPDU->SW2 = (responseCode >> (8 * 0)) & 0xff; +} \ No newline at end of file diff --git a/applications/debug/ccid_test/iso7816_response.h b/applications/debug/ccid_test/iso7816_response.h new file mode 100644 index 000000000..7c2e74257 --- /dev/null +++ b/applications/debug/ccid_test/iso7816_response.h @@ -0,0 +1,12 @@ +#pragma once + +#define ISO7816_RESPONSE_OK 0x9000 + +#define ISO7816_RESPONSE_WRONG_LENGTH 0x6700 +#define ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2 0x6A00 +#define ISO7816_RESPONSE_WRONG_LE 0x6C00 +#define ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED 0x6D00 +#define ISO7816_RESPONSE_CLASS_NOT_SUPPORTED 0x6E00 +#define ISO7816_RESPONSE_INTERNAL_EXCEPTION 0x6F00 + +void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode); \ 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 5fb695af1..916983229 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.c +++ b/applications/debug/ccid_test/iso7816_t0_apdu.c @@ -2,37 +2,73 @@ #include #include #include +#include #include "iso7816_t0_apdu.h" //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, +uint8_t iso7816_read_command_apdu( + 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]; + + if(dataLen == 4) { + command->Lc = 0; + command->Le = 0; + command->LePresent = false; + + return ISO7816_READ_COMMAND_APDU_OK; + } else if(dataLen == 5) { + //short le + + command->Lc = 0; + command->Le = dataBuffer[4]; + command->LePresent = true; + + return ISO7816_READ_COMMAND_APDU_OK; + } else if(dataLen > 5 && dataBuffer[4] != 0x00) { + //short lc + + command->Lc = dataBuffer[4]; + if(command->Lc > 0 && command->Lc < CCID_SHORT_APDU_SIZE) { //-V560 + memcpy(command->Data, &dataBuffer[5], command->Lc); + + //does it have a short le too? + if(dataLen == (uint32_t)(command->Lc + 5)) { + command->Le = 0; + command->LePresent = false; + return ISO7816_READ_COMMAND_APDU_OK; + } else if(dataLen == (uint32_t)(command->Lc + 6)) { + command->Le = dataBuffer[dataLen - 1]; + command->LePresent = true; + + return ISO7816_READ_COMMAND_APDU_OK; + } else { + return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH; + } + } else { + return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH; + } + } else { + return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH; + } } -//data buffer countains the whole APU response (response + trailer (SW1+SW2)) +//data buffer contains the whole APU response (response + trailer (SW1+SW2)) void iso7816_write_response_apdu( - const struct ISO7816_Response_APDU* response, + const ISO7816_Response_APDU* response, uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen, - uint8_t* responseDataBuffer, - uint32_t responseDataLen) { + uint32_t* readerToPcDataBlockLen) { uint32_t responseDataBufferIndex = 0; //response body - if(responseDataLen > 0) { - while(responseDataBufferIndex < responseDataLen) { - readerToPcDataBlock[responseDataBufferIndex] = - responseDataBuffer[responseDataBufferIndex]; + if(response->DataLen > 0) { + while(responseDataBufferIndex < response->DataLen) { + readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex]; responseDataBufferIndex++; } } diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816_t0_apdu.h index 48a189440..3b3450909 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816_t0_apdu.h @@ -1,11 +1,14 @@ -#ifndef _ISO7816_T0_APDU_H_ -#define _ISO7816_T0_APDU_H_ +#pragma once #include #include "iso7816_atr.h" #include "core/common_defines.h" -struct ISO7816_Command_APDU { +#define ISO7816_READ_COMMAND_APDU_OK 0 +#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE 1 +#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH 2 + +typedef struct { //header uint8_t CLA; uint8_t INS; @@ -13,24 +16,27 @@ struct ISO7816_Command_APDU { uint8_t P2; //body - uint8_t Lc; - uint8_t Le; -} FURI_PACKED; + uint16_t Lc; //data length + uint16_t Le; //maximum response data length expected by client -struct ISO7816_Response_APDU { + //Le can have value of 0x00, which actually meand 0x100 = 256 + bool LePresent; + uint8_t Data[0]; +} FURI_PACKED ISO7816_Command_APDU; + +typedef struct { uint8_t SW1; uint8_t SW2; -} FURI_PACKED; + uint16_t DataLen; + uint8_t Data[0]; +} FURI_PACKED ISO7816_Response_APDU; void iso7816_answer_to_reset(Iso7816Atr* atr); -void iso7816_read_command_apdu( - struct ISO7816_Command_APDU* command, - const uint8_t* dataBuffer, - uint32_t dataLen); +uint8_t iso7816_read_command_apdu( + ISO7816_Command_APDU* command, + const uint8_t* pcToReaderDataBlock, + uint32_t pcToReaderDataBlockLen); void iso7816_write_response_apdu( - const struct ISO7816_Response_APDU* response, + const ISO7816_Response_APDU* response, uint8_t* readerToPcDataBlock, - uint32_t* readerToPcDataBlockLen, - uint8_t* responseDataBuffer, - uint32_t responseDataLen); -#endif //_ISO7816_T0_APDU_H_ + uint32_t* readerToPcDataBlockLen); diff --git a/targets/f7/furi_hal/furi_hal_usb_ccid.c b/targets/f7/furi_hal/furi_hal_usb_ccid.c index 0fe5fe5d9..6a6527c3b 100644 --- a/targets/f7/furi_hal/furi_hal_usb_ccid.c +++ b/targets/f7/furi_hal/furi_hal_usb_ccid.c @@ -19,7 +19,8 @@ static const uint8_t USB_DEVICE_NO_PROTOCOL = 0x0; #define CCID_TOTAL_SLOTS 1 #define CCID_SLOT_INDEX 0 -#define CCID_DATABLOCK_SIZE 256 +#define CCID_DATABLOCK_SIZE \ + (4 + 1 + CCID_SHORT_APDU_SIZE + 1) //APDU Header + Lc + Short APDU size + Le #define ENDPOINT_DIR_IN 0x80 #define ENDPOINT_DIR_OUT 0x00 diff --git a/targets/furi_hal_include/furi_hal_usb_ccid.h b/targets/furi_hal_include/furi_hal_usb_ccid.h index cbd0bf092..223f16231 100644 --- a/targets/furi_hal_include/furi_hal_usb_ccid.h +++ b/targets/furi_hal_include/furi_hal_usb_ccid.h @@ -5,6 +5,8 @@ #include "hid_usage_consumer.h" #include "hid_usage_led.h" +#define CCID_SHORT_APDU_SIZE (0xFF) + #ifdef __cplusplus extern "C" { #endif