[pkg-opensc-commit] [opensc] 190/295: Added support for PIN commands via escape commands
Eric Dorland
eric at moszumanska.debian.org
Sat Jun 24 21:11:30 UTC 2017
This is an automated email from the git hooks/post-receive script.
eric pushed a commit to branch master
in repository opensc.
commit 40acedcc218c7770243a94eb5bc9d43078dd2209
Author: Frank Morgner <morgner at informatik.hu-berlin.de>
Date: Wed Nov 11 00:28:16 2015 +0100
Added support for PIN commands via escape commands
As defined in BSI TR-03119 to issue SCardTransmit (with Uses
Pseudo-APDU) instead of SCardControl (with FEATURE_VERIFY_PIN_DIRECT).
It allows using a very basic PC/SC reader driver without special support
for PIN verification or modification (such as the default CCID driver on
Windows).
Also gets IFD vendor information via escape commands.
PC/SC's Get Uid command is now only triggered if enable_escape = true;
was set by the user to allow disabling wrapped commands on broken
readers (see https://github.com/OpenSC/OpenSC/issues/810)
---
etc/opensc.conf.in | 6 +
src/libopensc/Makefile.am | 4 +-
src/libopensc/Makefile.mak | 2 +-
src/libopensc/card.c | 4 +
src/libopensc/ccid-types.h | 281 +++++++++++
src/libopensc/libopensc.exports | 6 +
src/libopensc/opensc.h | 1 +
src/libopensc/reader-ctapi.c | 2 +
src/libopensc/reader-openct.c | 2 +
src/libopensc/reader-pcsc.c | 52 +-
src/libopensc/reader-tr03119.c | 1012 +++++++++++++++++++++++++++++++++++++++
src/libopensc/reader-tr03119.h | 57 +++
src/pkcs11/slot.c | 33 +-
13 files changed, 1429 insertions(+), 33 deletions(-)
diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in
index bf74b63..5419b44 100644
--- a/etc/opensc.conf.in
+++ b/etc/opensc.conf.in
@@ -103,6 +103,12 @@ app default {
# Default: true
# enable_pinpad = false;
#
+ # Detect reader capabilities with escape commands (wrapped APDUs with
+ # CLA=0xFF as defined by PC/SC pt. 3 and BSI TR-03119, e.g. for getting
+ # the UID, escaped PIN commands and the reader's firmware version)
+ # Default: false
+ # enable_escape = true;
+ #
# Use specific pcsc provider.
# Default: @DEFAULT_PCSC_PROVIDER@
# provider_library = @DEFAULT_PCSC_PROVIDER@
diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am
index d836636..9cd44da 100644
--- a/src/libopensc/Makefile.am
+++ b/src/libopensc/Makefile.am
@@ -12,7 +12,7 @@ noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.
errors.h types.h compression.h itacns.h iso7816.h \
authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \
pace.h cwa14890.h cwa-dnie.h card-gids.h aux-data.h \
- jpki.h sc-ossl-compat.h card-npa.h
+ jpki.h sc-ossl-compat.h card-npa.h ccid-types.h reader-tr03119.h
AM_CPPFLAGS = -DOPENSC_CONF_PATH=\"$(sysconfdir)/opensc.conf\" \
-I$(top_srcdir)/src
@@ -30,7 +30,7 @@ libopensc_la_SOURCES = \
\
muscle.c muscle-filesystem.c \
\
- ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c \
+ ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c reader-tr03119.c \
\
card-setcos.c card-miocos.c card-flex.c card-gpk.c \
card-cardos.c card-tcos.c card-default.c \
diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak
index 1a3eb2a..a2431d3 100644
--- a/src/libopensc/Makefile.mak
+++ b/src/libopensc/Makefile.mak
@@ -12,7 +12,7 @@ OBJECTS = \
\
muscle.obj muscle-filesystem.obj \
\
- ctbcs.obj reader-ctapi.obj reader-pcsc.obj reader-openct.obj \
+ ctbcs.obj reader-ctapi.obj reader-pcsc.obj reader-openct.obj reader-tr03119.obj \
\
card-setcos.obj card-miocos.obj card-flex.obj card-gpk.obj \
card-cardos.obj card-tcos.obj card-default.obj \
diff --git a/src/libopensc/card.c b/src/libopensc/card.c
index dd96e17..73f8ede 100644
--- a/src/libopensc/card.c
+++ b/src/libopensc/card.c
@@ -29,6 +29,7 @@
#endif
#include <string.h>
+#include "reader-tr03119.h"
#include "internal.h"
#include "asn1.h"
#include "common/compat_strlcpy.h"
@@ -204,6 +205,9 @@ int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out)
card->reader = reader;
card->ctx = ctx;
+ if (reader->flags & SC_READER_ENABLE_ESCAPE)
+ sc_detect_escape_cmds(reader);
+
memcpy(&card->atr, &reader->atr, sizeof(card->atr));
memcpy(&card->uid, &reader->uid, sizeof(card->uid));
diff --git a/src/libopensc/ccid-types.h b/src/libopensc/ccid-types.h
new file mode 100644
index 0000000..59d3cf3
--- /dev/null
+++ b/src/libopensc/ccid-types.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2009-2015 Frank Morgner
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/**
+ * @file
+ */
+#ifndef _CCID_TYPES_H
+#define _CCID_TYPES_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#define PACKED
+#pragma pack(push,1)
+#elif defined(__GNUC__)
+#define PACKED __attribute__ ((__packed__))
+#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;
+} PACKED;
+
+typedef struct {
+ uint8_t bmFindexDindex;
+ uint8_t bmTCCKST0;
+ uint8_t bGuardTimeT0;
+ uint8_t bWaitingIntegerT0;
+ uint8_t bClockStop;
+} 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;
+} 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;
+} 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;
+} PACKED abPINDataStucture_Modification_t;
+
+typedef struct {
+ uint8_t bMessageType;
+ uint32_t dwLength;
+ uint8_t bSlot;
+ uint8_t bSeq;
+ uint8_t bBWI;
+ uint16_t wLevelParameter;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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;
+} 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 */
+} PACKED RDR_to_PC_NotifySlotChange_t;
+
+#ifdef _MSC_VER
+#undef PACKED
+#pragma pack(pop)
+#elif defined(__GNUC__)
+#undef PACKED
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports
index a7027b1..18f8037 100644
--- a/src/libopensc/libopensc.exports
+++ b/src/libopensc/libopensc.exports
@@ -353,3 +353,9 @@ perform_chip_authentication
npa_default_flags
npa_reset_retry_counter
npa_pace_get_tries_left
+escape_pace_input_to_buf
+escape_buf_to_pace_input
+escape_pace_output_to_buf
+escape_buf_to_pace_output
+escape_pace_capabilities_to_buf
+escape_buf_to_pace_capabilities
diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h
index fcd2843..01cbbc3 100644
--- a/src/libopensc/opensc.h
+++ b/src/libopensc/opensc.h
@@ -287,6 +287,7 @@ struct sc_reader_driver {
#define SC_READER_CARD_EXCLUSIVE 0x00000008
#define SC_READER_HAS_WAITING_AREA 0x00000010
#define SC_READER_REMOVED 0x00000020
+#define SC_READER_ENABLE_ESCAPE 0x00000040
/* reader capabilities */
#define SC_READER_CAP_DISPLAY 0x00000001
diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c
index 32f9104..0fc01db 100644
--- a/src/libopensc/reader-ctapi.c
+++ b/src/libopensc/reader-ctapi.c
@@ -397,6 +397,8 @@ static int ctapi_load_module(sc_context_t *ctx,
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
+ if (scconf_get_bool(conf_block, "enable_escape", 0))
+ reader->flags |= SC_READER_ENABLE_ESCAPE;
}
r = _sc_add_reader(ctx, reader);
diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c
index d66d391..9e3bef6 100644
--- a/src/libopensc/reader-openct.c
+++ b/src/libopensc/reader-openct.c
@@ -138,6 +138,8 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info)
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
+ if (scconf_get_bool(conf_block, "enable_escape", 0))
+ reader->flags |= SC_READER_ENABLE_ESCAPE;
}
if ((rc = _sc_add_reader(ctx, reader)) < 0) {
diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c
index 93bfbbe..bc33cfc 100644
--- a/src/libopensc/reader-pcsc.c
+++ b/src/libopensc/reader-pcsc.c
@@ -472,29 +472,31 @@ static int pcsc_reconnect(sc_reader_t * reader, DWORD action)
static void initialize_uid(sc_reader_t *reader)
{
- sc_apdu_t apdu;
- /* though we only expect 10 bytes max, we want to set the Le to 0x00 to not
- * get 0x6282 as SW in case of a UID variant shorter than 10 bytes */
- u8 rbuf[256];
-
- memset(&apdu, 0, sizeof(apdu));
- apdu.cse = SC_APDU_CASE_2_SHORT;
- apdu.cla = 0xFF;
- apdu.ins = 0xCA;
- apdu.p1 = 0x00;
- apdu.p2 = 0x00;
- apdu.le = 0x00;
- apdu.resp = rbuf;
- apdu.resplen = sizeof rbuf;
-
- if (SC_SUCCESS == pcsc_transmit(reader, &apdu)
- && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
- reader->uid.len = apdu.resplen;
- memcpy(reader->uid.value, apdu.resp, reader->uid.len);
- sc_debug_hex(reader->ctx, SC_LOG_DEBUG_NORMAL, "UID",
- reader->uid.value, reader->uid.len);
- } else {
- sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "unable to get UID");
+ if (reader->flags & SC_READER_ENABLE_ESCAPE) {
+ sc_apdu_t apdu;
+ /* though we only expect 10 bytes max, we want to set the Le to 0x00 to not
+ * get 0x6282 as SW in case of a UID variant shorter than 10 bytes */
+ u8 rbuf[256];
+
+ memset(&apdu, 0, sizeof(apdu));
+ apdu.cse = SC_APDU_CASE_2_SHORT;
+ apdu.cla = 0xFF;
+ apdu.ins = 0xCA;
+ apdu.p1 = 0x00;
+ apdu.p2 = 0x00;
+ apdu.le = 0x00;
+ apdu.resp = rbuf;
+ apdu.resplen = sizeof rbuf;
+
+ if (SC_SUCCESS == pcsc_transmit(reader, &apdu)
+ && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+ reader->uid.len = apdu.resplen;
+ memcpy(reader->uid.value, apdu.resp, reader->uid.len);
+ sc_debug_hex(reader->ctx, SC_LOG_DEBUG_NORMAL, "UID",
+ reader->uid.value, reader->uid.len);
+ } else {
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "unable to get UID");
+ }
}
}
@@ -1306,6 +1308,8 @@ static int pcsc_detect_readers(sc_context_t *ctx)
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
+ if (scconf_get_bool(conf_block, "enable_escape", 0))
+ reader->flags |= SC_READER_ENABLE_ESCAPE;
}
sc_log(ctx, "reader's max-send-size: %i, max-recv-size: %i", reader->max_send_size, reader->max_recv_size);
@@ -2393,6 +2397,8 @@ int cardmod_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcs
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
+ if (scconf_get_bool(conf_block, "enable_escape", 0))
+ reader->flags |= SC_READER_ENABLE_ESCAPE;
}
/* attempt to detect protocol in use T0/T1/RAW */
diff --git a/src/libopensc/reader-tr03119.c b/src/libopensc/reader-tr03119.c
new file mode 100644
index 0000000..2aada6e
--- /dev/null
+++ b/src/libopensc/reader-tr03119.c
@@ -0,0 +1,1012 @@
+/*
+ * reader-escape.c: implementation related to escape commands with pseudo APDUs
+ *
+ * Copyright (C) 2013-2015 Frank Morgner
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "reader-tr03119.h"
+#include "ccid-types.h"
+#include "internal.h"
+#include "libopensc/asn1.h"
+#include "libopensc/log.h"
+#include "libopensc/opensc.h"
+#include "libopensc/pace.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if _WIN32
+/* FIXME might not always work */
+#define htole16(x) (x)
+#define htole32(x) (x)
+#elif __APPLE__
+#include <libkern/OSByteOrder.h>
+#define htole16(x) OSSwapHostToLittleInt16(x)
+#define htole32(x) OSSwapHostToLittleInt32(x)
+#else
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE /* See feature_test_macros(7) */
+#endif
+#include <endian.h>
+#endif
+
+static const u8 escape_cla = 0xff;
+static const u8 escape_ins = 0x9a;
+
+static const u8 escape_p1_PIN = 0x04;
+static const u8 escape_p2_GetReaderPACECapabilities = 0x01;
+static const u8 escape_p2_EstablishPACEChannel = 0x02;
+/*static const u8 escape_p2_DestroyPACEChannel = 0x03;*/
+static const u8 escape_p2_PC_to_RDR_Secure = 0x10;
+
+static const u8 escape_p1_IFD = 0x01;
+static const u8 escape_p2_vendor = 0x01;
+/*static const u8 escape_p2_product = 0x03;*/
+static const u8 escape_p2_version_firmware = 0x06;
+/*static const u8 escape_p2_version_driver = 0x07;*/
+
+struct sc_asn1_entry g_boolean[] = {
+ { "boolean",
+ SC_ASN1_BOOLEAN, SC_ASN1_TAG_BOOLEAN, 0, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+struct sc_asn1_entry g_int_as_octet_string[] = {
+ { "int as octet string",
+ SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+struct sc_asn1_entry g_octet_string[] = {
+ { "octet string",
+ SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+struct sc_asn1_entry g_numeric_string_as_octet_string[] = {
+ { "utf8string",
+ SC_ASN1_OCTET_STRING, SC_ASN1_TAG_NUMERICSTRING, SC_ASN1_ALLOC, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+
+static const struct sc_asn1_entry g_EstablishPACEChannelInput_data[] = {
+ { "passwordID",
+ /* use an OCTET STRING to avoid a conversion to int */
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, 0, NULL, NULL },
+ { "transmittedPassword",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x02|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { "cHAT",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x03|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { "certificateDescription",
+ SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x04|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { "hashOID",
+ /* use an OCTET STRING to avoid a conversion to struct sc_object_id */
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x05|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+static const struct sc_asn1_entry g_EstablishPACEChannelOutput_data[] = {
+ { "errorCode",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, 0, NULL, NULL },
+ { "statusMSESetAT",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x02|SC_ASN1_CONS, 0, NULL, NULL },
+ { "efCardAccess",
+ SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x03|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
+ { "idPICC",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x04|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { "curCAR",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x05|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { "prevCAR",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x06|SC_ASN1_CONS, SC_ASN1_OPTIONAL|SC_ASN1_ALLOC, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+static const struct sc_asn1_entry g_EstablishPACEChannel[] = {
+ { "EstablishPACEChannel",
+ SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE|SC_ASN1_CONS, 0, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+
+int escape_pace_input_to_buf(sc_context_t *ctx,
+ const struct establish_pace_channel_input *input,
+ unsigned char **asn1, size_t *asn1_len)
+{
+ size_t pin_id_len = sizeof input->pin_id;
+ struct sc_asn1_entry EstablishPACEChannelInput_data[
+ sizeof g_EstablishPACEChannelInput_data/
+ sizeof *g_EstablishPACEChannelInput_data];
+ struct sc_asn1_entry EstablishPACEChannel[
+ sizeof g_EstablishPACEChannel/
+ sizeof *g_EstablishPACEChannel];
+ struct sc_asn1_entry passwordID[
+ sizeof g_int_as_octet_string/
+ sizeof *g_int_as_octet_string];
+ struct sc_asn1_entry transmittedPassword[
+ sizeof g_numeric_string_as_octet_string/
+ sizeof *g_numeric_string_as_octet_string];
+ struct sc_asn1_entry cHAT[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+
+ sc_copy_asn1_entry(g_EstablishPACEChannel,
+ EstablishPACEChannel);
+ sc_format_asn1_entry(EstablishPACEChannel,
+ EstablishPACEChannelInput_data, 0, 1);
+
+ sc_copy_asn1_entry(g_EstablishPACEChannelInput_data,
+ EstablishPACEChannelInput_data);
+
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+0,
+ passwordID, 0, 1);
+ sc_copy_asn1_entry(g_int_as_octet_string,
+ passwordID);
+ sc_format_asn1_entry(passwordID,
+ (unsigned char *) &input->pin_id, &pin_id_len, 1);
+
+ if (input->pin) {
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+1,
+ transmittedPassword,
+ 0, 1);
+ sc_copy_asn1_entry(g_numeric_string_as_octet_string,
+ transmittedPassword);
+ sc_format_asn1_entry(transmittedPassword,
+ (unsigned char *) input->pin,
+ (size_t *) &input->pin_length, 1);
+ }
+
+ if (input->chat) {
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+2,
+ cHAT,
+ 0, 1);
+ sc_copy_asn1_entry(g_octet_string,
+ cHAT);
+ sc_format_asn1_entry(cHAT,
+ (unsigned char *) input->chat,
+ (size_t *) &input->chat_length, 1);
+ }
+
+ if (input->certificate_description) {
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+3,
+ (unsigned char *) input->certificate_description,
+ (size_t *) &input->certificate_description_length, 1);
+ }
+
+ return sc_asn1_encode(ctx, EstablishPACEChannel, asn1, asn1_len);
+}
+
+int escape_buf_to_pace_input(sc_context_t *ctx,
+ const unsigned char *asn1, size_t asn1_len,
+ struct establish_pace_channel_input *input)
+{
+ size_t pin_id_len = sizeof input->pin_id;
+ struct sc_asn1_entry EstablishPACEChannelInput_data[
+ sizeof g_EstablishPACEChannelInput_data/
+ sizeof *g_EstablishPACEChannelInput_data];
+ struct sc_asn1_entry EstablishPACEChannel[
+ sizeof g_EstablishPACEChannel/
+ sizeof *g_EstablishPACEChannel];
+ struct sc_asn1_entry passwordID[
+ sizeof g_int_as_octet_string/
+ sizeof *g_int_as_octet_string];
+ struct sc_asn1_entry transmittedPassword[
+ sizeof g_numeric_string_as_octet_string/
+ sizeof *g_numeric_string_as_octet_string];
+ struct sc_asn1_entry cHAT[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ /* FIXME handle hashOID */
+
+ sc_copy_asn1_entry(g_EstablishPACEChannel,
+ EstablishPACEChannel);
+ sc_format_asn1_entry(EstablishPACEChannel,
+ EstablishPACEChannelInput_data, 0, 0);
+
+ sc_copy_asn1_entry(g_EstablishPACEChannelInput_data,
+ EstablishPACEChannelInput_data);
+
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+0,
+ passwordID, 0, 0);
+ sc_copy_asn1_entry(g_int_as_octet_string,
+ passwordID);
+ sc_format_asn1_entry(passwordID,
+ &input->pin_id, &pin_id_len, 0);
+
+ if (input->pin) {
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+1,
+ transmittedPassword, 0, 0);
+ sc_copy_asn1_entry(g_numeric_string_as_octet_string,
+ transmittedPassword);
+ sc_format_asn1_entry(transmittedPassword,
+ (unsigned char *) &input->pin, &input->pin_length, 0);
+ }
+
+ if (input->chat) {
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+2,
+ cHAT, 0, 0);
+ sc_copy_asn1_entry(g_octet_string,
+ cHAT);
+ sc_format_asn1_entry(cHAT,
+ (unsigned char *) &input->chat, &input->chat_length, 0);
+ }
+
+ if (input->certificate_description) {
+ sc_format_asn1_entry(EstablishPACEChannelInput_data+3,
+ (unsigned char *) &input->certificate_description,
+ &input->certificate_description_length, 0);
+ }
+
+ LOG_TEST_RET(ctx,
+ sc_asn1_decode(ctx, EstablishPACEChannel, asn1, asn1_len, NULL, NULL),
+ "Error decoding EstablishPACEChannel");
+
+ if (pin_id_len != sizeof input->pin_id)
+ return SC_ERROR_UNKNOWN_DATA_RECEIVED;
+
+ return SC_SUCCESS;
+}
+
+int escape_pace_output_to_buf(sc_context_t *ctx,
+ const struct establish_pace_channel_output *output,
+ unsigned char **asn1, size_t *asn1_len)
+{
+ uint16_t status_mse_set_at = ((output->mse_set_at_sw1 & 0xff) << 8) | output->mse_set_at_sw2;
+ size_t result_len = sizeof output->result,
+ status_mse_set_at_len = sizeof status_mse_set_at;
+ struct sc_asn1_entry EstablishPACEChannelOutput_data[
+ sizeof g_EstablishPACEChannelOutput_data/
+ sizeof *g_EstablishPACEChannelOutput_data];
+ struct sc_asn1_entry EstablishPACEChannel[
+ sizeof g_EstablishPACEChannel/
+ sizeof *g_EstablishPACEChannel];
+ struct sc_asn1_entry errorCode[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry statusMSESetAT[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry idPICC[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry curCAR[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry prevCAR[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+
+ sc_copy_asn1_entry(g_EstablishPACEChannel,
+ EstablishPACEChannel);
+ sc_format_asn1_entry(EstablishPACEChannel,
+ EstablishPACEChannelOutput_data, 0, 1);
+
+ sc_copy_asn1_entry(g_EstablishPACEChannelOutput_data,
+ EstablishPACEChannelOutput_data);
+
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+0,
+ errorCode, 0, 1);
+ sc_copy_asn1_entry(g_octet_string,
+ errorCode);
+ sc_format_asn1_entry(errorCode,
+ (unsigned char *) &output->result, &result_len, 1);
+
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+1,
+ statusMSESetAT, 0, 1);
+ sc_copy_asn1_entry(g_octet_string,
+ statusMSESetAT);
+ sc_format_asn1_entry(statusMSESetAT,
+ &status_mse_set_at, &status_mse_set_at_len, 1);
+
+ if (output->ef_cardaccess) {
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+2,
+ output->ef_cardaccess, (size_t *) &output->ef_cardaccess_length, 1);
+ }
+
+ if (output->id_icc) {
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+3,
+ idPICC, 0, 1);
+ sc_copy_asn1_entry(g_octet_string,
+ idPICC);
+ sc_format_asn1_entry(idPICC,
+ output->id_icc, (size_t *) &output->id_icc_length, 1);
+ }
+
+ if (output->recent_car) {
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+4,
+ curCAR, 0, 1);
+ sc_copy_asn1_entry(g_octet_string,
+ curCAR);
+ sc_format_asn1_entry(curCAR,
+ output->recent_car, (size_t *) &output->recent_car_length, 1);
+ }
+
+ if (output->previous_car) {
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+5,
+ prevCAR, 0, 1);
+ sc_copy_asn1_entry(g_octet_string,
+ prevCAR);
+ sc_format_asn1_entry(prevCAR,
+ output->previous_car, (size_t *) &output->previous_car_length, 1);
+ }
+
+ return sc_asn1_encode(ctx, EstablishPACEChannel, asn1, asn1_len);
+}
+
+int escape_buf_to_pace_output(sc_context_t *ctx,
+ const unsigned char *asn1, size_t asn1_len,
+ struct establish_pace_channel_output *output)
+{
+ uint16_t status_mse_set_at;
+ size_t result_len = sizeof output->result,
+ status_mse_set_at_len = sizeof status_mse_set_at;
+ struct sc_asn1_entry EstablishPACEChannelOutput_data[
+ sizeof g_EstablishPACEChannelOutput_data/
+ sizeof *g_EstablishPACEChannelOutput_data];
+ struct sc_asn1_entry EstablishPACEChannel[
+ sizeof g_EstablishPACEChannel/
+ sizeof *g_EstablishPACEChannel];
+ struct sc_asn1_entry errorCode[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry statusMSESetAT[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry idPICC[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry curCAR[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+ struct sc_asn1_entry prevCAR[
+ sizeof g_octet_string/
+ sizeof *g_octet_string];
+
+ sc_copy_asn1_entry(g_EstablishPACEChannel,
+ EstablishPACEChannel);
+ sc_format_asn1_entry(EstablishPACEChannel,
+ EstablishPACEChannelOutput_data, 0, 0);
+
+ sc_copy_asn1_entry(g_EstablishPACEChannelOutput_data,
+ EstablishPACEChannelOutput_data);
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+0,
+ errorCode, 0, 0);
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+1,
+ statusMSESetAT, 0, 0);
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+2,
+ &output->ef_cardaccess, &output->ef_cardaccess_length, 0);
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+3,
+ idPICC, 0, 0);
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+4,
+ curCAR, 0, 0);
+ sc_format_asn1_entry(EstablishPACEChannelOutput_data+5,
+ prevCAR, 0, 0);
+
+ sc_copy_asn1_entry(g_octet_string,
+ errorCode);
+ sc_format_asn1_entry(errorCode,
+ &output->result, &result_len, 0);
+ /* we already allocated memory for the result */
+ errorCode->flags = 0;
+
+ sc_copy_asn1_entry(g_octet_string,
+ statusMSESetAT);
+ sc_format_asn1_entry(statusMSESetAT,
+ &status_mse_set_at, &status_mse_set_at_len, 0);
+ /* we already allocated memory for the result */
+ statusMSESetAT->flags = 0;
+
+ sc_copy_asn1_entry(g_octet_string,
+ idPICC);
+ sc_format_asn1_entry(idPICC,
+ &output->id_icc, &output->id_icc_length, 0);
+
+ sc_copy_asn1_entry(g_octet_string,
+ curCAR);
+ sc_format_asn1_entry(curCAR,
+ &output->recent_car, &output->recent_car_length, 0);
+
+ sc_copy_asn1_entry(g_octet_string,
+ prevCAR);
+ sc_format_asn1_entry(prevCAR,
+ &output->previous_car, &output->previous_car_length, 0);
+
+ LOG_TEST_RET(ctx,
+ sc_asn1_decode(ctx, EstablishPACEChannel,
+ asn1, asn1_len, NULL, NULL),
+ "Error decoding EstablishPACEChannel");
+
+ if (status_mse_set_at_len != sizeof status_mse_set_at
+ || result_len != sizeof output->result)
+ return SC_ERROR_UNKNOWN_DATA_RECEIVED;
+
+ output->mse_set_at_sw1 = (status_mse_set_at >> 8) & 0xff;
+ output->mse_set_at_sw2 = status_mse_set_at & 0xff;
+
+ return SC_SUCCESS;
+}
+
+#define CCID_PIN_TIMEOUT 30
+#define CCID_DISPLAY_DEFAULT 0xff
+static int escape_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)
+{
+ 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 && *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 escape_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 escape_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 = escape_cla;
+ apdu.ins = escape_ins;
+ apdu.p1 = escape_p1_PIN;
+ apdu.p2 = escape_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 = escape_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 = escape_buf_to_verify_result(reader->ctx, apdu.resp, apdu.resplen,
+ data->apdu);
+
+err:
+ free((unsigned char *) apdu.data);
+
+ return r;
+}
+
+static int escape_perform_pace(struct sc_reader *reader,
+ void *establish_pace_channel_input,
+ void *establish_pace_channel_output)
+{
+ u8 rbuf[0xffff];
+ sc_apdu_t apdu;
+ int r;
+ struct establish_pace_channel_input *input =
+ establish_pace_channel_input;
+ struct establish_pace_channel_output *output =
+ establish_pace_channel_output;
+
+ memset(&apdu, 0, sizeof(apdu));
+ apdu.cse = SC_APDU_CASE_4_EXT;
+ apdu.cla = escape_cla;
+ apdu.ins = escape_ins;
+ apdu.p1 = escape_p1_PIN;
+ apdu.p2 = escape_p2_EstablishPACEChannel;
+ 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 = escape_pace_input_to_buf(reader->ctx, input,
+ (unsigned char **) &apdu.data, &apdu.datalen);
+ if (r < 0) {
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "Error encoding EstablishPACEChannel");
+ goto err;
+ }
+ apdu.lc = apdu.datalen;
+
+ r = reader->ops->transmit(reader, &apdu);
+ if (r < 0) {
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "Error performing EstablishPACEChannel");
+ goto err;
+ }
+
+ if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) {
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "Error decoding EstablishPACEChannel");
+ r = SC_ERROR_NOT_SUPPORTED;
+ goto err;
+ }
+
+ r = escape_buf_to_pace_output(reader->ctx, apdu.resp, apdu.resplen,
+ output);
+
+err:
+ free((unsigned char *) apdu.data);
+
+ return r;
+}
+
+struct sc_asn1_entry g_PACECapabilities_data[] = {
+ { "capabilityPACE",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x01|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
+ { "capabilityEID",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x02|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
+ { "capabilityESign",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x03|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
+ { "capabilityDestroy",
+ SC_ASN1_STRUCT, SC_ASN1_CTX|0x04|SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+struct sc_asn1_entry g_PACECapabilities[] = {
+ { "PACECapabilities",
+ SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE|SC_ASN1_CONS, 0, NULL, NULL },
+ { NULL , 0 , 0 , 0 , NULL , NULL }
+};
+
+int escape_buf_to_pace_capabilities(sc_context_t *ctx,
+ const unsigned char *asn1, size_t asn1_len,
+ unsigned long *sc_reader_t_capabilities)
+{
+ int pace = 0, eid = 0, esign = 0, destroy = 0;
+ struct sc_asn1_entry PACECapabilities_data[
+ sizeof g_PACECapabilities_data/
+ sizeof *g_PACECapabilities_data];
+ struct sc_asn1_entry PACECapabilities[
+ sizeof g_PACECapabilities/
+ sizeof *g_PACECapabilities];
+ struct sc_asn1_entry capabilityPACE[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+ struct sc_asn1_entry capabilityEID[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+ struct sc_asn1_entry capabilityESign[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+ struct sc_asn1_entry capabilityDestroy[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+
+ sc_copy_asn1_entry(g_PACECapabilities,
+ PACECapabilities);
+ sc_format_asn1_entry(PACECapabilities,
+ PACECapabilities_data, 0, 1);
+
+ sc_copy_asn1_entry(g_PACECapabilities_data,
+ PACECapabilities_data);
+ sc_format_asn1_entry(PACECapabilities_data+0,
+ &capabilityPACE, NULL, 1);
+ sc_format_asn1_entry(PACECapabilities_data+1,
+ &capabilityEID, NULL, 1);
+ sc_format_asn1_entry(PACECapabilities_data+2,
+ &capabilityESign, NULL, 1);
+ sc_format_asn1_entry(PACECapabilities_data+3,
+ &capabilityDestroy, NULL, 1);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityPACE);
+ sc_format_asn1_entry(capabilityPACE+0,
+ &pace, NULL, 0);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityEID);
+ sc_format_asn1_entry(capabilityEID+0,
+ &eid, NULL, 0);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityESign);
+ sc_format_asn1_entry(capabilityESign+0,
+ &esign, NULL, 0);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityDestroy);
+ sc_format_asn1_entry(capabilityDestroy+0,
+ &destroy, NULL, 0);
+
+ LOG_TEST_RET(ctx,
+ sc_asn1_decode(ctx, PACECapabilities,
+ asn1, asn1_len, NULL, NULL),
+ "Error decoding PACECapabilities");
+
+ /* We got a valid PACE Capabilities reply. There is currently no mechanism
+ * to determine support PIN verification/modification with a escape
+ * command. Since the reader implements this mechanism it is reasonable to
+ * assume that PIN verification/modification is available. */
+ *sc_reader_t_capabilities = SC_READER_CAP_PIN_PAD;
+
+ if (pace)
+ *sc_reader_t_capabilities |= SC_READER_CAP_PACE_GENERIC;
+ if (eid)
+ *sc_reader_t_capabilities |= SC_READER_CAP_PACE_EID;
+ if (esign)
+ *sc_reader_t_capabilities |= SC_READER_CAP_PACE_ESIGN;
+ if (destroy)
+ *sc_reader_t_capabilities |= SC_READER_CAP_PACE_DESTROY_CHANNEL;
+
+ return SC_SUCCESS;
+}
+
+int escape_pace_capabilities_to_buf(sc_context_t *ctx,
+ const unsigned long sc_reader_t_capabilities,
+ unsigned char **asn1, size_t *asn1_len)
+{
+ int yes = 1, no = 0;
+ struct sc_asn1_entry PACECapabilities_data[
+ sizeof g_PACECapabilities_data/
+ sizeof *g_PACECapabilities_data];
+ struct sc_asn1_entry PACECapabilities[
+ sizeof g_PACECapabilities/
+ sizeof *g_PACECapabilities];
+ struct sc_asn1_entry capabilityPACE[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+ struct sc_asn1_entry capabilityEID[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+ struct sc_asn1_entry capabilityESign[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+ struct sc_asn1_entry capabilityDestroy[
+ sizeof g_boolean/
+ sizeof *g_boolean];
+
+ sc_copy_asn1_entry(g_EstablishPACEChannel,
+ PACECapabilities);
+ sc_format_asn1_entry(PACECapabilities,
+ PACECapabilities_data, 0, 1);
+
+ sc_copy_asn1_entry(g_PACECapabilities_data,
+ PACECapabilities_data);
+ sc_format_asn1_entry(PACECapabilities_data+0,
+ &capabilityPACE, NULL, 1);
+ sc_format_asn1_entry(PACECapabilities_data+1,
+ &capabilityEID, NULL, 1);
+ sc_format_asn1_entry(PACECapabilities_data+2,
+ &capabilityESign, NULL, 1);
+ sc_format_asn1_entry(PACECapabilities_data+3,
+ &capabilityDestroy, NULL, 1);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityPACE);
+ sc_format_asn1_entry(capabilityPACE,
+ sc_reader_t_capabilities & SC_READER_CAP_PACE_GENERIC
+ ? &yes : &no, NULL, 1);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityEID);
+ sc_format_asn1_entry(capabilityEID,
+ sc_reader_t_capabilities & SC_READER_CAP_PACE_EID
+ ? &yes : &no, NULL, 1);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityESign);
+ sc_format_asn1_entry(capabilityESign,
+ sc_reader_t_capabilities & SC_READER_CAP_PACE_ESIGN
+ ? &yes : &no, NULL, 1);
+
+ sc_copy_asn1_entry(g_boolean,
+ capabilityDestroy);
+ sc_format_asn1_entry(capabilityDestroy,
+ sc_reader_t_capabilities & SC_READER_CAP_PACE_DESTROY_CHANNEL
+ ? &yes : &no, NULL, 1);
+
+ return sc_asn1_encode(ctx, PACECapabilities, asn1, asn1_len);
+}
+
+void sc_detect_escape_cmds(sc_reader_t *reader)
+{
+ int error = 0;
+ u8 rbuf[0xff+1];
+ sc_apdu_t apdu;
+ unsigned long capabilities;
+
+ if (reader && reader->ops && reader->ops->transmit) {
+ memset(&apdu, 0, sizeof(apdu));
+ apdu.cse = SC_APDU_CASE_2_SHORT;
+ apdu.cla = escape_cla;
+ apdu.ins = escape_ins;
+ apdu.p1 = escape_p1_PIN;
+ apdu.p2 = escape_p2_GetReaderPACECapabilities;
+ apdu.resp = rbuf;
+ apdu.resplen = sizeof rbuf;
+ apdu.le = sizeof rbuf;
+
+ if (reader->ops->transmit(reader, &apdu) == SC_SUCCESS
+ && apdu.sw1 == 0x90 && apdu.sw2 == 0x00
+ && escape_buf_to_pace_capabilities(reader->ctx,
+ apdu.resp, apdu.resplen, &capabilities) == SC_SUCCESS) {
+ if (capabilities & SC_READER_CAP_PIN_PAD
+ && !(reader->capabilities & SC_READER_CAP_PIN_PAD)) {
+ ((struct sc_reader_operations *) reader->ops)->perform_verify =
+ escape_perform_verify;
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "Added escape command wrappers for PIN verification/modification to '%s'", reader->name);
+ }
+
+ if (capabilities & SC_READER_CAP_PACE_GENERIC
+ && !(reader->capabilities & SC_READER_CAP_PACE_GENERIC)) {
+ ((struct sc_reader_operations *) reader->ops)->perform_pace =
+ escape_perform_pace;
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "Added escape command wrappers for PACE to '%s'", reader->name);
+ }
+
+ reader->capabilities |= capabilities;
+ } else {
+ error++;
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "%s does not support escape commands", reader->name);
+ }
+
+ apdu.p1 = escape_p1_IFD;
+ apdu.p2 = escape_p2_vendor;
+ apdu.resplen = sizeof rbuf;
+ if (reader->ops->transmit(reader, &apdu) == SC_SUCCESS
+ && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+ if (!reader->vendor) {
+ /* add NUL termination, just in case... */
+ rbuf[apdu.resplen] = '\0';
+ reader->vendor = strdup((const char *) rbuf);
+ }
+ } else {
+ error++;
+ }
+
+ apdu.p1 = escape_p1_IFD;
+ apdu.p2 = escape_p2_version_firmware;
+ apdu.resplen = sizeof rbuf;
+ if (reader->ops->transmit(reader, &apdu) == SC_SUCCESS
+ && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+ if (!reader->version_major && !reader->version_minor) {
+ unsigned int major = 0, minor = 0;
+ /* add NUL termination, just in case... */
+ rbuf[apdu.resplen] = '\0';
+ sscanf((const char *) rbuf, "%u.%u", &major, &minor);
+ reader->version_major = major>0xff ? 0xff : major;
+ reader->version_minor = minor>0xff ? 0xff : minor;
+ }
+ } else {
+ error++;
+ }
+ }
+
+ if (error) {
+ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
+ "%d escape command%s failed, need to reset the card",
+ error, error == 1 ? "" : "s");
+ if (reader && reader->ops && reader->ops->transmit) {
+ memset(&apdu, 0, sizeof(apdu));
+ apdu.cse = SC_APDU_CASE_3_SHORT;
+ apdu.cla = 0x00;
+ apdu.ins = 0xA4;
+ apdu.p1 = 8;
+ apdu.p2 = 0x0C;
+ apdu.data = rbuf;
+ rbuf[0] = 0x3F;
+ rbuf[1] = 0x00;
+ apdu.datalen = 2;
+ apdu.lc = 2;
+ apdu.resp = NULL;
+ apdu.resplen = 0;
+ apdu.le = 0;
+ reader->ops->transmit(reader, &apdu);
+ }
+ }
+}
diff --git a/src/libopensc/reader-tr03119.h b/src/libopensc/reader-tr03119.h
new file mode 100644
index 0000000..089074f
--- /dev/null
+++ b/src/libopensc/reader-tr03119.h
@@ -0,0 +1,57 @@
+/*
+ * reader-tr03119.h: interface related to escape commands with pseudo APDUs
+ *
+ * Copyright (C) 2013-2015 Frank Morgner
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _READER_TR03119_H
+#define _READER_TR03119_H
+
+#include "libopensc/opensc.h"
+#include "libopensc/pace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sc_detect_escape_cmds(sc_reader_t *reader);
+
+int escape_pace_input_to_buf(sc_context_t *ctx,
+ const struct establish_pace_channel_input *input,
+ unsigned char **asn1, size_t *asn1_len);
+int escape_buf_to_pace_input(sc_context_t *ctx,
+ const unsigned char *asn1, size_t asn1_len,
+ struct establish_pace_channel_input *input);
+int escape_pace_output_to_buf(sc_context_t *ctx,
+ const struct establish_pace_channel_output *output,
+ unsigned char **asn1, size_t *asn1_len);
+int escape_buf_to_pace_output(sc_context_t *ctx,
+ const unsigned char *asn1, size_t asn1_len,
+ struct establish_pace_channel_output *output);
+int escape_pace_capabilities_to_buf(sc_context_t *ctx,
+ const unsigned long sc_reader_t_capabilities,
+ unsigned char **asn1, size_t *asn1_len);
+int escape_buf_to_pace_capabilities(sc_context_t *ctx,
+ const unsigned char *asn1, size_t asn1_len,
+ unsigned long *sc_reader_t_capabilities);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c
index ba5e4f4..24891ef 100644
--- a/src/pkcs11/slot.c
+++ b/src/pkcs11/slot.c
@@ -50,13 +50,20 @@ static struct sc_pkcs11_slot * reader_get_slot(sc_reader_t *reader)
return NULL;
}
-static void init_slot_info(CK_SLOT_INFO_PTR pInfo)
+static void init_slot_info(CK_SLOT_INFO_PTR pInfo, sc_reader_t *reader)
{
- strcpy_bp(pInfo->slotDescription, "Virtual hotplug slot", 64);
- strcpy_bp(pInfo->manufacturerID, OPENSC_VS_FF_COMPANY_NAME, 32);
+ if (reader) {
+ strcpy_bp(pInfo->slotDescription, reader->name, 64);
+ strcpy_bp(pInfo->manufacturerID, reader->vendor, 32);
+ pInfo->hardwareVersion.major = reader->version_major;
+ pInfo->hardwareVersion.minor = reader->version_minor;
+ } else {
+ strcpy_bp(pInfo->slotDescription, "Virtual hotplug slot", 64);
+ strcpy_bp(pInfo->manufacturerID, OPENSC_VS_FF_COMPANY_NAME, 32);
+ pInfo->hardwareVersion.major = OPENSC_VERSION_MAJOR;
+ pInfo->hardwareVersion.minor = OPENSC_VERSION_MINOR;
+ }
pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT;
- pInfo->hardwareVersion.major = OPENSC_VERSION_MAJOR;
- pInfo->hardwareVersion.minor = OPENSC_VERSION_MINOR;
pInfo->firmwareVersion.major = 0;
pInfo->firmwareVersion.minor = 0;
}
@@ -105,7 +112,7 @@ CK_RV create_slot(sc_reader_t *reader)
slot->login_user = -1;
slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot);
- init_slot_info(&slot->slot_info);
+ init_slot_info(&slot->slot_info, reader);
sc_log(context, "Initializing slot with id 0x%lx", slot->id);
if (reader != NULL) {
@@ -127,7 +134,7 @@ void empty_slot(struct sc_pkcs11_slot *slot)
* already been reset by `slot_token_removed()`, lists have been
* emptied. We replace the reader with a virtual hotplug slot. */
slot->reader = NULL;
- init_slot_info(&slot->slot_info);
+ init_slot_info(&slot->slot_info, NULL);
} else {
list_destroy(&slot->objects);
list_destroy(&slot->logins);
@@ -273,6 +280,18 @@ again:
return sc_to_cryptoki_error(rc, NULL);
}
+ /* escape commands are only guaranteed to be working with a card
+ * inserted. That's why by now, after sc_connect_card() the reader's
+ * metadata may have changed. We re-initialize the metadata for every
+ * slot of this reader here. */
+ if (reader->flags & SC_READER_ENABLE_ESCAPE) {
+ for (i = 0; i<list_size(&virtual_slots); i++) {
+ sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
+ if (slot->reader == reader)
+ init_slot_info(&slot->slot_info, reader);
+ }
+ }
+
sc_log(context, "%s: Connected SC card %p", reader->name, p11card->card);
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git
More information about the pkg-opensc-commit
mailing list