From 2b6ba3c3c1f0196ee6828029ccda265c1b149314 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Fri, 21 Jun 2013 08:51:43 +0200 Subject: [PATCH] implemented boxing commands for verify/modify separates type definitions into ccid-types.h to be accessible in libnpa --- ccid/src/ccid-types.h | 276 +++++++++++++++++++++++++++++++++++++++++ ccid/src/ccid.h | 239 +----------------------------------- npa/configure.ac | 1 + npa/src/Makefile.am | 9 +- npa/src/boxing.c | 279 +++++++++++++++++++++++++++++++++++++++++- npa/src/ccid-types.h | 1 + 6 files changed, 557 insertions(+), 248 deletions(-) create mode 100644 ccid/src/ccid-types.h create mode 120000 npa/src/ccid-types.h diff --git a/ccid/src/ccid-types.h b/ccid/src/ccid-types.h new file mode 100644 index 0000000..62b2071 --- /dev/null +++ b/ccid/src/ccid-types.h @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2009 Frank Morgner + * + * This file is part of ccid. + * + * ccid is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * ccid is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * ccid. If not, see . + */ +/** + * @file + */ +#ifndef _CCID_TYPES_H +#define _CCID_TYPES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_REQ_CCID 0xA1 + +#define CCID_CONTROL_ABORT 0x01 +#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x02 +#define CCID_CONTROL_GET_DATA_RATES 0x03 + +#define CCID_OPERATION_VERIFY 0x00; +#define CCID_OPERATION_MODIFY 0x01; +#define CCID_ENTRY_VALIDATE 0x02 + +#define CCID_BERROR_CMD_ABORTED 0xff /** Host aborted the current activity */ +#define CCID_BERROR_ICC_MUTE 0xfe /** CCID timed out while talking to the ICC */ +#define CCID_BERROR_XFR_PARITY_ERROR 0xfd /** Parity error while talking to the ICC */ +#define CCID_BERROR_XFR_OVERRUN 0xfc /** Overrun error while talking to the ICC */ +#define CCID_BERROR_HW_ERROR 0xfb /** An all inclusive hardware error occurred */ +#define CCID_BERROR_BAD_ATR_TS 0xf +#define CCID_BERROR_BAD_ATR_TCK 0xf +#define CCID_BERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xf6 +#define CCID_BERROR_ICC_CLASS_NOT_SUPPORTED 0xf5 +#define CCID_BERROR_PROCEDURE_BYTE_CONFLICT 0xf4 +#define CCID_BERROR_DEACTIVATED_PROTOCOL 0xf3 +#define CCID_BERROR_BUSY_WITH_AUTO_SEQUENCE 0xf2 /** Automatic Sequence Ongoing */ +#define CCID_BERROR_PIN_TIMEOUT 0xf0 +#define CCID_BERROR_PIN_CANCELLED 0xef +#define CCID_BERROR_CMD_SLOT_BUSY 0xe0 /** A second command was sent to a slot which was already processing a command. */ +#define CCID_BERROR_CMD_NOT_SUPPORTED 0x00 +#define CCID_BERROR_OK 0x00 + +#define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */ +#define CCID_BSTATUS_OK_INACTIVE 0x01 /** No error. ICC is present and inactive */ +#define CCID_BSTATUS_OK_NOICC 0x02 /** No error. No ICC is present */ +#define CCID_BSTATUS_ERROR_ACTIVE 0x40 /** Failed. An ICC is present and active */ +#define CCID_BSTATUS_ERROR_INACTIVE 0x41 /** Failed. ICC is present and inactive */ +#define CCID_BSTATUS_ERROR_NOICC 0x42 /** Failed. No ICC is present */ + +#define CCID_WLEVEL_DIRECT __constant_cpu_to_le16(0) /** APDU begins and ends with this command */ +#define CCID_WLEVEL_CHAIN_NEXT_XFRBLOCK __constant_cpu_to_le16(1) /** APDU begins with this command, and continue in the next PC_to_RDR_XfrBlock */ +#define CCID_WLEVEL_CHAIN_END __constant_cpu_to_le16(2) /** abData field continues a command APDU and ends the APDU command */ +#define CCID_WLEVEL_CHAIN_CONTINUE __constant_cpu_to_le16(3) /** abData field continues a command APDU and another block is to follow */ +#define CCID_WLEVEL_RESPONSE_IN_DATABLOCK __constant_cpu_to_le16(0x10) /** empty abData field, continuation of response APDU is expected in the next RDR_to_PC_DataBlock */ + +#define CCID_PIN_ENCODING_BIN 0x00 +#define CCID_PIN_ENCODING_BCD 0x01 +#define CCID_PIN_ENCODING_ASCII 0x02 +#define CCID_PIN_UNITS_BYTES 0x80 +#define CCID_PIN_JUSTIFY_RIGHT 0x04 +#define CCID_PIN_CONFIRM_NEW 0x01 +#define CCID_PIN_INSERT_OLD 0x02 +#define CCID_PIN_NO_MSG 0x00 +#define CCID_PIN_MSG1 0x01 +#define CCID_PIN_MSG2 0x02 +#define CCID_PIN_MSG_REF 0x03 +#define CCID_PIN_MSG_DEFAULT 0xff + +#define CCID_SLOTS_UNCHANGED 0x00 +#define CCID_SLOT1_CARD_PRESENT 0x01 +#define CCID_SLOT1_CHANGED 0x02 +#define CCID_SLOT2_CARD_PRESENT 0x04 +#define CCID_SLOT2_CHANGED 0x08 +#define CCID_SLOT3_CARD_PRESENT 0x10 +#define CCID_SLOT3_CHANGED 0x20 +#define CCID_SLOT4_CARD_PRESENT 0x40 +#define CCID_SLOT4_CHANGED 0x80 + +#define CCID_EXT_APDU_MAX (4 + 3 + 0xffff + 3) +#define CCID_SHORT_APDU_MAX (4 + 1 + 0xff + 1) + +struct ccid_class_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdCCID; + uint8_t bMaxSlotIndex; + uint8_t bVoltageSupport; + uint32_t dwProtocols; + uint32_t dwDefaultClock; + uint32_t dwMaximumClock; + uint8_t bNumClockSupport; + uint32_t dwDataRate; + uint32_t dwMaxDataRate; + uint8_t bNumDataRatesSupported; + uint32_t dwMaxIFSD; + uint32_t dwSynchProtocols; + uint32_t dwMechanical; + uint32_t dwFeatures; + uint32_t dwMaxCCIDMessageLength; + uint8_t bClassGetResponse; + uint8_t bclassEnvelope; + uint16_t wLcdLayout; + uint8_t bPINSupport; + uint8_t bMaxCCIDBusySlots; +} __attribute__ ((packed)); + +typedef struct { + uint8_t bmFindexDindex; + uint8_t bmTCCKST0; + uint8_t bGuardTimeT0; + uint8_t bWaitingIntegerT0; + uint8_t bClockStop; +} __attribute__ ((packed)) abProtocolDataStructure_T0_t; +typedef struct { + uint8_t bmFindexDindex; + uint8_t bmTCCKST1; + uint8_t bGuardTimeT1; + uint8_t bWaitingIntegersT1; + uint8_t bClockStop; + uint8_t bIFSC; + uint8_t bNadValue; +} __attribute__ ((packed)) abProtocolDataStructure_T1_t; + +typedef struct { + uint8_t bTimeOut; + uint8_t bmFormatString; + uint8_t bmPINBlockString; + uint8_t bmPINLengthFormat; + uint16_t wPINMaxExtraDigit; + uint8_t bEntryValidationCondition; + uint8_t bNumberMessage; + uint16_t wLangId; + uint8_t bMsgIndex; + uint8_t bTeoPrologue1; + uint16_t bTeoPrologue2; +} __attribute__ ((packed)) abPINDataStucture_Verification_t; +typedef struct { + uint8_t bTimeOut; + uint8_t bmFormatString; + uint8_t bmPINBlockString; + uint8_t bmPINLengthFormat; + uint8_t bInsertionOffsetOld; + uint8_t bInsertionOffsetNew; + uint16_t wPINMaxExtraDigit; + uint8_t bConfirmPIN; + uint8_t bEntryValidationCondition; + uint8_t bNumberMessage; + uint16_t wLangId; + uint8_t bMsgIndex1; +} __attribute__ ((packed)) abPINDataStucture_Modification_t; + +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bBWI; + uint16_t wLevelParameter; +} __attribute__ ((packed)) PC_to_RDR_XfrBlock_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t abRFU1; + uint16_t abRFU2; +} __attribute__ ((packed)) PC_to_RDR_IccPowerOff_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t abRFU1; + uint16_t abRFU2; +} __attribute__ ((packed)) PC_to_RDR_GetSlotStatus_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t abRFU1; + uint16_t abRFU2; +} __attribute__ ((packed)) PC_to_RDR_GetParameters_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t abRFU1; + uint16_t abRFU2; +} __attribute__ ((packed)) PC_to_RDR_ResetParameters_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bProtocolNum; + uint16_t abRFU; +} __attribute__ ((packed)) PC_to_RDR_SetParameters_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bBWI; + uint16_t wLevelParameter; +} __attribute__ ((packed)) PC_to_RDR_Secure_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bPowerSelect; + uint16_t abRFU; +} __attribute__ ((packed)) PC_to_RDR_IccPowerOn_t; + +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bStatus; + uint8_t bError; + uint8_t bClockStatus; +} __attribute__ ((packed)) RDR_to_PC_SlotStatus_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bStatus; + uint8_t bError; + uint8_t bChainParameter; +} __attribute__ ((packed)) RDR_to_PC_DataBlock_t; +typedef struct { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bStatus; + uint8_t bError; + uint8_t bProtocolNum; +} __attribute__ ((packed)) RDR_to_PC_Parameters_t; +typedef struct { + uint8_t bMessageType; + uint8_t bmSlotICCState; /* we support 1 slots, so we need 2*1 bits = 1 byte */ +} __attribute__ ((packed)) RDR_to_PC_NotifySlotChange_t; + +struct hid_class_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint32_t bCountryCode; + uint8_t bNumDescriptors; +} __attribute__ ((packed)); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/ccid/src/ccid.h b/ccid/src/ccid.h index 3c72766..9c9b006 100644 --- a/ccid/src/ccid.h +++ b/ccid/src/ccid.h @@ -24,249 +24,12 @@ #include #include +#include "ccid-types.h" #ifdef __cplusplus extern "C" { #endif -#define USB_REQ_CCID 0xA1 - -#define CCID_CONTROL_ABORT 0x01 -#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x02 -#define CCID_CONTROL_GET_DATA_RATES 0x03 - -#define CCID_BERROR_CMD_ABORTED 0xff /** Host aborted the current activity */ -#define CCID_BERROR_ICC_MUTE 0xfe /** CCID timed out while talking to the ICC */ -#define CCID_BERROR_XFR_PARITY_ERROR 0xfd /** Parity error while talking to the ICC */ -#define CCID_BERROR_XFR_OVERRUN 0xfc /** Overrun error while talking to the ICC */ -#define CCID_BERROR_HW_ERROR 0xfb /** An all inclusive hardware error occurred */ -#define CCID_BERROR_BAD_ATR_TS 0xf -#define CCID_BERROR_BAD_ATR_TCK 0xf -#define CCID_BERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xf6 -#define CCID_BERROR_ICC_CLASS_NOT_SUPPORTED 0xf5 -#define CCID_BERROR_PROCEDURE_BYTE_CONFLICT 0xf4 -#define CCID_BERROR_DEACTIVATED_PROTOCOL 0xf3 -#define CCID_BERROR_BUSY_WITH_AUTO_SEQUENCE 0xf2 /** Automatic Sequence Ongoing */ -#define CCID_BERROR_PIN_TIMEOUT 0xf0 -#define CCID_BERROR_PIN_CANCELLED 0xef -#define CCID_BERROR_CMD_SLOT_BUSY 0xe0 /** A second command was sent to a slot which was already processing a command. */ -#define CCID_BERROR_CMD_NOT_SUPPORTED 0x00 -#define CCID_BERROR_OK 0x00 - -#define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */ -#define CCID_BSTATUS_OK_INACTIVE 0x01 /** No error. ICC is present and inactive */ -#define CCID_BSTATUS_OK_NOICC 0x02 /** No error. No ICC is present */ -#define CCID_BSTATUS_ERROR_ACTIVE 0x40 /** Failed. An ICC is present and active */ -#define CCID_BSTATUS_ERROR_INACTIVE 0x41 /** Failed. ICC is present and inactive */ -#define CCID_BSTATUS_ERROR_NOICC 0x42 /** Failed. No ICC is present */ - -#define CCID_WLEVEL_DIRECT __constant_cpu_to_le16(0) /** APDU begins and ends with this command */ -#define CCID_WLEVEL_CHAIN_NEXT_XFRBLOCK __constant_cpu_to_le16(1) /** APDU begins with this command, and continue in the next PC_to_RDR_XfrBlock */ -#define CCID_WLEVEL_CHAIN_END __constant_cpu_to_le16(2) /** abData field continues a command APDU and ends the APDU command */ -#define CCID_WLEVEL_CHAIN_CONTINUE __constant_cpu_to_le16(3) /** abData field continues a command APDU and another block is to follow */ -#define CCID_WLEVEL_RESPONSE_IN_DATABLOCK __constant_cpu_to_le16(0x10) /** empty abData field, continuation of response APDU is expected in the next RDR_to_PC_DataBlock */ - -#define CCID_PIN_ENCODING_BIN 0x00 -#define CCID_PIN_ENCODING_BCD 0x01 -#define CCID_PIN_ENCODING_ASCII 0x02 -#define CCID_PIN_UNITS_BYTES 0x80 -#define CCID_PIN_JUSTIFY_RIGHT 0x04 -#define CCID_PIN_CONFIRM_NEW 0x01 -#define CCID_PIN_INSERT_OLD 0x02 -#define CCID_PIN_NO_MSG 0x00 -#define CCID_PIN_MSG1 0x01 -#define CCID_PIN_MSG2 0x02 -#define CCID_PIN_MSG_REF 0x03 -#define CCID_PIN_MSG_DEFAULT 0xff - -#define CCID_SLOTS_UNCHANGED 0x00 -#define CCID_SLOT1_CARD_PRESENT 0x01 -#define CCID_SLOT1_CHANGED 0x02 -#define CCID_SLOT2_CARD_PRESENT 0x04 -#define CCID_SLOT2_CHANGED 0x08 -#define CCID_SLOT3_CARD_PRESENT 0x10 -#define CCID_SLOT3_CHANGED 0x20 -#define CCID_SLOT4_CARD_PRESENT 0x40 -#define CCID_SLOT4_CHANGED 0x80 - -#define CCID_EXT_APDU_MAX (4 + 3 + 0xffff + 3) -#define CCID_SHORT_APDU_MAX (4 + 1 + 0xff + 1) - -struct ccid_class_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdCCID; - __u8 bMaxSlotIndex; - __u8 bVoltageSupport; - __le32 dwProtocols; - __le32 dwDefaultClock; - __le32 dwMaximumClock; - __u8 bNumClockSupport; - __le32 dwDataRate; - __le32 dwMaxDataRate; - __u8 bNumDataRatesSupported; - __le32 dwMaxIFSD; - __le32 dwSynchProtocols; - __le32 dwMechanical; - __le32 dwFeatures; - __le32 dwMaxCCIDMessageLength; - __u8 bClassGetResponse; - __u8 bclassEnvelope; - __le16 wLcdLayout; - __u8 bPINSupport; - __u8 bMaxCCIDBusySlots; -} __attribute__ ((packed)); - -typedef struct { - __u8 bmFindexDindex; - __u8 bmTCCKST0; - __u8 bGuardTimeT0; - __u8 bWaitingIntegerT0; - __u8 bClockStop; -} __attribute__ ((packed)) abProtocolDataStructure_T0_t; -typedef struct { - __u8 bmFindexDindex; - __u8 bmTCCKST1; - __u8 bGuardTimeT1; - __u8 bWaitingIntegersT1; - __u8 bClockStop; - __u8 bIFSC; - __u8 bNadValue; -} __attribute__ ((packed)) abProtocolDataStructure_T1_t; - -typedef struct { - __u8 bTimeOut; - __u8 bmFormatString; - __u8 bmPINBlockString; - __u8 bmPINLengthFormat; - __le16 wPINMaxExtraDigit; - __u8 bEntryValidationCondition; - __u8 bNumberMessage; - __le16 wLangId; - __u8 bMsgIndex; - __u8 bTeoPrologue1; - __le16 bTeoPrologue2; -} __attribute__ ((packed)) abPINDataStucture_Verification_t; -typedef struct { - __u8 bTimeOut; - __u8 bmFormatString; - __u8 bmPINBlockString; - __u8 bmPINLengthFormat; - __u8 bInsertionOffsetOld; - __u8 bInsertionOffsetNew; - __le16 wPINMaxExtraDigit; - __u8 bConfirmPIN; - __u8 bEntryValidationCondition; - __u8 bNumberMessage; - __le16 wLangId; - __u8 bMsgIndex1; -} __attribute__ ((packed)) abPINDataStucture_Modification_t; - -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bBWI; - __le16 wLevelParameter; -} __attribute__ ((packed)) PC_to_RDR_XfrBlock_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 abRFU1; - __le16 abRFU2; -} __attribute__ ((packed)) PC_to_RDR_IccPowerOff_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 abRFU1; - __le16 abRFU2; -} __attribute__ ((packed)) PC_to_RDR_GetSlotStatus_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 abRFU1; - __le16 abRFU2; -} __attribute__ ((packed)) PC_to_RDR_GetParameters_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 abRFU1; - __le16 abRFU2; -} __attribute__ ((packed)) PC_to_RDR_ResetParameters_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bProtocolNum; - __le16 abRFU; -} __attribute__ ((packed)) PC_to_RDR_SetParameters_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bBWI; - __le16 wLevelParameter; -} __attribute__ ((packed)) PC_to_RDR_Secure_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bPowerSelect; - __le16 abRFU; -} __attribute__ ((packed)) PC_to_RDR_IccPowerOn_t; - -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bStatus; - __u8 bError; - __u8 bClockStatus; -} __attribute__ ((packed)) RDR_to_PC_SlotStatus_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bStatus; - __u8 bError; - __u8 bChainParameter; -} __attribute__ ((packed)) RDR_to_PC_DataBlock_t; -typedef struct { - __u8 bMessageType; - __le32 dwLength; - __u8 bSlot; - __u8 bSeq; - __u8 bStatus; - __u8 bError; - __u8 bProtocolNum; -} __attribute__ ((packed)) RDR_to_PC_Parameters_t; -typedef struct { - __u8 bMessageType; - __u8 bmSlotICCState; /* we support 1 slots, so we need 2*1 bits = 1 byte */ -} __attribute__ ((packed)) RDR_to_PC_NotifySlotChange_t; - -struct hid_class_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdHID; - __le32 bCountryCode; - __u8 bNumDescriptors; -} __attribute__ ((packed)); - /** * @brief Initializes reader for relaying * diff --git a/npa/configure.ac b/npa/configure.ac index f97c781..a7e9e18 100644 --- a/npa/configure.ac +++ b/npa/configure.ac @@ -61,6 +61,7 @@ AC_MSG_CHECKING([for iasecc_sm_external_authentication]) AC_TRY_LINK_FUNC(iasecc_sm_external_authentication, [ AC_MSG_RESULT([yes]) ], [ AC_MSG_ERROR([Cannot link against libopensc with SM]) ]) +AC_CHECK_FUNCS([sc_apdu_get_octets]) CPPFLAGS="$saved_CPPFLAGS" LIBS="$saved_LIBS" diff --git a/npa/src/Makefile.am b/npa/src/Makefile.am index 2fe8dbb..00cb360 100644 --- a/npa/src/Makefile.am +++ b/npa/src/Makefile.am @@ -11,19 +11,19 @@ do_subst = $(SED) \ BUILT_SOURCES = cmdline.h cmdline.c -EXTRA_DIST = npa-tool.ggo npa-tool.ggo.in +EXTRA_DIST = npa-tool.ggo npa-tool.ggo.in opensc/src/libopensc/apdu.c EXTRA_DIST += $(shell find -L $(top_srcdir)/src/opensc/src -path '*/.git' -prune -o -type f -a -name '*.h' -print) MAINTAINERCLEANFILES = $(BUILT_SOURCES) npa-tool.ggo $(dist_man1_MANS) dist_man1_MANS = npa-tool.1 libnpa_la_SOURCES = iso-sm.c scutil.c npa.c boxing.c -libnpa_la_LIBADD = $(OPENSSL_LIBS) $(OPENPACE_LIBS) $(OPENSC_LIBS) +libnpa_la_LIBADD = $(OPENSC_LIBS) $(OPENPACE_LIBS) $(OPENSSL_LIBS) libnpa_la_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS) libnpa_la_LDFLAGS = -no-undefined npa_tool_SOURCES = npa-tool.c $(BUILT_SOURCES) -npa_tool_LDADD = $(OPENSSL_LIBS) $(OPENPACE_LIBS) $(OPENSC_LIBS) libnpa.la +npa_tool_LDADD = libnpa.la $(OPENSC_LIBS) $(OPENPACE_LIBS) $(OPENSSL_LIBS) npa_tool_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS) example_SOURCES = example.c @@ -54,7 +54,8 @@ noinst_PROGRAMS = example lib_LTLIBRARIES = libnpa.la noinst_HEADERS = \ - sslutil.h + sslutil.h \ + ccid-types.h nobase_include_HEADERS = \ npa/iso-sm.h \ diff --git a/npa/src/boxing.c b/npa/src/boxing.c index 79b048f..f654865 100644 --- a/npa/src/boxing.c +++ b/npa/src/boxing.c @@ -19,13 +19,33 @@ * libnpa. If not, see . */ +#include "ccid-types.h" #include #include #include #include +#include #include #include +#if _WIN32 +/* FIXME might not always work */ +#define htole16(x) (x) +#define htole32(x) (x) +#else +#ifndef _BSD_SOURCE +#define _BSD_SOURCE /* See feature_test_macros(7) */ +#endif +#include +#endif + +#if HAVE_SC_APDU_GET_OCTETS +#include "libopensc/internal.h" +#else +/* Pull request for exporting sc_apdu_get_octets is pending. */ +#include "libopensc/apdu.c" +#endif + static const u8 boxing_cla = 0xff; static const u8 boxing_ins = 0x9a; static const u8 boxing_p1 = 0x04; @@ -209,9 +229,9 @@ int boxing_buf_to_pace_output(sc_context_t *ctx, sc_copy_asn1_entry(g_EstablishPACEChannelOutput_data, EstablishPACEChannelOutput_data); sc_format_asn1_entry(EstablishPACEChannelOutput_data+0, - &output->result, &result_len, 0); + &output->result, &result_len, 0); sc_format_asn1_entry(EstablishPACEChannelOutput_data+1, - &status_mse_set_at, &status_mse_set_at_len, 0); + &status_mse_set_at, &status_mse_set_at_len, 0); sc_format_asn1_entry(EstablishPACEChannelOutput_data+2, &output->ef_cardaccess, &output->ef_cardaccess_length, 0); sc_format_asn1_entry(EstablishPACEChannelOutput_data+3, @@ -236,9 +256,256 @@ int boxing_buf_to_pace_output(sc_context_t *ctx, return SC_SUCCESS; } -static int boxing_perform_verify(struct sc_reader *reader, struct sc_pin_cmd_data *data) +#define CCID_PIN_TIMEOUT 30 +#define CCID_DISPLAY_DEFAULT 0xff +static int boxing_pin_cmd_to_buf(sc_context_t *ctx, + const struct sc_pin_cmd_data *data, + unsigned char **pc_to_rdr_secure, size_t *pc_to_rdr_secure_len) { - return SC_ERROR_NOT_SUPPORTED; + PC_to_RDR_Secure_t *secure; + abPINDataStucture_Modification_t *modify; + abPINDataStucture_Verification_t *verify; + uint16_t wLangId = 0, + bTeoPrologue2 = 0, + wPINMaxExtraDigit; + uint8_t bTimeOut = CCID_PIN_TIMEOUT, + bNumberMessage = CCID_DISPLAY_DEFAULT, + bTeoPrologue1 = 0, + bMsgIndex = 0, + bMessageType = 0x69, + bSlot = 0, + bSeq = 0, + bBWI = 0xff, + wLevelParameter = 0, + bEntryValidationCondition = CCID_ENTRY_VALIDATE, + bmFormatString, bmPINLengthFormat, bmPINBlockString; + const struct sc_pin_cmd_pin *pin_ref; + int r; + unsigned char *pinapdu = NULL; + size_t pinapdu_len = 0; + + if (!data || !pc_to_rdr_secure || !pc_to_rdr_secure_len) { + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + + pin_ref = data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? + &data->pin2 : &data->pin1; + + wPINMaxExtraDigit = htole16( + (0xff & pin_ref->min_length) << 8) + | (pin_ref->max_length & 0xff); + + bmFormatString = CCID_PIN_UNITS_BYTES + | ((pin_ref->offset & 0xf) << 3); + switch (pin_ref->encoding) { + case SC_PIN_ENCODING_ASCII: + bmFormatString |= CCID_PIN_ENCODING_ASCII; + break; + case SC_PIN_ENCODING_BCD: + bmFormatString |= CCID_PIN_ENCODING_BCD; + break; + default: + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + + /* GLP PINs expect the effective PIN length from bit 4 */ + bmPINLengthFormat = pin_ref->encoding == SC_PIN_ENCODING_GLP ? + 0x04 : 0x00; + + if (pin_ref->encoding == SC_PIN_ENCODING_GLP) { + /* GLP PIN length is encoded in 4 bits and block size is always 8 bytes */ + bmPINBlockString = 0x40 | 0x08; + } else if (pin_ref->encoding == SC_PIN_ENCODING_ASCII && data->flags & SC_PIN_CMD_NEED_PADDING) { + bmPINBlockString = pin_ref->pad_length; + } else { + bmPINBlockString = 0x00; + } + + r = sc_apdu_get_octets(ctx, data->apdu, &pinapdu, &pinapdu_len, + SC_PROTO_T1); + if (r < 0) + goto err; + + switch (data->cmd) { + case SC_PIN_CMD_VERIFY: + *pc_to_rdr_secure_len = sizeof *secure + 1 + + sizeof *verify + pinapdu_len; + break; + + case SC_PIN_CMD_CHANGE: + *pc_to_rdr_secure_len = sizeof *secure + 1 + + sizeof *modify + 3 + pinapdu_len; + break; + + default: + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + + *pc_to_rdr_secure = malloc(*pc_to_rdr_secure_len); + if (!*pc_to_rdr_secure) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } + secure = (PC_to_RDR_Secure_t *) *pc_to_rdr_secure; + secure->bMessageType = bMessageType; + secure->dwLength = htole32((*pc_to_rdr_secure_len) - sizeof *secure); + secure->bSlot = bSlot; + secure->bSeq = bSeq; + secure->bBWI = bBWI; + secure->wLevelParameter = wLevelParameter; + + switch (data->cmd) { + case SC_PIN_CMD_VERIFY: + /* bPINOperation */ + *((*pc_to_rdr_secure) + sizeof *secure) = CCID_OPERATION_VERIFY; + verify = (abPINDataStucture_Verification_t *) + ((*pc_to_rdr_secure) + sizeof *secure + 1); + verify->bTimeOut = bTimeOut; + verify->bmFormatString = bmFormatString; + verify->bmPINBlockString = bmPINBlockString; + verify->bmPINLengthFormat = bmPINLengthFormat; + verify->wPINMaxExtraDigit = wPINMaxExtraDigit; + verify->bEntryValidationCondition = bEntryValidationCondition; + verify->bNumberMessage = bNumberMessage; + verify->wLangId = wLangId; + verify->bMsgIndex = bMsgIndex; + verify->bTeoPrologue1 = bTeoPrologue1; + verify->bTeoPrologue2 = bTeoPrologue2; + + memcpy((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *verify, + pinapdu, pinapdu_len); + break; + + case SC_PIN_CMD_CHANGE: + /* bPINOperation */ + *((*pc_to_rdr_secure) + sizeof *secure) = CCID_OPERATION_MODIFY; + modify = (abPINDataStucture_Modification_t *) + ((*pc_to_rdr_secure) + sizeof *secure + 1); + modify->bTimeOut = bTimeOut; + modify->bmFormatString = bmFormatString; + modify->bmPINBlockString = bmPINBlockString; + modify->bmPINLengthFormat = bmPINLengthFormat; + if (!(data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) + && data->pin1.offset) { + modify->bInsertionOffsetOld = data->pin1.offset - 5; + } else { + modify->bInsertionOffsetOld = 0; + } + modify->bInsertionOffsetNew = data->pin2.offset ? data->pin2.offset - 5 : 0; + modify->wPINMaxExtraDigit = wPINMaxExtraDigit; + modify->bConfirmPIN = CCID_PIN_CONFIRM_NEW + | (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0 : CCID_PIN_INSERT_OLD); + modify->bEntryValidationCondition = bEntryValidationCondition; + modify->bNumberMessage = bNumberMessage; + modify->wLangId = wLangId; + modify->bMsgIndex1 = bMsgIndex; + *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 0) = + bTeoPrologue1; + *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 1) = + bTeoPrologue1; + *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 2) = + bTeoPrologue1; + + memcpy((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 3, + pinapdu, pinapdu_len); + break; + + default: + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + + r = SC_SUCCESS; + +err: + free(pinapdu); + if (r < 0 && *pc_to_rdr_secure) { + free(*pc_to_rdr_secure); + *pc_to_rdr_secure = NULL; + } + + return r; +} + +#define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */ +static int boxing_buf_to_verify_result(sc_context_t *ctx, + const unsigned char *rdr_to_pc_datablock, + size_t rdr_to_pc_datablock_len, + sc_apdu_t *apdu) +{ + RDR_to_PC_DataBlock_t *datablock = + (RDR_to_PC_DataBlock_t *) rdr_to_pc_datablock; + + if (!rdr_to_pc_datablock + || rdr_to_pc_datablock_len < sizeof *datablock + || datablock->bMessageType != 0x80) + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + + if (datablock->bStatus != CCID_BSTATUS_OK_ACTIVE) + return SC_ERROR_TRANSMIT_FAILED; + + return sc_apdu_set_resp(ctx, apdu, + rdr_to_pc_datablock + sizeof *datablock, + htole32(datablock->dwLength)); +} + +static int boxing_perform_verify(struct sc_reader *reader, + struct sc_pin_cmd_data *data) +{ + u8 rbuf[0xff]; + sc_apdu_t apdu; + int r; + + memset(&apdu, 0, sizeof(apdu)); + apdu.cse = SC_APDU_CASE_4_SHORT; + apdu.cla = boxing_cla; + apdu.ins = boxing_ins; + apdu.p1 = boxing_p1; + apdu.p2 = boxing_p2_PC_to_RDR_Secure; + apdu.resp = rbuf; + apdu.resplen = sizeof rbuf; + apdu.le = sizeof rbuf; + + if (!reader || !reader->ops || !reader->ops->transmit) { + r = SC_ERROR_NOT_SUPPORTED; + goto err; + } + + r = boxing_pin_cmd_to_buf(reader->ctx, data, + (unsigned char **) &apdu.data, &apdu.datalen); + if (r < 0) { + sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, + "Error encoding PC_to_RDR_Secure"); + goto err; + } + apdu.lc = apdu.datalen; + + r = SC_SUCCESS; + + r = reader->ops->transmit(reader, &apdu); + if (r < 0) { + sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, + "Error performing PC_to_RDR_Secure"); + goto err; + } + + if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { + sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, + "Error decoding PC_to_RDR_Secure"); + r = SC_ERROR_NOT_SUPPORTED; + goto err; + } + + r = boxing_buf_to_verify_result(reader->ctx, apdu.resp, apdu.resplen, + data->apdu); + +err: + free((unsigned char *) apdu.data); + + return r; } static int boxing_perform_pace(struct sc_reader *reader, @@ -416,7 +683,7 @@ int boxing_pace_capabilities_to_buf(sc_context_t *ctx, return sc_asn1_encode(ctx, PACECapabilities, asn1, asn1_len); } -#ifdef DISABLE_GLOBAL_BOXING_INITIALIZATION +#ifndef DISABLE_GLOBAL_BOXING_INITIALIZATION static #endif void sc_detect_boxing_cmds(sc_reader_t *reader) @@ -464,7 +731,7 @@ void sc_detect_boxing_cmds(sc_reader_t *reader) } } -#ifdef DISABLE_GLOBAL_BOXING_INITIALIZATION +#ifndef DISABLE_GLOBAL_BOXING_INITIALIZATION void sc_initialize_boxing_cmds(sc_context_t *ctx) { sc_reader_t *reader; diff --git a/npa/src/ccid-types.h b/npa/src/ccid-types.h new file mode 120000 index 0000000..0e46797 --- /dev/null +++ b/npa/src/ccid-types.h @@ -0,0 +1 @@ +../../ccid/src/ccid-types.h \ No newline at end of file