Files
vsmartcard/ccid/patches/ccid-1.4.4.patch
frankmorgner 4af89d967f patch to newest version of libccid
git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@488 96b47cad-a561-4643-ad3b-153ac7d7599c
2011-08-09 11:20:29 +00:00

577 lines
19 KiB
Diff

Index: ccid-1.4.4/src/ccid.h
===================================================================
--- ccid-1.4.4.orig/src/ccid.h 2011-08-09 12:43:45.364997651 +0200
+++ ccid-1.4.4/src/ccid.h 2011-08-09 12:44:14.611616565 +0200
@@ -142,8 +142,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 */
@@ -154,6 +156,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 */
@@ -230,6 +251,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.4/src/ccid_ifdhandler.h
===================================================================
--- ccid-1.4.4.orig/src/ccid_ifdhandler.h 2011-08-09 12:43:45.373002117 +0200
+++ ccid-1.4.4/src/ccid_ifdhandler.h 2011-08-09 13:00:19.457796237 +0200
@@ -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.4/src/commands.c
===================================================================
--- ccid-1.4.4.orig/src/commands.c 2011-08-09 12:43:45.381006510 +0200
+++ ccid-1.4.4/src/commands.c 2011-08-09 12:46:11.466014831 +0200
@@ -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);
@@ -753,6 +765,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[1024];
+ 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;
+}
+
/*****************************************************************************
*
@@ -2155,6 +2502,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.4/src/commands.h
===================================================================
--- ccid-1.4.4.orig/src/commands.h 2011-08-09 12:43:45.393012512 +0200
+++ ccid-1.4.4/src/commands.h 2011-08-09 12:44:14.615618285 +0200
@@ -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.4/src/ifdhandler.c
===================================================================
--- ccid-1.4.4.orig/src/ifdhandler.c 2011-08-09 12:43:45.409020406 +0200
+++ ccid-1.4.4/src/ifdhandler.c 2011-08-09 12:50:19.537986427 +0200
@@ -65,6 +65,71 @@
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:
+ 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)
@@ -1400,6 +1465,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 */
@@ -1582,6 +1658,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;