diff --git a/ccid/configure.ac b/ccid/configure.ac index 437773b..599323d 100644 --- a/ccid/configure.ac +++ b/ccid/configure.ac @@ -88,6 +88,7 @@ fi AC_SUBST(OPENSSL_CFLAGS) AC_SUBST(OPENSSL_LIBS) AM_CONDITIONAL(WITH_PACE, test "${enable_pace}" != "no") +AM_COND_IF(WITH_PACE, [AC_DEFINE(WITH_PACE, 1, [enable PACE support])]) # Checks for header files. diff --git a/ccid/pcsclite_trunk.patch b/ccid/pcsclite_trunk.patch new file mode 100644 index 0000000..af7ade3 --- /dev/null +++ b/ccid/pcsclite_trunk.patch @@ -0,0 +1,234 @@ +Index: PCSC/src/PCSC/reader.h.in +=================================================================== +--- PCSC/src/PCSC/reader.h.in (Revision 4999) ++++ PCSC/src/PCSC/reader.h.in (Arbeitskopie) +@@ -121,6 +121,7 @@ + #define FEATURE_IFD_DISPLAY_PROPERTIES 0x11 + #define FEATURE_GET_TLV_PROPERTIES 0x12 + #define FEATURE_CCID_ESC_COMMAND 0x13 ++#define FEATURE_EXECUTE_PACE 0x20 + + /* structures used (but not defined) in PC/SC Part 10: + * "IFDs with Secure Pin Entry Capabilities" */ +Index: Drivers/ccid/src/ifdhandler.c +=================================================================== +--- Drivers/ccid/src/ifdhandler.c (Revision 4999) ++++ Drivers/ccid/src/ifdhandler.c (Arbeitskopie) +@@ -1384,6 +1384,16 @@ + iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); + } + ++ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_SPECIAL) ++ { ++ 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 */ +@@ -1548,6 +1558,16 @@ + } + } + ++ if (IOCTL_FEATURE_EXECUTE_PACE == dwControlCode) ++ { ++ unsigned int iBytesReturned; ++ ++ iBytesReturned = RxLength; ++ return_value = SecurePINSpecialVerify(reader_index, TxBuffer, TxLength, ++ RxBuffer, &iBytesReturned); ++ *pdwBytesReturned = iBytesReturned; ++ } ++ + if (IFD_SUCCESS != return_value) + *pdwBytesReturned = 0; + +Index: Drivers/ccid/src/commands.c +=================================================================== +--- Drivers/ccid/src/commands.c (Revision 4999) ++++ Drivers/ccid/src/commands.c (Arbeitskopie) +@@ -68,7 +68,13 @@ + unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length, + unsigned char rx_buffer[]); + ++static RESPONSECODE SecurePINSpecial(unsigned int reader_index, ++ const unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength, ++ unsigned char bPINOperation); ++ + static void i2dw(int value, unsigned char *buffer); ++static void i2w(int value, unsigned char *buffer); + + + /***************************************************************************** +@@ -712,7 +718,96 @@ + return ret; + } /* SecurePINModify */ + ++RESPONSECODE SecurePINSpecialVerify(unsigned int reader_index, ++ const unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength) ++{ ++ /* bPINOperation: PIN Special Capabilities */ ++ return SecurePINSpecial(reader_index, TxBuffer, TxLength, RxBuffer, ++ RxLength, 0x11); ++} + ++RESPONSECODE SecurePINSpecialCapabilities(unsigned int reader_index, ++ const unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength) ++{ ++ /* bPINOperation: PIN Special Capabilities */ ++ return SecurePINSpecial(reader_index, TxBuffer, TxLength, RxBuffer, ++ RxLength, 0x10); ++} ++ ++static RESPONSECODE SecurePINSpecial(unsigned int reader_index, ++ const unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength, ++ unsigned char bPINOperation) ++{ ++ unsigned char cmd[11+CMD_BUF_SIZE]; ++ int length; ++ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); ++ status_t res; ++ ++ cmd[0] = 0x69; /* Secure */ ++ i2dw(TxLength, cmd+1); /* dwLength */ ++ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */ ++ cmd[6] = (*ccid_descriptor->pbSeq)++; ++ cmd[7] = 0; /* bBWI */ ++ cmd[8] = 0; /* wLevelParameter */ ++ cmd[9] = 0; ++ cmd[10] = bPINOperation; ++ ++ 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); ++ length = *RxLength; ++ return IFD_ERROR_INSUFFICIENT_BUFFER; ++ } ++ ++ return IFD_SUCCESS; ++} ++ ++ + /***************************************************************************** + * + * Escape +@@ -729,7 +824,7 @@ + int old_read_timeout; + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + +- old_read_timeout = ccid_descriptor -> readTimeout; ++ old_read_timeout= ccid_descriptor -> readTimeout; + ccid_descriptor -> readTimeout = 30*1000; /* 30 seconds */ + + again: +@@ -2113,3 +2208,15 @@ + buffer[3] = (value >> 24) & 0xFF; + } /* i2dw */ + ++ ++/***************************************************************************** ++ * ++ * i2w ++ * ++ ****************************************************************************/ ++static void i2w(int value, unsigned char buffer[]) ++{ ++ buffer[0] = value & 0xFF; ++ buffer[1] = (value >> 8) & 0xFF; ++} /* i2w */ ++ +Index: Drivers/ccid/src/commands.h +=================================================================== +--- Drivers/ccid/src/commands.h (Revision 4999) ++++ Drivers/ccid/src/commands.h (Arbeitskopie) +@@ -37,6 +37,14 @@ + unsigned char TxBuffer[], unsigned int TxLength, + unsigned char RxBuffer[], unsigned int *RxLength); + ++RESPONSECODE SecurePINSpecialCapabilities(unsigned int reader_index, ++ const unsigned char TxBuffer[], unsigned int TxLength, ++ unsigned char RxBuffer[], unsigned int *RxLength); ++ ++RESPONSECODE SecurePINSpecialVerify(unsigned int reader_index, ++ const 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: Drivers/ccid/src/ccid.h +=================================================================== +--- Drivers/ccid/src/ccid.h (Revision 4999) ++++ Drivers/ccid/src/ccid.h (Arbeitskopie) +@@ -144,6 +144,7 @@ + /* Features from bPINSupport */ + #define CCID_CLASS_PIN_VERIFY 0x01 + #define CCID_CLASS_PIN_MODIFY 0x02 ++#define CCID_CLASS_PIN_SPECIAL 0x10 + + /* See CCID specs ch. 4.2.1 */ + #define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */ +Index: Drivers/ccid/src/ccid_ifdhandler.h +=================================================================== +--- Drivers/ccid/src/ccid_ifdhandler.h (Revision 4999) ++++ Drivers/ccid/src/ccid_ifdhandler.h (Arbeitskopie) +@@ -37,6 +37,8 @@ + SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC) + #define IOCTL_FEATURE_GET_TLV_PROPERTIES \ + SCARD_CTL_CODE(FEATURE_GET_TLV_PROPERTIES + CLASS2_IOCTL_MAGIC) ++#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 diff --git a/ccid/src/Makefile.am b/ccid/src/Makefile.am index 44bf38c..cf3d422 100644 --- a/ccid/src/Makefile.am +++ b/ccid/src/Makefile.am @@ -1,13 +1,5 @@ IFDNFC_LIB = libifdnfc.$(DYN_LIB_EXT) -bin_PROGRAMS = -if WITH_CCID -bin_PROGRAMS += ccid-emulator -endif -if WITH_PACE -bin_PROGRAMS += pace-tool -endif - ccid_emulator_SOURCES = ccid.c usbstring.c usb.c binutil.c scutil.c ccid_emulator_LDADD = $(OPENSC_LIBS) $(PTHREAD_LIBS) ccid_emulator_CFLAGS = $(OPENSC_CFLAGS) $(PTHREAD_CFLAGS) @@ -16,4 +8,16 @@ pace_tool_SOURCES = sm.c pace-tool.c binutil.c scutil.c pace.c pace_lib.c pace_tool_LDADD = $(OPENSC_LIBS) $(OPENSSL_LIBS) pace_tool_CFLAGS = $(OPENSC_CFLAGS) $(OPENSSL_CFLAGS) +bin_PROGRAMS = +if WITH_CCID +bin_PROGRAMS += ccid-emulator +endif +if WITH_PACE +bin_PROGRAMS += pace-tool + +ccid_emulator_SOURCES += sm.c pace.c pace_lib.c +ccid_emulator_LDADD += $(OPENSSL_LIBS) +ccid_emulator_CFLAGS += $(OPENSSL_CFLAGS) +endif + noinst_HEADERS = binutil.h ccid.h pace.h pace_lib.h scutil.h sm.h usbstring.h diff --git a/ccid/src/ccid.c b/ccid/src/ccid.c index 5a371f4..21ad4cc 100644 --- a/ccid/src/ccid.c +++ b/ccid/src/ccid.c @@ -28,6 +28,14 @@ #include "ccid.h" #include "scutil.h" +#include "config.h" + +#ifdef WITH_PACE +#include "pace.h" +#include "sm.h" + +struct sm_ctx sctx; +#endif static sc_context_t *ctx = NULL; static sc_card_t *card_in_slot[SC_MAX_SLOTS]; @@ -127,6 +135,10 @@ int ccid_initialize(int reader_id, const char *cdriver, int verbose) ccid_desc.bMaxSlotIndex = reader->slot_count - 1; +#ifdef WITH_PACE + memset(&sctx, 0, sizeof(sctx)); +#endif + return SC_SUCCESS; } @@ -140,6 +152,11 @@ void ccid_shutdown() } if (ctx) sc_release_context(ctx); + +#ifdef WITH_PACE + pace_sm_ctx_clear_free(sctx.cipher_ctx); + memset(&sctx, 0, sizeof(sctx)); +#endif } static int get_rapdu(sc_apdu_t *apdu, size_t slot, __u8 **buf, size_t *resplen) @@ -153,13 +170,18 @@ static int get_rapdu(sc_apdu_t *apdu, size_t slot, __u8 **buf, size_t *resplen) apdu->resplen = apdu->le; /* Get two more bytes to later use as return buffer including sw1 and sw2 */ - apdu->resp = malloc(apdu->resplen + sizeof(__u8) + sizeof(__u8)); + apdu->resp = realloc(*buf, apdu->resplen + sizeof(__u8) + sizeof(__u8)); if (!apdu->resp) { sc_result = SC_ERROR_OUT_OF_MEMORY; goto err; } + *buf = apdu->resp; +#ifdef WITH_PACE + sc_result = sm_transmit_apdu(&sctx, card_in_slot[slot], apdu); +#else sc_result = sc_transmit_apdu(card_in_slot[slot], apdu); +#endif if (sc_result < 0) { goto err; } @@ -179,13 +201,9 @@ static int get_rapdu(sc_apdu_t *apdu, size_t slot, __u8 **buf, size_t *resplen) (unsigned int) *resplen, !*resplen ? "" : "s", apdu->sw1, apdu->sw2); - SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_SUCCESS); + sc_result = SC_SUCCESS; err: - if (apdu->resp) { - free(apdu->resp); - } - SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, sc_result); } @@ -425,7 +443,7 @@ perform_PC_to_RDR_XfrBlock(const u8 *in, __u8** out, size_t *outlen) int sc_result, r; size_t resplen = 0; sc_apdu_t apdu; - __u8 *abDataOut; + __u8 *abDataOut = NULL; RDR_to_PC_DataBlock_t *result; if (!in || !out || !outlen) @@ -739,7 +757,7 @@ perform_PC_to_RDR_Secure(const __u8 *in, __u8** out, size_t *outlen) sc_ui_hints_t hints; const PC_to_RDR_Secure_t *request = (PC_to_RDR_Secure_t *) in; const __u8* abData = in + sizeof *request; - u8 *abDataOut; + u8 *abDataOut = NULL; size_t resplen = 0; RDR_to_PC_DataBlock_t *result; @@ -792,6 +810,20 @@ perform_PC_to_RDR_Secure(const __u8 *in, __u8** out, size_t *outlen) abPINApdu = (__u8*) modify + sizeof(*modify); apdulen = __le32_to_cpu(request->dwLength) - sizeof(*modify) - sizeof(__u8); break; +#ifdef WITH_PACE + case 0x10: + sc_result = + GetReadersPACECapabilities(card_in_slot[request->bSlot], + abData + 1, &abDataOut, &resplen); + goto err; + break; + case 0x11: + sc_result = EstablishPACEChannel(&sctx, + card_in_slot[request->bSlot], abData + 1, &abDataOut, + &resplen, &sctx); + goto err; + break; +#endif case 0x04: // Cancel PIN function default: diff --git a/ccid/src/pace.c b/ccid/src/pace.c index 3d74bdc..fe63db6 100644 --- a/ccid/src/pace.c +++ b/ccid/src/pace.c @@ -869,6 +869,9 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, r = SC_ERROR_OUT_OF_MEMORY; goto err; } + r = reset_ssc(sctx->authentication_ctx); + if (r < 0) + goto err; sctx->cipher_ctx = sctx->authentication_ctx; sctx->authenticate = pace_sm_authenticate; sctx->encrypt = pace_sm_encrypt; @@ -878,8 +881,7 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, sctx->post_transmit = pace_sm_post_transmit; sctx->padding_indicator = SM_ISO_PADDING; sctx->block_length = EVP_CIPHER_block_size(pctx->cipher); - - r = reset_ssc(sctx->authentication_ctx); + sctx->active = 1; err: if (ef_cardaccess && !second_execution) diff --git a/ccid/src/sm.c b/ccid/src/sm.c index 6c9e33a..237ce3a 100644 --- a/ccid/src/sm.c +++ b/ccid/src/sm.c @@ -583,6 +583,11 @@ int sm_transmit_apdu(const struct sm_ctx *sctx, sc_card_t *card, SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, sc_transmit_apdu(card, apdu)); } + if (!sctx || !sctx->active) { + sc_debug(card->ctx, "Secure messaging disabled."); + SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, sc_transmit_apdu(card, apdu)); + } + if (sctx->pre_transmit) SC_TEST_RET(card->ctx, sctx->pre_transmit(card, sctx, apdu), "Could not complete SM specific pre transmit routine"); diff --git a/ccid/src/sm.h b/ccid/src/sm.h index 85c78b1..537f86d 100644 --- a/ccid/src/sm.h +++ b/ccid/src/sm.h @@ -29,6 +29,8 @@ extern "C" { #define SM_NO_PADDING 0x02 struct sm_ctx { + unsigned char active; + u8 padding_indicator; size_t block_length;