diff --git a/ccid/patches/ccid-1.3.11.patch b/ccid/patches/ccid-1.3.11.patch index 60822d1..bfbbe07 100644 --- a/ccid/patches/ccid-1.3.11.patch +++ b/ccid/patches/ccid-1.3.11.patch @@ -356,7 +356,7 @@ Index: ccid-1.3.11/src/commands.c + unsigned char RxBuffer[], unsigned int *RxLength, + unsigned char bPINOperation) +{ -+ unsigned char cmd[1024]; ++ unsigned char cmd[CMD_BUF_SIZE]; + unsigned int length; + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + status_t res; diff --git a/ccid/patches/ccid-1.4.4.patch b/ccid/patches/ccid-1.4.4.patch index 1b56263..e9b50c1 100644 --- a/ccid/patches/ccid-1.4.4.patch +++ b/ccid/patches/ccid-1.4.4.patch @@ -353,7 +353,7 @@ Index: ccid-1.4.4/src/commands.c + unsigned char RxBuffer[], unsigned int *RxLength, + unsigned char bPINOperation) +{ -+ unsigned char cmd[1024]; ++ unsigned char cmd[CMD_BUF_SIZE]; + unsigned int length; + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + status_t res; diff --git a/ccid/patches/ccid-1.4.5.patch b/ccid/patches/ccid-1.4.5.patch new file mode 100644 index 0000000..b54730d --- /dev/null +++ b/ccid/patches/ccid-1.4.5.patch @@ -0,0 +1,578 @@ +Index: ccid-1.4.5/src/ccid.h +=================================================================== +--- ccid-1.4.5.orig/src/ccid.h 2011-10-11 22:27:44.000000000 +0200 ++++ ccid-1.4.5/src/ccid.h 2012-01-24 21:25:58.287191632 +0100 +@@ -152,8 +152,10 @@ + #define CCID_CLASS_EXCHANGE_MASK 0x00070000 + + /* Features from bPINSupport */ +-#define CCID_CLASS_PIN_VERIFY 0x01 +-#define CCID_CLASS_PIN_MODIFY 0x02 ++#define CCID_CLASS_PIN_VERIFY 0x01 ++#define CCID_CLASS_PIN_MODIFY 0x02 ++#define CCID_CLASS_PIN_PACE_CAPABILITIES 0x10 ++#define CCID_CLASS_PIN_PACE_EXECUTE 0x20 + + /* See CCID specs ch. 4.2.1 */ + #define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */ +@@ -164,6 +166,25 @@ + #define CCID_COMMAND_FAILED 0x40 /* 01 0000 00 */ + #define CCID_TIME_EXTENSION 0x80 /* 10 0000 00 */ + ++#define PACE_SUCCESS 0x00000000 ++#define PACE_ERROR_LENGTH_INCONSISTENT 0xD0000001 ++#define PACE_ERROR_UNEXPECTED_DATA 0xD0000002 ++#define PACE_ERROR_UNEXPECTED_DATA_COMBINATION 0xD0000003 ++#define PACE_ERROR_CARD_NOT_SUPPORTED 0xE0000001 ++#define PACE_ERROR_ALGORITH_NOT_SUPPORTED 0xE0000002 ++#define PACE_ERROR_PINID_NOT_SUPPORTED 0xE0000003 ++#define PACE_ERROR_SELECT_EF_CARDACCESS 0xF0000000 ++#define PACE_ERROR_READ_BINARY 0xF0010000 ++#define PACE_ERROR_MSE_SET_AT 0xF0020000 ++#define PACE_ERROR_GENERAL_AUTHENTICATE_1 0xF0030000 ++#define PACE_ERROR_GENERAL_AUTHENTICATE_2 0xF0040000 ++#define PACE_ERROR_GENERAL_AUTHENTICATE_3 0xF0050000 ++#define PACE_ERROR_GENERAL_AUTHENTICATE_4 0xF0060000 ++#define PACE_ERROR_COMMUNICATION 0xF0100001 ++#define PACE_ERROR_NO_CARD 0xF0100002 ++#define PACE_ERROR_ABORTED 0xF0200001 ++#define PACE_ERROR_TIMEOUT 0xF0200002 ++ + /* bInterfaceProtocol for ICCD */ + #define PROTOCOL_CCID 0 /* plain CCID */ + #define PROTOCOL_ICCD_A 1 /* ICCD Version A */ +@@ -240,6 +261,8 @@ + + /* convert a 4 byte integer in USB format into an int */ + #define dw2i(a, x) (unsigned int)((((((a[x+3] << 8) + a[x+2]) << 8) + a[x+1]) << 8) + a[x]) ++/* convert a 2 byte integer in USB format into an int */ ++#define w2i(a, x) (unsigned int)(((a[x+1]) << 8) + a[x]) + + /* all the data rates specified by ISO 7816-3 Fi/Di tables */ + #define ISO_DATA_RATES 10753, 14337, 15625, 17204, \ +Index: ccid-1.4.5/src/ccid_ifdhandler.h +=================================================================== +--- ccid-1.4.5.orig/src/ccid_ifdhandler.h 2010-06-04 14:31:15.000000000 +0200 ++++ ccid-1.4.5/src/ccid_ifdhandler.h 2012-01-24 21:25:58.287191632 +0100 +@@ -59,4 +59,9 @@ + CcidDesc *get_ccid_slot(unsigned int reader_index); + + #endif ++#ifndef FEATURE_EXECUTE_PACE ++#define FEATURE_EXECUTE_PACE 0x20 ++#endif ++#define IOCTL_FEATURE_EXECUTE_PACE \ ++ SCARD_CTL_CODE(FEATURE_EXECUTE_PACE + CLASS2_IOCTL_MAGIC) + +Index: ccid-1.4.5/src/commands.c +=================================================================== +--- ccid-1.4.5.orig/src/commands.c 2011-08-24 11:15:36.000000000 +0200 ++++ ccid-1.4.5/src/commands.c 2012-01-24 21:26:31.815357930 +0100 +@@ -75,6 +75,18 @@ + unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length, + unsigned char rx_buffer[]); + ++static RESPONSECODE SecurePINPACE(unsigned int reader_index, ++ unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength, ++ unsigned char bPINOperation); ++ ++static RESPONSECODE transform_EstablishPACEChannel_InputData( ++ unsigned char input[], unsigned int input_length); ++ ++static RESPONSECODE transform_EstablishPACEChannel_OutputData( ++ unsigned char output[], unsigned int output_length); ++ ++static void i2w(uint16_t value, unsigned char *buffer); + static void i2dw(int value, unsigned char *buffer); + static unsigned int bei2i(unsigned char *buffer); + +@@ -739,6 +751,341 @@ + return ret; + } /* SecurePINModify */ + ++static RESPONSECODE transform_EstablishPACEChannel_InputData( ++ unsigned char input[], unsigned int input_length) ++{ ++ uint8_t lengthCHAT, lengthPIN; ++ uint16_t lengthCertificateDescription; ++ size_t parsed = 0; ++ ++ /* transform length fields of input data to little endian */ ++ ++ if (input_length < parsed+1) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ switch (input[parsed]) { ++ case 0x01: ++ DEBUG_COMM("Initiating PACE with MRZ"); ++ break; ++ case 0x02: ++ DEBUG_COMM("Initiating PACE with CAN"); ++ break; ++ case 0x03: ++ DEBUG_COMM("Initiating PACE with PIN"); ++ break; ++ case 0x04: ++ DEBUG_COMM("Initiating PACE with PUK"); ++ break; ++ default: ++ DEBUG_COMM("Initiating PACE with unknown PACE secret type"); ++ break; ++ } ++ parsed += 1; ++ ++ if (input_length < parsed+1) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ lengthCHAT = input[parsed]; ++ parsed += 1; ++ ++ if (input_length < parsed+lengthCHAT) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ if (lengthCHAT) ++ DEBUG_INFO_XXD("CHAT:\n", &input[parsed], lengthCHAT); ++ parsed += lengthCHAT; ++ ++ if (input_length < parsed+1) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ lengthPIN = input[parsed]; ++ parsed += 1; ++ ++ if (input_length < parsed+lengthPIN) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++#if 0 ++ /* dont print secrets... */ ++ if (lengthPIN) ++ DEBUG_INFO_XXD("PIN:\n", &input[parsed], lengthPIN); ++#endif ++ parsed += lengthPIN; ++ ++ if (input_length < parsed+2) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ memcpy(&lengthCertificateDescription, &input[parsed], 2); ++ i2w(lengthCertificateDescription, &input[parsed]); ++ parsed += 2; ++ ++ if (input_length < parsed+lengthCertificateDescription) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel input data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ if (lengthCertificateDescription) ++ DEBUG_INFO_XXD("Certificate description:\n", &input[parsed], lengthCertificateDescription); ++ parsed += lengthCertificateDescription; ++ ++ if (parsed < input_length) { ++ DEBUG_CRITICAL2("Overrun by %u bytes", input_length - parsed); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ return IFD_SUCCESS; ++} ++ ++static RESPONSECODE transform_EstablishPACEChannel_OutputData( ++ unsigned char output[], unsigned int output_length) ++{ ++ uint8_t lengthCAR, lengthCARprev; ++ uint16_t lengthOutputData, lengthEF_CardAccess, length_IDicc; ++ uint32_t result; ++ size_t parsed = 0; ++ ++ if (parsed+4 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ result = dw2i(output, parsed); ++ memcpy(&output[parsed], &result, 4); ++ DEBUG_INFO2("EstablishPACEChannel Result: %08X", result); ++ parsed += 4; ++ ++ if (parsed+2 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ lengthOutputData = w2i(output, parsed); ++ if ((unsigned int)lengthOutputData+6 != output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ parsed += 2; ++ ++ if (parsed+2 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ DEBUG_INFO3("MSE:Set AT Statusbytes: %02X %02X", ++ output[parsed+0], output[parsed+1]); ++ parsed += 2; ++ ++ if (parsed+2 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ lengthEF_CardAccess = w2i(output, parsed); ++ memcpy(&output[parsed], &lengthEF_CardAccess, 2); ++ parsed += 2; ++ ++ if (parsed+lengthEF_CardAccess > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ if (lengthEF_CardAccess) ++ DEBUG_INFO_XXD("EF.CardAccess:\n", &output[parsed], lengthEF_CardAccess); ++ parsed += lengthEF_CardAccess; ++ ++ if (parsed+1 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ lengthCAR = output[parsed]; ++ parsed += 1; ++ ++ if (parsed+lengthCAR > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ if (lengthCAR) ++ DEBUG_INFO_XXD("Recent Certificate Authority:\n", ++ &output[parsed], lengthCAR); ++ parsed += lengthCAR; ++ ++ if (parsed+1 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ lengthCARprev = output[parsed]; ++ parsed += 1; ++ ++ if (parsed+lengthCARprev > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ if (lengthCARprev) ++ DEBUG_INFO_XXD("Previous Certificate Authority:\n", ++ &output[parsed], lengthCARprev); ++ parsed += lengthCARprev; ++ ++ if (parsed+2 > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ length_IDicc = w2i(output, parsed); ++ memcpy(&output[parsed], &length_IDicc, 2); ++ parsed += 2; ++ ++ if (parsed+length_IDicc > output_length) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ if (length_IDicc) ++ DEBUG_INFO_XXD("IDicc:\n", &output[parsed], length_IDicc); ++ parsed += length_IDicc; ++ ++ if (parsed < output_length) { ++ DEBUG_CRITICAL2("Overrun by %u bytes", output_length - parsed); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ return IFD_SUCCESS; ++} ++ ++RESPONSECODE SecurePINPACEVerify(unsigned int reader_index, ++ unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength) ++{ ++ /* bPINOperation: PIN PACE Capabilities */ ++ RESPONSECODE return_value; ++ int old_read_timeout; ++ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); ++ ++ old_read_timeout= ccid_descriptor -> readTimeout; ++ ccid_descriptor -> readTimeout = 30*1000; /* 30 seconds */ ++ ++ return_value = transform_EstablishPACEChannel_InputData(TxBuffer, TxLength); ++ if (IFD_SUCCESS != return_value) ++ goto err; ++ ++ return_value = SecurePINPACE(reader_index, TxBuffer, TxLength, RxBuffer, ++ RxLength, CCID_CLASS_PIN_PACE_EXECUTE); ++ if (IFD_SUCCESS != return_value) ++ goto err; ++ ++ if (*RxLength < 6) { ++ DEBUG_CRITICAL("Malformed Establish PACE output buffer."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ ++ return_value = transform_EstablishPACEChannel_OutputData(RxBuffer, *RxLength); ++ if (IFD_SUCCESS != return_value) ++ goto err; ++ ++err: ++ ccid_descriptor -> readTimeout = old_read_timeout; ++ return return_value; ++} ++ ++RESPONSECODE SecurePINPACECapabilities(unsigned int reader_index, ++ unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength) ++{ ++ /* bPINOperation: PIN PACE Capabilities */ ++ if (*RxLength < 6) { ++ DEBUG_CRITICAL2("overrun by %d bytes", 6 - *RxLength); ++ return IFD_ERROR_INSUFFICIENT_BUFFER; ++ } ++ ++ unsigned int length = *RxLength - 6; ++ RESPONSECODE r = SecurePINPACE(reader_index, TxBuffer, TxLength, ++ RxBuffer+6, &length, CCID_CLASS_PIN_PACE_CAPABILITIES); ++ if (r != IFD_SUCCESS) ++ return r; ++ ++ uint32_t s = PACE_SUCCESS; ++ memcpy(RxBuffer, &s, 4); /* Result */ ++ memcpy(RxBuffer+4, &length, 2); /* lengthOutputData */ ++ *RxLength = length + 6; ++ ++ return IFD_SUCCESS; ++} ++ ++static RESPONSECODE SecurePINPACE(unsigned int reader_index, ++ unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength, ++ unsigned char bPINOperation) ++{ ++ unsigned char cmd[CMD_BUF_SIZE]; ++ unsigned int length; ++ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); ++ status_t res; ++ ++ cmd[0] = 0x69; /* Secure */ ++ i2dw(TxLength, cmd+1); ++ cmd[5] = ccid_descriptor->bCurrentSlotIndex; ++ cmd[6] = (*ccid_descriptor->pbSeq)++; ++ cmd[7] = 0; ++ cmd[8] = 0; ++ cmd[9] = 0; ++ cmd[10] = bPINOperation; ++ ++ if (sizeof(cmd) < 11+TxLength) ++ { ++ DEBUG_CRITICAL2("Too much data in input (overrun by %d bytes)", ++ 11+TxLength - sizeof(cmd)); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ memcpy(cmd+11, TxBuffer, TxLength); ++ ++ res = WritePort(reader_index, 11+TxLength, cmd); ++ if (res != STATUS_SUCCESS) ++ { ++ if (STATUS_NO_SUCH_DEVICE == res) ++ return IFD_NO_SUCH_DEVICE; ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ length = sizeof(cmd); ++ res = ReadPort(reader_index, &length, cmd); ++ if (res != STATUS_SUCCESS) ++ { ++ if (STATUS_NO_SUCH_DEVICE == res) ++ return IFD_NO_SUCH_DEVICE; ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ if (length < STATUS_OFFSET+1) ++ { ++ DEBUG_CRITICAL2("Not enough data received: %d bytes", length); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED) ++ { ++ ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */ ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ /* we have read less (or more) data than the CCID frame says to contain */ ++ if (length-10 != dw2i(cmd, 1)) ++ { ++ DEBUG_CRITICAL3("Can't read all data (%d out of %d expected)", ++ length-10, dw2i(cmd, 1)); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ length = dw2i(cmd, 1); ++ if (length <= *RxLength) ++ *RxLength = length; ++ else ++ { ++ DEBUG_CRITICAL2("overrun by %d bytes", length - *RxLength); ++ return IFD_ERROR_INSUFFICIENT_BUFFER; ++ } ++ ++ memcpy(RxBuffer, cmd+10, *RxLength); ++ ++ return IFD_SUCCESS; ++} ++ + + /***************************************************************************** + * +@@ -2123,6 +2470,18 @@ + } /* i2dw */ + + /***************************************************************************** ++ * ++ * i2w ++ * ++ ****************************************************************************/ ++static void i2w(uint16_t value, unsigned char buffer[]) ++{ ++ buffer[0] = value & 0xFF; ++ buffer[1] = (value >> 8) & 0xFF; ++} /* i2w */ ++ ++ ++/***************************************************************************** + * + * bei2i (big endian integer to host order interger) + * +Index: ccid-1.4.5/src/commands.h +=================================================================== +--- ccid-1.4.5.orig/src/commands.h 2010-06-04 14:31:15.000000000 +0200 ++++ ccid-1.4.5/src/commands.h 2012-01-24 21:25:58.287191632 +0100 +@@ -37,6 +37,14 @@ + unsigned char TxBuffer[], unsigned int TxLength, + unsigned char RxBuffer[], unsigned int *RxLength); + ++RESPONSECODE SecurePINPACECapabilities(unsigned int reader_index, ++ unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength); ++ ++RESPONSECODE SecurePINPACEVerify(unsigned int reader_index, ++ unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength); ++ + RESPONSECODE CmdEscape(unsigned int reader_index, + const unsigned char TxBuffer[], unsigned int TxLength, + unsigned char RxBuffer[], unsigned int *RxLength); +Index: ccid-1.4.5/src/ifdhandler.c +=================================================================== +--- ccid-1.4.5.orig/src/ifdhandler.c 2011-10-11 22:27:44.000000000 +0200 ++++ ccid-1.4.5/src/ifdhandler.c 2012-01-24 21:25:58.291191648 +0100 +@@ -66,6 +66,73 @@ + static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI, + int CWI, int clock_frequency); + static int get_IFSC(ATR_t *atr, int *i); ++static RESPONSECODE do_feature_execute_pace(unsigned int reader_index, ++ PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength, ++ PDWORD pdwBytesReturned); ++ ++static RESPONSECODE do_feature_execute_pace(unsigned int reader_index, ++ PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength, ++ PDWORD pdwBytesReturned) ++{ ++ uint16_t lengthInputData; ++ unsigned int i; ++ RESPONSECODE r; ++ ++ if (TxLength < 3 || !TxBuffer) { ++ DEBUG_CRITICAL("Buffer too small, could not determine length of " ++ "input data"); ++ i = PACE_ERROR_LENGTH_INCONSISTENT; ++ goto err; ++ } ++ ++ memcpy(&lengthInputData, &TxBuffer[1], 2); ++ ++ if (TxLength != 3+lengthInputData) { ++ DEBUG_CRITICAL3("Buffer too small or too big to contain only " ++ "function index and input data (expected %u, got %u)", ++ 3+lengthInputData, TxLength); ++ i = PACE_ERROR_LENGTH_INCONSISTENT; ++ goto err; ++ } ++ ++ switch(*TxBuffer) { ++ case 1: ++ i = RxLength; ++ r = SecurePINPACECapabilities(reader_index, ++ TxBuffer+3, lengthInputData, RxBuffer, &i); ++ *pdwBytesReturned = i; ++ return r; ++ ++ case 2: ++ i = RxLength; ++ r = SecurePINPACEVerify(reader_index, TxBuffer+3, ++ lengthInputData, RxBuffer, &i); ++ *pdwBytesReturned = i; ++ return r; ++ ++ default: ++ DEBUG_CRITICAL2("Unknown PACE function %u", ++ (unsigned char)*TxBuffer); ++ if (RxLength < 6 || !RxBuffer) { ++ DEBUG_CRITICAL2("Need %u more bytes in RxBuffer", ++ RxLength>6 ? (unsigned int)6-RxLength : 0); ++ return IFD_COMMUNICATION_ERROR; ++ } ++ ++ i = PACE_ERROR_UNEXPECTED_DATA; ++ goto err; ++ } ++ ++err: ++ memcpy(RxBuffer, &i, 4); ++ memset(RxBuffer + 4, 0, 2); ++ ++ *pdwBytesReturned = 6; ++ ++ return IFD_SUCCESS; ++} ++ ++ + + + EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice) +@@ -1412,6 +1479,17 @@ + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); + } + ++ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_PACE_CAPABILITIES) ++ { ++ pcsc_tlv -> tag = FEATURE_EXECUTE_PACE; ++ pcsc_tlv -> length = 0x04; /* always 0x04 */ ++ pcsc_tlv -> value = htonl(IOCTL_FEATURE_EXECUTE_PACE); ++ ++ pcsc_tlv++; ++ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); ++ } ++ ++ + /* We can always forward wLcdLayout */ + pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES; + pcsc_tlv -> length = 0x04; /* always 0x04 */ +@@ -1613,6 +1691,12 @@ + } + } + ++ if (IOCTL_FEATURE_EXECUTE_PACE == dwControlCode) ++ { ++ return_value = do_feature_execute_pace(reader_index, TxBuffer, ++ TxLength, RxBuffer, RxLength, pdwBytesReturned); ++ } ++ + if (IFD_SUCCESS != return_value) + *pdwBytesReturned = 0; +