Index: ccid-1.3.11/src/ccid.h
===================================================================
--- ccid-1.3.11.orig/src/ccid.h	2009-06-30 21:42:38.000000000 +0200
+++ ccid-1.3.11/src/ccid.h	2011-11-28 15:47:16.230511000 +0100
@@ -137,8 +137,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 */
@@ -149,6 +151,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 ICCD_A	1	/* ICCD Version A */
 #define ICCD_B	2	/* ICCD Version B */
@@ -216,6 +237,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.3.11/src/ccid_ifdhandler.h
===================================================================
--- ccid-1.3.11.orig/src/ccid_ifdhandler.h	2009-06-30 21:42:38.000000000 +0200
+++ ccid-1.3.11/src/ccid_ifdhandler.h	2011-11-28 15:53:02.574510999 +0100
@@ -38,6 +38,11 @@
 #define IOCTL_FEATURE_IFD_PIN_PROPERTIES \
 	SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)
 #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)
 
 #define DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED 1
 #define DRIVER_OPTION_GEMPC_TWIN_KEY_APDU 2
Index: ccid-1.3.11/src/commands.c
===================================================================
--- ccid-1.3.11.orig/src/commands.c	2009-06-12 15:06:22.000000000 +0200
+++ ccid-1.3.11/src/commands.c	2011-11-28 15:47:16.234511000 +0100
@@ -68,7 +68,19 @@
 	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 i2dw(int value, unsigned char *buffer);
+static void i2w(uint16_t value, unsigned char *buffer);
 
 
 /*****************************************************************************
@@ -691,6 +703,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[11+0xffff];
+    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;
+}
+
 
 /*****************************************************************************
  *
@@ -2081,3 +2428,15 @@
 	buffer[3] = (value >> 24) & 0xFF;
 } /* i2dw */
 
+
+/*****************************************************************************
+ *
+ *					i2w
+ *
+ ****************************************************************************/
+static void i2w(uint16_t value, unsigned char buffer[])
+{
+	buffer[0] = value & 0xFF;
+	buffer[1] = (value >> 8) & 0xFF;
+} /* i2w */
+
Index: ccid-1.3.11/src/commands.h
===================================================================
--- ccid-1.3.11.orig/src/commands.h	2009-01-07 00:14:35.000000000 +0100
+++ ccid-1.3.11/src/commands.h	2011-11-28 15:47:16.234511000 +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.3.11/src/defs.h
===================================================================
--- ccid-1.3.11.orig/src/defs.h	2009-07-01 14:28:01.000000000 +0200
+++ ccid-1.3.11/src/defs.h	2011-11-28 15:47:16.234511000 +0100
@@ -66,16 +66,10 @@
 /* Flag set when a power down is requested */
 #define MASK_POWERFLAGS_PDWN 0x02
 
-/* Kobil readers does not support APDU chaining for T=1 so you can't send an
- * extended APDU. The readers supports a command of up to 512 or 420 bytes.
- * For a Kobil KAAN Base/advanced reader you should use
- *  #define CMD_BUF_SIZE 420
- * For the other models you should use
- *  #define CMD_BUF_SIZE 512
- * Kobil is aware of the problem and do not plan to solve it.
- */
-/* Communication buffer size (max=adpu+Lc+data+Le) */
-#define CMD_BUF_SIZE (4+1+256+1)
+/* Communication buffer size (max=adpu+Lc+data+Le)
+ *  * we use a 64kB for extended APDU on APDU mode readers */
+#define CMD_BUF_SIZE (4 +3 +64*1024 +3)
+
 /* Larger communication buffer size (max=reader status+data+sw) */
 #define RESP_BUF_SIZE (1+256+2)
 
Index: ccid-1.3.11/src/ifdhandler.c
===================================================================
--- ccid-1.3.11.orig/src/ifdhandler.c	2009-07-28 22:57:07.000000000 +0200
+++ ccid-1.3.11/src/ifdhandler.c	2011-11-28 15:47:16.234511000 +0100
@@ -68,6 +68,71 @@
 	int clock_frequency);
 static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI,
 	int CWI, int clock_frequency);
+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:
+            r = SecurePINPACECapabilities(reader_index,
+                    TxBuffer+3, lengthInputData, RxBuffer, &i);
+            *pdwBytesReturned = i;
+            return r;
+
+        case 2:
+            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)
@@ -1266,6 +1331,16 @@
 			iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
 		}
 
+		if (get_ccid_descriptor(reader_index) -> 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);
+		}
+
 #ifdef FEATURE_IFD_PIN_PROPERTIES
 		/* We can always forward wLcdLayout */
 		pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES;
@@ -1365,6 +1440,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;
 
