libccid project is hosted at http://pcsclite.alioth.debian.org/ccid.html
This code is shared with the libccid project. In order to easily port
changes between libccid and UEFI projects I decided to keep the coding
style as it was and not strictly comply to the UEFI coding style.
Contributed-under: GNU LGPL v2.1+
Signed-off-by: Ludovic Rousseau <***@gmail.com>
---
.../Library/SmartCardReader/libccid/ccid.c | 659 ++++++
.../Library/SmartCardReader/libccid/ccid.h | 340 +++
.../SmartCardReader/libccid/ccid_ifdhandler.h | 63 +
.../Library/SmartCardReader/libccid/ccid_uefi.c | 470 ++++
.../Library/SmartCardReader/libccid/ccid_uefi.h | 46 +
.../Library/SmartCardReader/libccid/commands.c | 2294 ++++++++++++++++++++
.../Library/SmartCardReader/libccid/commands.h | 64 +
.../Library/SmartCardReader/libccid/debug.c | 157 ++
.../Library/SmartCardReader/libccid/debug.h | 100 +
.../Library/SmartCardReader/libccid/defs.h | 126 ++
.../Library/SmartCardReader/libccid/ifdhandler.c | 2265 +++++++++++++++++++
.../Library/SmartCardReader/libccid/openct/LICENSE | 28 +
.../Library/SmartCardReader/libccid/openct/README | 7 +
.../SmartCardReader/libccid/openct/buffer.c | 73 +
.../SmartCardReader/libccid/openct/buffer.h | 36 +
.../SmartCardReader/libccid/openct/checksum.c | 95 +
.../SmartCardReader/libccid/openct/checksum.h | 37 +
.../SmartCardReader/libccid/openct/proto-t1.c | 800 +++++++
.../SmartCardReader/libccid/openct/proto-t1.h | 85 +
.../SmartCardReader/libccid/towitoko/COPYING | 505 +++++
.../SmartCardReader/libccid/towitoko/README | 14 +
.../Library/SmartCardReader/libccid/towitoko/atr.c | 365 ++++
.../Library/SmartCardReader/libccid/towitoko/atr.h | 111 +
.../SmartCardReader/libccid/towitoko/defines.h | 56 +
.../Library/SmartCardReader/libccid/towitoko/pps.c | 136 ++
.../Library/SmartCardReader/libccid/towitoko/pps.h | 71 +
.../Library/SmartCardReader/libccid/utils.c | 85 +
.../Library/SmartCardReader/libccid/utils.h | 33 +
28 files changed, 9121 insertions(+)
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/defs.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.h
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid.c b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
new file mode 100644
index 0000000..eff9050
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
@@ -0,0 +1,659 @@
+/*
+ ccid.c: CCID common code
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid.c 6976 2014-09-04 11:35:46Z rousseau $
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <pcsclite.h>
+#include <ifdhandler.h>
+
+#include "debug.h"
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "commands.h"
+#include "utils.h"
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+/*****************************************************************************
+ *
+ * ccid_open_hack_pre
+ *
+ ****************************************************************************/
+int ccid_open_hack_pre(unsigned int reader_index)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ switch (ccid_descriptor->readerID)
+ {
+ case MYSMARTPAD:
+ ccid_descriptor->dwMaxIFSD = 254;
+ break;
+
+ case CL1356D:
+ /* the firmware needs some time to initialize */
+ (void)sleep(1);
+ ccid_descriptor->readTimeout = 60*1000; /* 60 seconds */
+ break;
+
+ case GEMPCTWIN:
+ case GEMPCKEY:
+ case DELLSCRK:
+ /* Only the chipset with firmware version 2.00 is "bogus"
+ * The reader may send packets of 0 bytes when the reader is
+ * connected to a USB 3 port */
+ if (0x0200 == ccid_descriptor->IFD_bcdDevice)
+ {
+ ccid_descriptor->zlp = TRUE;
+ DEBUG_INFO1("ZLP fixup");
+ }
+ break;
+
+ case OZ776_7772:
+ ccid_descriptor->dwMaxDataRate = 9600;
+ break;
+ }
+
+ /* CCID */
+ if ((PROTOCOL_CCID == ccid_descriptor->bInterfaceProtocol)
+ && (3 == ccid_descriptor -> bNumEndpoints))
+ {
+#ifndef TWIN_SERIAL
+ /* just wait for 100ms in case a notification is in the pipe */
+ (void)InterruptRead(reader_index, 100);
+#endif
+ }
+
+ /* ICCD type A */
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char tmp[MAX_ATR_SIZE];
+ unsigned int n = sizeof(tmp);
+
+ DEBUG_COMM("ICCD type A");
+ (void)CmdPowerOff(reader_index);
+ (void)CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE);
+ (void)CmdPowerOff(reader_index);
+ }
+
+ /* ICCD type B */
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char tmp[MAX_ATR_SIZE];
+ unsigned int n = sizeof(tmp);
+
+ DEBUG_COMM("ICCD type B");
+ if (CCID_CLASS_SHORT_APDU ==
+ (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK))
+ {
+ /* use the extended APDU comm alogorithm */
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_EXTENDED_APDU;
+ }
+
+ (void)CmdPowerOff(reader_index);
+ (void)CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE);
+ (void)CmdPowerOff(reader_index);
+ }
+
+ return 0;
+} /* ccid_open_hack_pre */
+
+#ifndef NO_LOG
+/*****************************************************************************
+ *
+ * dump_gemalto_firmware_features
+ *
+ ****************************************************************************/
+static void dump_gemalto_firmware_features(struct GEMALTO_FIRMWARE_FEATURES *gff)
+{
+ DEBUG_INFO2("Dumping Gemalto firmware features (%zd bytes):",
+ sizeof(struct GEMALTO_FIRMWARE_FEATURES));
+
+#ifdef UEFI_DRIVER
+#define YESNO(x) (x) ? L"yes" : L"no"
+#else
+#define YESNO(x) (x) ? "yes" : "no"
+#endif
+
+ DEBUG_INFO2(" bLogicalLCDLineNumber: %d", gff->bLogicalLCDLineNumber);
+ DEBUG_INFO2(" bLogicalLCDRowNumber: %d", gff->bLogicalLCDRowNumber);
+ DEBUG_INFO2(" bLcdInfo: 0x%02X", gff->bLcdInfo);
+ DEBUG_INFO2(" bEntryValidationCondition: 0x%02X",
+ gff->bEntryValidationCondition);
+
+ DEBUG_INFO1(" Reader supports PC/SCv2 features:");
+ DEBUG_INFO2(" VerifyPinStart: %s", YESNO(gff->VerifyPinStart));
+ DEBUG_INFO2(" VerifyPinFinish: %s", YESNO(gff->VerifyPinFinish));
+ DEBUG_INFO2(" ModifyPinStart: %s", YESNO(gff->ModifyPinStart));
+ DEBUG_INFO2(" ModifyPinFinish: %s", YESNO(gff->ModifyPinFinish));
+ DEBUG_INFO2(" GetKeyPressed: %s", YESNO(gff->GetKeyPressed));
+ DEBUG_INFO2(" VerifyPinDirect: %s", YESNO(gff->VerifyPinDirect));
+ DEBUG_INFO2(" ModifyPinDirect: %s", YESNO(gff->ModifyPinDirect));
+ DEBUG_INFO2(" Abort: %s", YESNO(gff->Abort));
+ DEBUG_INFO2(" GetKey: %s", YESNO(gff->GetKey));
+ DEBUG_INFO2(" WriteDisplay: %s", YESNO(gff->WriteDisplay));
+ DEBUG_INFO2(" SetSpeMessage: %s", YESNO(gff->SetSpeMessage));
+ DEBUG_INFO2(" bTimeOut2: %s", YESNO(gff->bTimeOut2));
+ DEBUG_INFO2(" bPPDUSupportOverXferBlock: %s",
+ YESNO(gff->bPPDUSupportOverXferBlock));
+ DEBUG_INFO2(" bPPDUSupportOverEscape: %s",
+ YESNO(gff->bPPDUSupportOverEscape));
+
+ DEBUG_INFO2(" bListSupportedLanguages: %s",
+ YESNO(gff->bListSupportedLanguages));
+ DEBUG_INFO2(" bNumberMessageFix: %s", YESNO(gff->bNumberMessageFix));
+
+ DEBUG_INFO2(" VersionNumber: 0x%02X", gff->VersionNumber);
+ DEBUG_INFO2(" MinimumPINSize: %d", gff->MinimumPINSize);
+ DEBUG_INFO2(" MaximumPINSize: %d", gff->MaximumPINSize);
+ DEBUG_INFO2(" Firewall: %s", YESNO(gff->Firewall));
+ if (gff->Firewall && gff->FirewalledCommand_SW1
+ && gff->FirewalledCommand_SW2)
+ {
+ DEBUG_INFO2(" FirewalledCommand_SW1: 0x%02X",
+ gff->FirewalledCommand_SW1);
+ DEBUG_INFO2(" FirewalledCommand_SW2: 0x%02X",
+ gff->FirewalledCommand_SW2);
+ }
+
+} /* dump_gemalto_firmware_features */
+#endif
+
+/*****************************************************************************
+ *
+ * set_gemalto_firmware_features
+ *
+ ****************************************************************************/
+static void set_gemalto_firmware_features(unsigned int reader_index)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ struct GEMALTO_FIRMWARE_FEATURES *gf_features;
+
+ gf_features = malloc(sizeof(struct GEMALTO_FIRMWARE_FEATURES));
+ if (gf_features)
+ {
+ unsigned char cmd[] = { 0x6A }; /* GET_FIRMWARE_FEATURES command id */
+ unsigned int len_features = sizeof *gf_features;
+ RESPONSECODE ret;
+
+ ret = CmdEscape(reader_index, cmd, sizeof cmd,
+ (unsigned char*)gf_features, &len_features, 0);
+ if ((IFD_SUCCESS == ret) &&
+ (len_features == sizeof *gf_features))
+ {
+ /* Command is supported if it succeeds at CCID level */
+ /* and returned size matches our expectation */
+ ccid_descriptor->gemalto_firmware_features = gf_features;
+#ifndef NO_LOG
+ dump_gemalto_firmware_features(gf_features);
+#endif
+ }
+ else
+ {
+ /* Command is not supported, let's free allocated memory */
+ free(gf_features);
+ DEBUG_INFO3("GET_FIRMWARE_FEATURES failed: " DWORD_D ", len=%d",
+ ret, len_features);
+ }
+ }
+} /* set_gemalto_firmware_features */
+
+/*****************************************************************************
+ *
+ * ccid_open_hack_post
+ *
+ ****************************************************************************/
+int ccid_open_hack_post(unsigned int reader_index)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ RESPONSECODE return_value = IFD_SUCCESS;
+
+ switch (ccid_descriptor->readerID)
+ {
+ case GEMPCKEY:
+ case GEMPCTWIN:
+ /* Reader announces TPDU but can do APDU (EMV in fact) */
+ if (DriverOptions & DRIVER_OPTION_GEMPC_TWIN_KEY_APDU)
+ {
+ unsigned char cmd[] = { 0x1F, 0x02 };
+ unsigned char res[10];
+ unsigned int length_res = sizeof(res);
+
+ if (CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0) == IFD_SUCCESS)
+ {
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU;
+ }
+ }
+ break;
+
+ case VEGAALPHA:
+ case GEMPCPINPAD:
+ /* load the l10n strings in the pinpad memory */
+ {
+#define L10N_HEADER_SIZE 5
+#define L10N_STRING_MAX_SIZE 16
+#define L10N_NB_STRING 10
+
+ unsigned char cmd[L10N_HEADER_SIZE + L10N_NB_STRING * L10N_STRING_MAX_SIZE];
+ unsigned char res[20];
+ unsigned int length_res = sizeof(res);
+ int offset, i, j;
+
+ const char *fr[] = {
+ "Entrer PIN",
+ "Nouveau PIN",
+ "Confirmer PIN",
+ "PIN correct",
+ "PIN Incorrect !",
+ "Delai depasse",
+ "* essai restant",
+ "Inserer carte",
+ "Erreur carte",
+ "PIN bloque" };
+
+ const char *de[] = {
+ "PIN eingeben",
+ "Neue PIN",
+ "PIN bestatigen",
+ "PIN korrect",
+ "Falsche PIN !",
+ "Zeit abgelaufen",
+ "* Versuche ubrig",
+ "Karte einstecken",
+ "Fehler Karte",
+ "PIN blockiert" };
+
+ const char *es[] = {
+ "Introducir PIN",
+ "Nuevo PIN",
+ "Confirmar PIN",
+ "PIN OK",
+ "PIN Incorrecto !",
+ "Tiempo Agotado",
+ "* ensayos quedan",
+ "Introducir Tarj.",
+ "Error en Tarjeta",
+ "PIN bloqueado" };
+
+ const char *it[] = {
+ "Inserire PIN",
+ "Nuovo PIN",
+ "Confermare PIN",
+ "PIN Corretto",
+ "PIN Errato !",
+ "Tempo scaduto",
+ "* prove rimaste",
+ "Inserire Carta",
+ "Errore Carta",
+ "PIN ostruito"};
+
+ const char *pt[] = {
+ "Insira PIN",
+ "Novo PIN",
+ "Conf. novo PIN",
+ "PIN OK",
+ "PIN falhou!",
+ "Tempo expirou",
+ "* tentiv. restam",
+ "Introduza cartao",
+ "Erro cartao",
+ "PIN bloqueado" };
+
+ const char *nl[] = {
+ "Inbrengen code",
+ "Nieuwe code",
+ "Bevestig code",
+ "Code aanvaard",
+ "Foute code",
+ "Time out",
+ "* Nog Pogingen",
+ "Kaart inbrengen",
+ "Kaart fout",
+ "Kaart blok" };
+
+ const char *tr[] = {
+ "PIN Giriniz",
+ "Yeni PIN",
+ "PIN Onayala",
+ "PIN OK",
+ "Yanlis PIN",
+ "Zaman Asimi",
+ "* deneme kaldi",
+ "Karti Takiniz",
+ "Kart Hatasi",
+ "Kart Kilitli" };
+
+ const char *en[] = {
+ "Enter PIN",
+ "New PIN",
+ "Confirm PIN",
+ "PIN OK",
+ "Incorrect PIN!",
+ "Time Out",
+ "* retries left",
+ "Insert Card",
+ "Card Error",
+ "PIN blocked" };
+
+ const char *lang;
+ const char **l10n;
+
+#ifdef __APPLE__
+ CFArrayRef cfa;
+ CFStringRef slang;
+
+ /* Get the complete ordered list */
+ cfa = CFLocaleCopyPreferredLanguages();
+
+ /* Use the first/preferred language
+ * As the driver is run as root we get the language
+ * selected during install */
+ slang = CFArrayGetValueAtIndex(cfa, 0);
+
+ /* CFString -> C string */
+ lang = CFStringGetCStringPtr(slang, kCFStringEncodingMacRoman);
+#else
+ /* The other Unixes just use the LANG env variable */
+ lang = getenv("LANG");
+#endif
+ DEBUG_COMM2("Using lang: %s", lang);
+ if (NULL == lang)
+ l10n = en;
+ else
+ {
+ if (0 == strncmp(lang, "fr", 2))
+ l10n = fr;
+ else if (0 == strncmp(lang, "de", 2))
+ l10n = de;
+ else if (0 == strncmp(lang, "es", 2))
+ l10n = es;
+ else if (0 == strncmp(lang, "it", 2))
+ l10n = it;
+ else if (0 == strncmp(lang, "pt", 2))
+ l10n = pt;
+ else if (0 == strncmp(lang, "nl", 2))
+ l10n = nl;
+ else if (0 == strncmp(lang, "tr", 2))
+ l10n = tr;
+ else
+ l10n = en;
+ }
+
+#ifdef __APPLE__
+ /* Release the allocated array */
+ CFRelease(cfa);
+#endif
+ offset = 0;
+ cmd[offset++] = 0xB2; /* load strings */
+ cmd[offset++] = 0xA0; /* address of the memory */
+ cmd[offset++] = 0x00; /* address of the first byte */
+ cmd[offset++] = 0x4D; /* magic value */
+ cmd[offset++] = 0x4C; /* magic value */
+
+ /* for each string */
+ for (i=0; i<L10N_NB_STRING; i++)
+ {
+ /* copy the string */
+ for (j=0; l10n[i][j]; j++)
+ cmd[offset++] = l10n[i][j];
+
+ /* pad with " " */
+ for (; j<L10N_STRING_MAX_SIZE; j++)
+ cmd[offset++] = ' ';
+ }
+
+ (void)sleep(1);
+ if (IFD_SUCCESS == CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, DEFAULT_COM_READ_TIMEOUT))
+ {
+ DEBUG_COMM("l10n string loaded successfully");
+ }
+ else
+ {
+ DEBUG_COMM("Failed to load l10n strings");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ if (DriverOptions & DRIVER_OPTION_DISABLE_PIN_RETRIES)
+ {
+ /* disable VERIFY from reader */
+ const unsigned char cmd2[] = {0xb5, 0x00};
+ length_res = sizeof(res);
+ if (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, DEFAULT_COM_READ_TIMEOUT))
+ {
+ DEBUG_COMM("Disable SPE retry counter successfull");
+ }
+ else
+ {
+ DEBUG_CRITICAL("Failed to disable SPE retry counter");
+ }
+ }
+ }
+ break;
+
+ case HPSMARTCARDKEYBOARD:
+ case HP_CCIDSMARTCARDKEYBOARD:
+ case FUJITSUSMARTKEYB:
+ /* the Secure Pin Entry is bogus so disable it
+ * http://martinpaljak.net/2011/03/19/insecure-hp-usb-smart-card-keyboard/
+ */
+ ccid_descriptor->bPINSupport = 0;
+ break;
+
+#if 0
+ /* SCM SCR331-DI contactless */
+ case SCR331DI:
+ /* SCM SCR331-DI-NTTCOM contactless */
+ case SCR331DINTTCOM:
+ /* SCM SDI010 contactless */
+ case SDI010:
+ /* the contactless reader is in the second slot */
+ if (ccid_descriptor->bCurrentSlotIndex > 0)
+ {
+ unsigned char cmd1[] = { 0x00 };
+ /* command: 00 ??
+ * response: 06 10 03 03 00 00 00 01 FE FF FF FE 01 ?? */
+ unsigned char cmd2[] = { 0x02 };
+ /* command: 02 ??
+ * response: 00 ?? */
+
+ unsigned char res[20];
+ unsigned int length_res = sizeof(res);
+
+ if ((IFD_SUCCESS == CmdEscape(reader_index, cmd1, sizeof(cmd1), res, &length_res, 0))
+ && (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, 0)))
+ {
+ DEBUG_COMM("SCM SCR331-DI contactless detected");
+ }
+ else
+ {
+ DEBUG_COMM("SCM SCR331-DI contactless init failed");
+ }
+
+ /* hack since the contactless reader do not share dwFeatures */
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU;
+
+ ccid_descriptor->dwFeatures |= CCID_CLASS_AUTO_IFSD;
+ }
+ break;
+#endif
+ }
+
+ /* Gemalto readers may report additional information */
+ if (GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO)
+ set_gemalto_firmware_features(reader_index);
+
+ return return_value;
+} /* ccid_open_hack_post */
+
+/*****************************************************************************
+ *
+ * ccid_error
+ *
+ ****************************************************************************/
+void ccid_error(int error, const char *file, int line, const char *function)
+{
+#ifndef NO_LOG
+ const char *text;
+ char var_text[30];
+
+ switch (error)
+ {
+ case 0x00:
+ text = "Command not supported or not allowed";
+ break;
+
+ case 0x01:
+ text = "Wrong command length";
+ break;
+
+ case 0x05:
+ text = "Invalid slot number";
+ break;
+
+ case 0xA2:
+ text = "Card short-circuiting. Card powered off";
+ break;
+
+ case 0xA3:
+ text = "ATR too long (> 33)";
+ break;
+
+ case 0xAB:
+ text = "No data exchanged";
+ break;
+
+ case 0xB0:
+ text = "Reader in EMV mode and T=1 message too long";
+ break;
+
+ case 0xBB:
+ text = "Protocol error in EMV mode";
+ break;
+
+ case 0xBD:
+ text = "Card error during T=1 exchange";
+ break;
+
+ case 0xBE:
+ text = "Wrong APDU command length";
+ break;
+
+ case 0xE0:
+ text = "Slot busy";
+ break;
+
+ case 0xEF:
+ text = "PIN cancelled";
+ break;
+
+ case 0xF0:
+ text = "PIN timeout";
+ break;
+
+ case 0xF2:
+ text = "Busy with autosequence";
+ break;
+
+ case 0xF3:
+ text = "Deactivated protocol";
+ break;
+
+ case 0xF4:
+ text = "Procedure byte conflict";
+ break;
+
+ case 0xF5:
+ text = "Class not supported";
+ break;
+
+ case 0xF6:
+ text = "Protocol not supported";
+ break;
+
+ case 0xF7:
+ text = "Invalid ATR checksum byte (TCK)";
+ break;
+
+ case 0xF8:
+ text = "Invalid ATR first byte";
+ break;
+
+ case 0xFB:
+ text = "Hardware error";
+ break;
+
+ case 0xFC:
+ text = "Overrun error";
+ break;
+
+ case 0xFD:
+ text = "Parity error during exchange";
+ break;
+
+ case 0xFE:
+ text = "Card absent or mute";
+ break;
+
+ case 0xFF:
+ text = "Activity aborted by Host";
+ break;
+
+ default:
+#ifndef UEFI_DRIVER
+ if ((error >= 1) && (error <= 127))
+ (void)snprintf(var_text, sizeof(var_text), "error on byte %d",
+ error);
+ else
+ (void)snprintf(var_text, sizeof(var_text),
+ "Unknown CCID error: 0x%02X", error);
+#endif
+
+ text = var_text;
+ break;
+ }
+#ifndef UEFI_DRIVER
+ log_msg(PCSC_LOG_ERROR, "%s:%d:%s %s", file, line, function, text);
+#endif
+
+#endif
+
+} /* ccid_error */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid.h b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
new file mode 100644
index 0000000..0dc644c
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
@@ -0,0 +1,340 @@
+/*
+ ccid.h: CCID structures
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid.h 6845 2014-02-14 09:16:01Z rousseau $
+ */
+
+typedef struct
+{
+ /*
+ * CCID Sequence number
+ */
+ unsigned char *pbSeq;
+ unsigned char real_bSeq;
+
+ /*
+ * VendorID << 16 + ProductID
+ */
+ int readerID;
+
+ /*
+ * Maximum message length
+ */
+ unsigned int dwMaxCCIDMessageLength;
+
+ /*
+ * Maximum IFSD
+ */
+ int dwMaxIFSD;
+
+ /*
+ * Features supported by the reader (directly from Class Descriptor)
+ */
+ int dwFeatures;
+
+ /*
+ * PIN support of the reader (directly from Class Descriptor)
+ */
+ char bPINSupport;
+
+ /*
+ * Display dimensions of the reader (directly from Class Descriptor)
+ */
+ unsigned int wLcdLayout;
+
+ /*
+ * Default Clock
+ */
+ int dwDefaultClock;
+
+ /*
+ * Max Data Rate
+ */
+ unsigned int dwMaxDataRate;
+
+ /*
+ * Number of available slots
+ */
+ char bMaxSlotIndex;
+
+ /*
+ * Slot in use
+ */
+ char bCurrentSlotIndex;
+
+ /*
+ * The array of data rates supported by the reader
+ */
+ unsigned int *arrayOfSupportedDataRates;
+
+ /*
+ * Read communication port timeout
+ * value is milliseconds
+ * this value can evolve dynamically if card request it (time processing).
+ */
+ unsigned int readTimeout;
+
+ /*
+ * Card protocol
+ */
+ int cardProtocol;
+
+ /*
+ * bInterfaceProtocol (CCID, ICCD-A, ICCD-B)
+ */
+ int bInterfaceProtocol;
+
+ /*
+ * bNumEndpoints
+ */
+ int bNumEndpoints;
+
+ /*
+ * GemCore SIM PRO slot status management
+ * The reader always reports a card present even if no card is inserted.
+ * If the Power Up fails the driver will report IFD_ICC_NOT_PRESENT instead
+ * of IFD_ICC_PRESENT
+ */
+ int dwSlotStatus;
+
+ /*
+ * bVoltageSupport (bit field)
+ * 1 = 5.0V
+ * 2 = 3.0V
+ * 4 = 1.8V
+ */
+ int bVoltageSupport;
+
+ /*
+ * USB serial number of the device (if any)
+ */
+ char *sIFD_serial_number;
+
+ /*
+ * USB iManufacturer string
+ */
+ char *sIFD_iManufacturer;
+
+ /*
+ * USB bcdDevice
+ */
+ int IFD_bcdDevice;
+
+ /*
+ * Gemalto extra features, if any
+ */
+ struct GEMALTO_FIRMWARE_FEATURES *gemalto_firmware_features;
+
+ /*
+ * Zero Length Packet fixup (boolean)
+ */
+ char zlp;
+} _ccid_descriptor;
+
+/* Features from dwFeatures */
+#define CCID_CLASS_AUTO_CONF_ATR 0x00000002
+#define CCID_CLASS_AUTO_VOLTAGE 0x00000008
+#define CCID_CLASS_AUTO_BAUD 0x00000020
+#define CCID_CLASS_AUTO_PPS_PROP 0x00000040
+#define CCID_CLASS_AUTO_PPS_CUR 0x00000080
+#define CCID_CLASS_AUTO_IFSD 0x00000400
+#define CCID_CLASS_CHARACTER 0x00000000
+#define CCID_CLASS_TPDU 0x00010000
+#define CCID_CLASS_SHORT_APDU 0x00020000
+#define CCID_CLASS_EXTENDED_APDU 0x00040000
+#define CCID_CLASS_EXCHANGE_MASK 0x00070000
+
+/* Features from bPINSupport */
+#define CCID_CLASS_PIN_VERIFY 0x01
+#define CCID_CLASS_PIN_MODIFY 0x02
+
+/* See CCID specs ch. 4.2.1 */
+#define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */
+#define CCID_ICC_PRESENT_INACTIVE 0x01 /* 00 0000 01 */
+#define CCID_ICC_ABSENT 0x02 /* 00 0000 10 */
+#define CCID_ICC_STATUS_MASK 0x03 /* 00 0000 11 */
+
+#define CCID_COMMAND_FAILED 0x40 /* 01 0000 00 */
+#define CCID_TIME_EXTENSION 0x80 /* 10 0000 00 */
+
+/* bInterfaceProtocol for ICCD */
+#define PROTOCOL_CCID 0 /* plain CCID */
+#define PROTOCOL_ICCD_A 1 /* ICCD Version A */
+#define PROTOCOL_ICCD_B 2 /* ICCD Version B */
+
+/* Product identification for special treatments */
+#define GEMPC433 0x08E64433
+#define GEMPCKEY 0x08E63438
+#define GEMPCTWIN 0x08E63437
+#define GEMPCPINPAD 0x08E63478
+#define GEMCORESIMPRO 0x08E63480
+#define GEMCORESIMPRO2 0x08E60000 /* Does NOT match a real VID/PID as new firmware release exposes same VID/PID */
+#define GEMCOREPOSPRO 0x08E63479
+#define GEMALTOPROXDU 0x08E65503
+#define GEMALTOPROXSU 0x08E65504
+#define GEMALTO_EZIO_CBP 0x08E634C3
+#define CARDMAN3121 0x076B3021
+#define LTC31 0x07830003
+#define SCR331DI 0x04E65111
+#define SCR331DINTTCOM 0x04E65120
+#define SDI010 0x04E65121
+#define CHERRYXX33 0x046A0005
+#define CHERRYST2000 0x046A003E
+#define OZ776 0x0B977762
+#define OZ776_7772 0x0B977772
+#define SPR532 0x04E6E003
+#define MYSMARTPAD 0x09BE0002
+#define CHERRYXX44 0x046a0010
+#define CL1356D 0x0B810200
+#define REINER_SCT 0x0C4B0300
+#define SEG 0x08E68000
+#define BLUDRIVEII_CCID 0x1B0E1078
+#define DELLSCRK 0x413C2101
+#define DELLSK 0x413C2100
+#define KOBIL_TRIBANK 0x0D463010
+#define KOBIL_MIDENTITY_VISUAL 0x0D460D46
+#define VEGAALPHA 0x09820008
+#define HPSMARTCARDKEYBOARD 0x03F01024
+#define HP_CCIDSMARTCARDKEYBOARD 0x03F00036
+#define KOBIL_IDTOKEN 0x0D46301D
+#define FUJITSUSMARTKEYB 0x0BF81017
+
+#define VENDOR_GEMALTO 0x08E6
+#define GET_VENDOR(readerID) ((readerID >> 16) & 0xFFFF)
+
+/*
+ * The O2Micro OZ776S reader has a wrong USB descriptor
+ * The extra[] field is associated with the last endpoint instead of the
+ * main USB descriptor
+ */
+#define O2MICRO_OZ776_PATCH
+
+/* Escape sequence codes */
+#define ESC_GEMPC_SET_ISO_MODE 1
+#define ESC_GEMPC_SET_APDU_MODE 2
+
+/*
+ * Possible values :
+ * 3 -> 1.8V, 3V, 5V
+ * 2 -> 3V, 5V
+ * 1 -> 5V only
+ * 0 -> automatic (selection made by the reader)
+ */
+/*
+ * To be safe we default to 5V
+ * otherwise we would have to parse the ATR and get the value of TAi (i>2) when
+ * in T=15
+ */
+#define VOLTAGE_AUTO 0
+#define VOLTAGE_5V 1
+#define VOLTAGE_3V 2
+#define VOLTAGE_1_8V 3
+
+int ccid_open_hack_pre(unsigned int reader_index);
+int ccid_open_hack_post(unsigned int reader_index);
+void ccid_error(int error, const char *file, int line, const char *function);
+_ccid_descriptor *get_ccid_descriptor(unsigned int reader_index);
+
+/* convert a 4 byte integer in USB format into an int */
+#define dw2i(a, x) (unsigned int)((((((a[x+3] << 8) + a[x+2]) << 8) + a[x+1]) << 8) + a[x])
+
+/* all the data rates specified by ISO 7816-3 Fi/Di tables */
+#define ISO_DATA_RATES 10753, 14337, 15625, 17204, \
+ 20833, 21505, 23438, 25806, 28674, \
+ 31250, 32258, 34409, 39063, 41667, \
+ 43011, 46875, 52083, 53763, 57348, \
+ 62500, 64516, 68817, 71685, 78125, \
+ 83333, 86022, 93750, 104167, 107527, \
+ 114695, 125000, 129032, 143369, 156250, \
+ 166667, 172043, 215054, 229391, 250000, \
+ 344086
+
+/* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */
+#define GEMPLUS_CUSTOM_DATA_RATES 10753, 21505, 43011, 125000
+
+/* data rates for GemCore SIM Pro 2 */
+#define SIMPRO2_ISO_DATA_RATES 8709, 10322, 12403, 12500, \
+ 12903, 17204, 18750, 20645, 24806, \
+ 25000, 25806, 28125, 30967, 34408, \
+ 37500, 41290, 46875, 49612, 50000, \
+ 51612, 56250, 62500, 64516, 68817, \
+ 74418, 75000, 82580, 86021, 93750, \
+ 99224, 100000, 103225, 112500, 124031, \
+ 125000, 137634, 150000, 154838, 165161, \
+ 172043, 187500, 198449, 200000, 206451, \
+ 258064, 275268, 300000, 396899, 400000, \
+ 412903, 550537, 600000, 825806
+
+/* Structure returned by Gemalto readers for the CCID Escape command 0x6A */
+struct GEMALTO_FIRMWARE_FEATURES
+{
+ unsigned char bLogicalLCDLineNumber; /* Logical number of LCD lines */
+ unsigned char bLogicalLCDRowNumber; /* Logical number of characters per LCD line */
+ unsigned char bLcdInfo; /* b0 indicates if scrolling is available */
+ unsigned char bEntryValidationCondition; /* See PIN_PROPERTIES */
+
+ /* Here come the PC/SC bit features to report */
+ unsigned char VerifyPinStart:1;
+ unsigned char VerifyPinFinish:1;
+ unsigned char ModifyPinStart:1;
+ unsigned char ModifyPinFinish:1;
+ unsigned char GetKeyPressed:1;
+ unsigned char VerifyPinDirect:1;
+ unsigned char ModifyPinDirect:1;
+ unsigned char Abort:1;
+
+ unsigned char GetKey:1;
+ unsigned char WriteDisplay:1;
+ unsigned char SetSpeMessage:1;
+ unsigned char RFUb1:5;
+
+ unsigned char RFUb2[2];
+
+ /* Additional flags */
+ unsigned char bTimeOut2:1;
+ unsigned char bListSupportedLanguages:1; /* Reader is able to indicate
+ the list of supported languages through CCID-ESC 0x6B */
+ unsigned char bNumberMessageFix:1; /* Reader handles correctly shifts
+ made by bNumberMessage in PIN modification data structure */
+ unsigned char bPPDUSupportOverXferBlock:1; /* Reader supports PPDU over
+ PC_to_RDR_XferBlock command */
+ unsigned char bPPDUSupportOverEscape:1; /* Reader supports PPDU over
+ PC_to_RDR_Escape command with abData[0]=0xFF */
+ unsigned char RFUb3:3;
+
+ unsigned char RFUb4[3];
+
+ unsigned char VersionNumber; /* ?? */
+ unsigned char MinimumPINSize; /* for Verify and Modify */
+ unsigned char MaximumPINSize;
+
+ /* Miscellaneous reader features */
+ unsigned char Firewall:1;
+ unsigned char RFUb5:7;
+
+ /* The following fields, FirewalledCommand_SW1 and
+ * FirewalledCommand_SW2 are only valid if Firewall=1
+ * These fields give the SW1 SW2 value used by the reader to
+ * indicate a command has been firewalled */
+ unsigned char FirewalledCommand_SW1;
+ unsigned char FirewalledCommand_SW2;
+ unsigned char RFUb6[3];
+};
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
new file mode 100644
index 0000000..6276154
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
@@ -0,0 +1,63 @@
+/*
+ ccid_ifdhandler.h: non-generic ifdhandler functions
+ Copyright (C) 2004-2010 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid_ifdhandler.h 6876 2014-03-23 12:00:57Z rousseau $
+ */
+
+#ifndef _ccid_ifd_handler_h_
+#define _ccid_ifd_handler_h_
+
+#define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1)
+
+#define CLASS2_IOCTL_MAGIC 0x330000
+#define IOCTL_FEATURE_VERIFY_PIN_DIRECT \
+ SCARD_CTL_CODE(FEATURE_VERIFY_PIN_DIRECT + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_MODIFY_PIN_DIRECT \
+ SCARD_CTL_CODE(FEATURE_MODIFY_PIN_DIRECT + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_MCT_READER_DIRECT \
+ SCARD_CTL_CODE(FEATURE_MCT_READER_DIRECT + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_IFD_PIN_PROPERTIES \
+ 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 DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED 1
+#define DRIVER_OPTION_GEMPC_TWIN_KEY_APDU 2
+#define DRIVER_OPTION_USE_BOGUS_FIRMWARE 4
+#define DRIVER_OPTION_RESET_ON_CLOSE 8
+#define DRIVER_OPTION_DISABLE_PIN_RETRIES (1 << 6)
+
+extern int DriverOptions;
+
+/*
+ * Maximum number of CCID readers supported simultaneously
+ *
+ * The maximum number of readers is also limited in pcsc-lite (16 by default)
+ * see the definition of PCSCLITE_MAX_READERS_CONTEXTS in src/PCSC/pcsclite.h
+ */
+#define CCID_DRIVER_MAX_READERS 16
+
+/*
+ * CCID driver specific functions
+ */
+CcidDesc *get_ccid_slot(unsigned int reader_index);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
new file mode 100644
index 0000000..ac888c1
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
@@ -0,0 +1,470 @@
+/*
+ ccid_uefi.c: USB access routines using the UEFI USB protocol
+ Copyright (C) 2014 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid_usb.c 6890 2014-04-24 13:51:03Z rousseau $
+ */
+
+#include <Protocol/UsbIo.h>
+#include <Library/UefiLib.h>
+#include <CcidDriver.h>
+
+#include <ifdhandler.h>
+
+#include "config.h"
+#include "misc.h"
+#include "ccid.h"
+#include "debug.h"
+#include "defs.h"
+#include "utils.h"
+#include "ccid_ifdhandler.h"
+
+
+/* write timeout
+ * we don't have to wait a long time since the card was doing nothing */
+#define USB_WRITE_TIMEOUT (5 * 1000) /* 5 seconds timeout */
+
+/*
+ * Proprietary USB Class (0xFF) are (or are not) accepted
+ * A proprietary class is used for devices released before the final CCID
+ * specifications were ready.
+ * We should not have problems with non CCID devices because the
+ * Manufacturer and Product ID are also used to identify the device */
+#define ALLOW_PROPRIETARY_CLASS
+
+#define BUS_DEVICE_STRSIZE 32
+
+#define CCID_INTERRUPT_SIZE 8
+
+typedef struct
+{
+ EFI_USB_INTERFACE_DESCRIPTOR *dev_handle;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ uint8_t bus_number;
+ uint8_t device_address;
+
+ /*
+ * Endpoints
+ */
+ EFI_USB_ENDPOINT_DESCRIPTOR bulk_in;
+ EFI_USB_ENDPOINT_DESCRIPTOR bulk_out;
+ EFI_USB_ENDPOINT_DESCRIPTOR interrupt;
+
+ /* Number of slots using the same device */
+ int real_nb_opened_slots;
+ int *nb_opened_slots;
+
+ /*
+ * CCID infos common to USB and serial
+ */
+ _ccid_descriptor ccid;
+
+} _usbDevice;
+
+/* The _usbDevice structure must be defined before including ccid_usb.h */
+#include "ccid_uefi.h"
+
+/* ne need to initialize to 0 since it is static */
+static _usbDevice usbDevice[CCID_DRIVER_MAX_READERS];
+
+//
+// Send general device request timeout.
+//
+// The USB Specification 2.0, section 11.24.1 recommends a value of
+// 50 milliseconds. We use a value of 500 milliseconds to work
+// around slower hubs and devices.
+//
+#define USB_GENERAL_DEVICE_REQUEST_TIMEOUT 500
+
+
+/*****************************************************************************
+ *
+ * OpenUEFI
+ *
+ ****************************************************************************/
+status_t OpenUEFI(unsigned int reader_index, DWORD Channel)
+{
+ int return_value = STATUS_UNSUCCESSFUL;
+ USB_CCID_DEV *UsbCcidDevice = (USB_CCID_DEV *)Channel;
+ int index;
+ UINT8 EndpointNumber;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ unsigned char * device_descriptor, *ccid_descriptor;
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT32 Status_uint;
+
+ DEBUG_COMM3("Reader index: %X, Channel: %p", reader_index, UsbCcidDevice);
+
+ UsbIo = UsbCcidDevice->UsbIo;
+ usbDevice[reader_index].UsbIo = UsbIo;
+
+ //
+ // Get the Device Path Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ UsbCcidDevice->ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbCcidDevice->DevicePath,
+ UsbCcidDevice->DriverBindingHandle,
+ UsbCcidDevice->ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "OpenProtocol %d", Status);
+ goto ErrorExit;
+ }
+
+ /* Get Device descriptor */
+ Status = UsbIo->UsbGetDeviceDescriptor(UsbIo,
+ &UsbCcidDevice->DeviceDescriptor);
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "UsbGetDeviceDescriptor %d", Status);
+ goto ErrorExit;
+ }
+
+ /* Get Config descriptor */
+ Status = UsbIo->UsbGetConfigDescriptor(UsbIo,
+ &UsbCcidDevice->ConfigDescriptor);
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "UsbGetConfigDescriptor %d", Status);
+ goto ErrorExit;
+ }
+
+ //
+ // Get interface & endpoint descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor(UsbIo,
+ &UsbCcidDevice->InterfaceDescriptor);
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "UsbGetInterfaceDescriptor %d", Status);
+ goto ErrorExit;
+ }
+
+ EndpointNumber = UsbCcidDevice->InterfaceDescriptor.NumEndpoints;
+
+ /* Get Endpoints values*/
+ for (index = 0; index < EndpointNumber; index++)
+ {
+ UsbIo->UsbGetEndpointDescriptor (UsbIo, index, &EndpointDescriptor);
+
+ if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT)
+ CopyMem(&usbDevice[reader_index].interrupt, &EndpointDescriptor, sizeof(EndpointDescriptor));
+
+ if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)
+ {
+ if (EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN)
+ CopyMem(&usbDevice[reader_index].bulk_in, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ else
+ CopyMem(&usbDevice[reader_index].bulk_out, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ }
+ }
+
+ device_descriptor = AllocateZeroPool(UsbCcidDevice->ConfigDescriptor.TotalLength);
+ ASSERT(device_descriptor != NULL);
+
+ /* Get USB CCID Descriptor */
+ DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;
+ DevReq.Request = USB_REQ_GET_DESCRIPTOR;
+ DevReq.Value = (UINT16)((USB_DESC_TYPE_CONFIG << 8) | 0 /* Index */);
+ DevReq.Index = UsbCcidDevice->InterfaceDescriptor.InterfaceNumber;
+ DevReq.Length = UsbCcidDevice->ConfigDescriptor.TotalLength;
+
+ Status = UsbIo->UsbControlTransfer(UsbIo,
+ &DevReq,
+ EfiUsbDataIn,
+ USB_GENERAL_DEVICE_REQUEST_TIMEOUT,
+ device_descriptor,
+ UsbCcidDevice->ConfigDescriptor.TotalLength,
+ &Status_uint
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeExit;
+ }
+
+ /* find the CCID descriptor */
+ index = 0;
+ while (device_descriptor[index] != 0x36 && index < UsbCcidDevice->ConfigDescriptor.TotalLength)
+ {
+ /* bug in descriptor? */
+ if (0 == device_descriptor[index])
+ break;
+
+ index += device_descriptor[index];
+ }
+
+ if (device_descriptor[index] != 0x36 && device_descriptor[index+1] != 0x21)
+ {
+ Print(L"CCID descriptor not found\n");
+ goto FreeExit;
+ }
+
+ /* move to the first byte of the CCID descriptor */
+ ccid_descriptor = device_descriptor + index;
+
+ /* store device information */
+ usbDevice[reader_index].real_nb_opened_slots = 1;
+ usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots;
+
+ /* CCID common informations */
+ usbDevice[reader_index].ccid.real_bSeq = 0;
+ usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq;
+ usbDevice[reader_index].ccid.readerID =
+ (UsbCcidDevice->DeviceDescriptor.IdVendor << 16)
+ + UsbCcidDevice->DeviceDescriptor.IdProduct;
+ usbDevice[reader_index].ccid.dwFeatures = dw2i(ccid_descriptor, 40);
+ usbDevice[reader_index].ccid.wLcdLayout =
+ (ccid_descriptor[51] << 8) + ccid_descriptor[50];
+ usbDevice[reader_index].ccid.bPINSupport = ccid_descriptor[52];
+ usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(ccid_descriptor, 44);
+ usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(ccid_descriptor, 28);
+ usbDevice[reader_index].ccid.dwDefaultClock = dw2i(ccid_descriptor, 10);
+ usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(ccid_descriptor, 23);
+ usbDevice[reader_index].ccid.bMaxSlotIndex = ccid_descriptor[4];
+ usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
+ usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
+#if 0
+ if (ccid_descriptor[27])
+ usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, config_desc, num);
+ else
+ {
+ usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
+ DEBUG_INFO1("bNumDataRatesSupported is 0");
+ }
+#endif
+ usbDevice[reader_index].ccid.bInterfaceProtocol = UsbCcidDevice->InterfaceDescriptor.InterfaceProtocol;
+ usbDevice[reader_index].ccid.bNumEndpoints = UsbCcidDevice->InterfaceDescriptor.NumEndpoints;
+ usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
+ usbDevice[reader_index].ccid.bVoltageSupport = ccid_descriptor[5];
+ usbDevice[reader_index].ccid.sIFD_serial_number = NULL;
+ usbDevice[reader_index].ccid.gemalto_firmware_features = NULL;
+ usbDevice[reader_index].ccid.zlp = FALSE;
+ usbDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
+ usbDevice[reader_index].ccid.IFD_bcdDevice = UsbCcidDevice->DeviceDescriptor.BcdDevice;
+
+ /* no error */
+ return_value = STATUS_SUCCESS;
+
+FreeExit:
+ FreePool(device_descriptor);
+
+ErrorExit:
+ return return_value;
+} /* OpenUEFI */
+
+
+/*****************************************************************************
+ *
+ * OpenUEFIByName
+ *
+ ****************************************************************************/
+status_t OpenUEFIByName(unsigned int reader_index, /*@null@*/ char *device)
+{
+ return STATUS_UNSUCCESSFUL;
+} /* OpenUEFIByName */
+
+
+/*****************************************************************************
+ *
+ * WriteUEFI
+ *
+ ****************************************************************************/
+status_t WriteUEFI(unsigned int reader_index, unsigned int length,
+ unsigned char *buffer)
+{
+ UINT32 TransStatus;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo = usbDevice[reader_index].UsbIo;
+ UINTN DataLength;
+
+ DEBUG_XXD(">", buffer, length);
+
+ DataLength = length;
+ Status = UsbIo->UsbBulkTransfer(UsbIo,
+ usbDevice[reader_index].bulk_out.EndpointAddress, buffer, &DataLength,
+ USB_WRITE_TIMEOUT, &TransStatus);
+
+ if (EFI_ERROR (Status))
+ {
+ Print(L"UsbBulkTransfer(write) failed\n");
+ return STATUS_COMM_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+} /* WriteUEFI */
+
+
+/*****************************************************************************
+ *
+ * ReadUEFI
+ *
+ ****************************************************************************/
+status_t ReadUEFI(unsigned int reader_index, unsigned int * length,
+ unsigned char *buffer)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ int duplicate_frame = 0;
+ UINT32 TransStatus;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo = usbDevice[reader_index].UsbIo;
+ UINTN DataLength;
+
+read_again:
+ DataLength = *length;
+ Status = UsbIo->UsbBulkTransfer(UsbIo,
+ usbDevice[reader_index].bulk_in.EndpointAddress, buffer, &DataLength,
+ usbDevice[reader_index].ccid.readTimeout, &TransStatus);
+
+ if (EFI_ERROR (Status))
+ {
+ *length = 0;
+ Print(L"UsbBulkTransfer(read) failed\n");
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ *length = DataLength;
+
+ DEBUG_XXD("<", buffer, *length);
+
+#define BSEQ_OFFSET 6
+ if ((*length >= BSEQ_OFFSET)
+ && (buffer[BSEQ_OFFSET] < *ccid_descriptor->pbSeq -1))
+ {
+ duplicate_frame++;
+ if (duplicate_frame > 10)
+ {
+ DEBUG_CRITICAL("Too many duplicate frame detected");
+ return STATUS_UNSUCCESSFUL;
+ }
+ DEBUG_INFO1("Duplicate frame detected");
+ goto read_again;
+ }
+
+ return STATUS_SUCCESS;
+} /* ReadUEFI */
+
+
+/*****************************************************************************
+ *
+ * ControlUSB
+ *
+ ****************************************************************************/
+int ControlUSB(int reader_index, int requesttype, int request, int value,
+ unsigned char *bytes, unsigned int size)
+{
+ Print(L"ControlUEFI not implemented\n");
+ return STATUS_COMM_ERROR;
+} /* ControlUSB */
+
+
+/*****************************************************************************
+ *
+ * CloseUEFI
+ *
+ ****************************************************************************/
+status_t CloseUEFI(unsigned int reader_index)
+{
+ /* device not opened */
+ if (usbDevice[reader_index].dev_handle == NULL)
+ return STATUS_UNSUCCESSFUL;
+
+ Log0(PCSC_LOG_DEBUG);
+ DEBUG_COMM3("Closing USB device: %d/%d",
+ usbDevice[reader_index].bus_number,
+ usbDevice[reader_index].device_address);
+
+ /* one slot closed */
+ (*usbDevice[reader_index].nb_opened_slots)--;
+
+ /* release the allocated ressources for the last slot only */
+ if (0 == *usbDevice[reader_index].nb_opened_slots)
+ {
+ DEBUG_COMM("Last slot closed. Release resources");
+
+ if (usbDevice[reader_index].ccid.gemalto_firmware_features)
+ free(usbDevice[reader_index].ccid.gemalto_firmware_features);
+
+ if (usbDevice[reader_index].ccid.sIFD_serial_number)
+ free(usbDevice[reader_index].ccid.sIFD_serial_number);
+
+ if (usbDevice[reader_index].ccid.sIFD_iManufacturer)
+ free(usbDevice[reader_index].ccid.sIFD_iManufacturer);
+
+ if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates)
+ free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);
+ }
+
+ /* mark the resource unused */
+ usbDevice[reader_index].dev_handle = NULL;
+
+ return STATUS_SUCCESS;
+} /* CloseUEFI */
+
+
+/*****************************************************************************
+ *
+ * get_ccid_descriptor
+ *
+ ****************************************************************************/
+_ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
+{
+ return &usbDevice[reader_index].ccid;
+} /* get_ccid_descriptor */
+
+
+/*****************************************************************************
+ *
+ * get_usb_device
+ *
+ ****************************************************************************/
+void duplicate_usb_device(unsigned int reader_index,
+ unsigned int new_reader_index)
+{
+ usbDevice[new_reader_index] = usbDevice[reader_index];
+} /* get_usb_device */
+
+/*****************************************************************************
+ *
+ * InterruptRead
+ *
+ ****************************************************************************/
+int InterruptRead(int reader_index, int timeout /* in ms */)
+{
+ int return_value = IFD_SUCCESS;
+ return return_value;
+} /* InterruptRead */
+
+
+/*****************************************************************************
+ *
+ * Stop the async loop
+ *
+ ****************************************************************************/
+void InterruptStop(int reader_index)
+{
+} /* InterruptStop */
+
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
new file mode 100644
index 0000000..31d32f0
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
@@ -0,0 +1,46 @@
+/*
+ ccid_uefi.h: USB access routines using the UEFI USB protocol
+ Copyright (C) 2014 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid_uefi.h 5473 2011-01-04 09:52:26Z rousseau $
+ */
+
+#ifndef __CCID_UEF_H__
+#define __CCID_UEFI_H__
+status_t OpenUEFI(unsigned int reader_index, DWORD channel);
+
+status_t OpenUEFIByName(unsigned int reader_index, /*@null@*/ char *device);
+
+status_t WriteUEFI(unsigned int reader_index, unsigned int length,
+ unsigned char *Buffer);
+
+status_t ReadUEFI(unsigned int reader_index, unsigned int *length,
+ /*@out@*/ unsigned char *Buffer);
+
+status_t CloseUEFI(unsigned int reader_index);
+
+int ControlUSB(int reader_index, int requesttype, int request, int value,
+ unsigned char *bytes, unsigned int size);
+
+void duplicate_usb_device(unsigned int reader_index,
+ unsigned int new_reader_index);
+
+int InterruptRead(int reader_index, int timeout);
+
+#endif
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/commands.c b/MdeModulePkg/Library/SmartCardReader/libccid/commands.c
new file mode 100644
index 0000000..006f546
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/commands.c
@@ -0,0 +1,2294 @@
+/*
+ commands.c: Commands sent to the card
+ Copyright (C) 2003-2010 Ludovic Rousseau
+ Copyright (C) 2005 Martin Paljak
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: commands.c 6975 2014-09-04 11:33:05Z rousseau $
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <pcsclite.h>
+#include <ifdhandler.h>
+#include <reader.h>
+
+#include "misc.h"
+#include "commands.h"
+#include "openct/proto-t1.h"
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "debug.h"
+
+/* All the pinpad readers I used are more or less bogus
+ * I use code to change the user command and make the firmware happy */
+#define BOGUS_PINPAD_FIRMWARE
+
+/* The firmware of SCM readers reports dwMaxCCIDMessageLength = 263
+ * instead of 270 so this prevents from sending a full length APDU
+ * of 260 bytes since the driver check this value */
+#define BOGUS_SCM_FIRMWARE_FOR_dwMaxCCIDMessageLength
+
+#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef BSWAP_16
+#define BSWAP_8(x) ((x) & 0xff)
+#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
+#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
+#endif
+
+#define CHECK_STATUS(res) \
+ if (STATUS_NO_SUCH_DEVICE == res) \
+ return IFD_NO_SUCH_DEVICE; \
+ if (STATUS_SUCCESS != res) \
+ return IFD_COMMUNICATION_ERROR;
+
+/* internal functions */
+static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[]);
+
+static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[]);
+
+static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index, unsigned int
+ tx_length, unsigned char tx_buffer[], unsigned int *rx_length, unsigned
+ char rx_buffer[]);
+
+static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[]);
+
+static void i2dw(int value, unsigned char *buffer);
+static unsigned int bei2i(unsigned char *buffer);
+
+
+/*****************************************************************************
+ *
+ * CmdPowerOn
+ *
+ ****************************************************************************/
+RESPONSECODE CmdPowerOn(unsigned int reader_index, unsigned int * nlength,
+ unsigned char buffer[], int voltage)
+{
+ unsigned char cmd[10];
+ status_t res;
+ int length, count = 1;
+ unsigned int atr_len;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+
+ /* first power off to reset the ICC state machine */
+ r = CmdPowerOff(reader_index);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* wait for ready */
+ r = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Power On */
+ r = ControlUSB(reader_index, 0xA1, 0x62, 0, buffer, *nlength);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ *nlength = r;
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char tmp[MAX_ATR_SIZE+1];
+
+ /* first power off to reset the ICC state machine */
+ r = CmdPowerOff(reader_index);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Power On */
+ r = ControlUSB(reader_index, 0x21, 0x62, 1, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, tmp, sizeof(tmp));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (tmp[0] != 0x00)
+ {
+ DEBUG_CRITICAL2("bResponseType: 0x%02X", tmp[0]);
+
+ /* Status Information? */
+ if (0x40 == tmp[0])
+ ccid_error(tmp[2], __FILE__, __LINE__, __FUNCTION__);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ DEBUG_INFO_XXD("Data Block: ", tmp, r);
+ if ((int)*nlength > r-1)
+ *nlength = r-1;
+ memcpy(buffer, tmp+1, *nlength);
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ /* store length of buffer[] */
+ length = *nlength;
+
+ if (ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_VOLTAGE)
+ voltage = 0; /* automatic voltage selection */
+ else
+ {
+ int bVoltageSupport = ccid_descriptor->bVoltageSupport;
+
+ if ((1 == voltage) && !(bVoltageSupport & 1))
+ {
+ DEBUG_INFO1("5V requested but not support by reader");
+ voltage = 2; /* 3V */
+ }
+
+ if ((2 == voltage) && !(bVoltageSupport & 2))
+ {
+ DEBUG_INFO1("3V requested but not support by reader");
+ voltage = 3; /* 1.8V */
+ }
+
+ if ((3 == voltage) && !(bVoltageSupport & 4))
+ {
+ DEBUG_INFO1("1.8V requested but not support by reader");
+ voltage = 0; /* auto */
+ }
+ }
+
+again:
+ cmd[0] = 0x62; /* IccPowerOn */
+ cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = voltage;
+ cmd[8] = cmd[9] = 0; /* RFU */
+
+ res = WritePort(reader_index, sizeof(cmd), cmd);
+ CHECK_STATUS(res)
+
+ /* reset available buffer size */
+ /* needed if we go back after a switch to ISO mode */
+ *nlength = length;
+
+ res = ReadPort(reader_index, nlength, buffer);
+ CHECK_STATUS(res)
+
+ if (*nlength < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", *nlength);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+
+ if (0xBB == buffer[ERROR_OFFSET] && /* Protocol error in EMV mode */
+ ((GEMPC433 == ccid_descriptor->readerID)
+ || (CHERRYXX33 == ccid_descriptor->readerID)))
+ {
+ unsigned char cmd_tmp[] = {0x1F, 0x01};
+ unsigned char res_tmp[1];
+ unsigned int res_length = sizeof(res_tmp);
+
+ if ((return_value = CmdEscape(reader_index, cmd_tmp,
+ sizeof(cmd_tmp), res_tmp, &res_length, 0)) != IFD_SUCCESS)
+ return return_value;
+
+ /* avoid looping if we can't switch mode */
+ if (count--)
+ goto again;
+ else
+ DEBUG_CRITICAL("Can't set reader in ISO mode");
+ }
+
+ /* continue with 3 volts and 5 volts */
+ if (voltage > 1)
+ {
+#ifndef NO_LOG
+ const char *voltage_code[] = { "auto", "5V", "3V", "1.8V" };
+#endif
+
+ DEBUG_INFO3("Power up with %s failed. Try with %s.",
+ voltage_code[voltage], voltage_code[voltage-1]);
+ voltage--;
+ goto again;
+ }
+
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* extract the ATR */
+ atr_len = dw2i(buffer, 1); /* ATR length */
+ if (atr_len > *nlength)
+ atr_len = *nlength;
+ else
+ *nlength = atr_len;
+
+ memmove(buffer, buffer+10, atr_len);
+
+ return return_value;
+} /* CmdPowerOn */
+
+
+/*****************************************************************************
+ *
+ * SecurePINVerify
+ *
+ ****************************************************************************/
+RESPONSECODE SecurePINVerify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength)
+{
+ unsigned char cmd[11+14+TxLength];
+ unsigned int a, b;
+ PIN_VERIFY_STRUCTURE *pvs;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ int old_read_timeout;
+ RESPONSECODE ret;
+ status_t res;
+
+ pvs = (PIN_VERIFY_STRUCTURE *)TxBuffer;
+ cmd[0] = 0x69; /* Secure */
+ 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] = 0; /* bPINOperation: PIN Verification */
+
+ if (TxLength < 19+4 /* 4 = APDU size */) /* command too short? */
+ {
+ DEBUG_INFO3("Command too short: %d < %d", TxLength, 19+4);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* On little endian machines we are all set. */
+ /* If on big endian machine and caller is using host byte order */
+ if ((pvs->ulDataLength + 19 == TxLength) &&
+ (bei2i((unsigned char*)(&pvs->ulDataLength)) == pvs->ulDataLength))
+ {
+ DEBUG_INFO1("Reversing order from big to little endian");
+ /* If ulDataLength is big endian, assume others are too */
+ /* reverse the byte order for 3 fields */
+ pvs->wPINMaxExtraDigit = BSWAP_16(pvs->wPINMaxExtraDigit);
+ pvs->wLangId = BSWAP_16(pvs->wLangId);
+ pvs->ulDataLength = BSWAP_32(pvs->ulDataLength);
+ }
+ /* At this point we now have the above 3 variables in little endian */
+
+ if (dw2i(TxBuffer, 15) + 19 != TxLength) /* ulDataLength field coherency */
+ {
+ DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 15) + 19, TxLength);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* make sure bEntryValidationCondition is valid
+ * The Cherry XX44 reader crashes with a wrong value */
+ if ((0x00 == TxBuffer[7]) || (TxBuffer[7] > 0x07))
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition (was 0x%02X)",
+ TxBuffer[7]);
+ TxBuffer[7] = 0x02;
+ }
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+ /* bug circumvention for the GemPC Pinpad */
+ if ((GEMPCPINPAD == ccid_descriptor->readerID)
+ || (VEGAALPHA == ccid_descriptor->readerID))
+ {
+ /* the firmware reject the cases: 00h No string and FFh default
+ * CCID message. The only value supported is 01h (display 1 message) */
+ if (0x01 != TxBuffer[8])
+ {
+ DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
+ TxBuffer[8]);
+ TxBuffer[8] = 0x01;
+ }
+
+ /* The reader does not support, and actively reject, "max size reached"
+ * and "timeout occured" validation conditions */
+ if (0x02 != TxBuffer[7])
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
+ TxBuffer[7]);
+ TxBuffer[7] = 0x02; /* validation key pressed */
+ }
+
+ }
+
+ if ((DELLSCRK == ccid_descriptor->readerID)
+ || (DELLSK == ccid_descriptor->readerID))
+ {
+ /* the firmware rejects the cases: 01h-FEh and FFh default
+ * CCID message. The only value supported is 00h (no message) */
+ if (0x00 != TxBuffer[8])
+ {
+ DEBUG_INFO2("Correct bNumberMessage for Dell keyboard (was %d)",
+ TxBuffer[8]);
+ TxBuffer[8] = 0x00;
+ }
+
+ /* avoid the command rejection because the Enter key is still
+ * pressed. Wait a bit for the key to be released */
+ (void)usleep(250*1000);
+ }
+
+ if (DELLSK == ccid_descriptor->readerID)
+ {
+ /* the 2 bytes of wPINMaxExtraDigit are reversed */
+ int tmp;
+
+ tmp = TxBuffer[6];
+ TxBuffer[6] = TxBuffer[5];
+ TxBuffer[5] = tmp;
+ DEBUG_INFO1("Correcting wPINMaxExtraDigit for Dell keyboard");
+ }
+#endif
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ ct_buf_t sbuf;
+ unsigned char sdata[T1_BUFFER_SIZE];
+
+ /* Initialize send buffer with the APDU */
+ ct_buf_set(&sbuf,
+ (void *)(TxBuffer + offsetof(PIN_VERIFY_STRUCTURE, abData)),
+ TxLength - offsetof(PIN_VERIFY_STRUCTURE, abData));
+
+ /* Create T=1 block */
+ (void)t1_build(&((get_ccid_slot(reader_index))->t1),
+ sdata, 0, T1_I_BLOCK, &sbuf, NULL);
+
+ /* Increment the sequence numbers */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+
+ /* Copy the generated T=1 block prologue into the teoprologue
+ * of the CCID command */
+ memcpy(TxBuffer + offsetof(PIN_VERIFY_STRUCTURE, bTeoPrologue),
+ sdata, 3);
+ }
+
+ /* Build a CCID block from a PC/SC V2.02.05 Part 10 block */
+ for (a = 11, b = 0; b < TxLength; b++)
+ {
+ if (1 == b) /* bTimeOut2 field */
+ /* Ignore the second timeout as there's nothing we can do with
+ * it currently */
+ continue;
+
+ if ((b >= 15) && (b <= 18)) /* ulDataLength field (4 bytes) */
+ /* the ulDataLength field is not present in the CCID frame
+ * so do not copy */
+ continue;
+
+ /* copy the CCID block 'verbatim' */
+ cmd[a] = TxBuffer[b];
+ a++;
+ }
+
+ /* SPR532 and Case 1 APDU */
+ if ((SPR532 == ccid_descriptor->readerID)
+ /* bmPINBlockString = 0 => PIN length not inserted in APDU */
+ && (0 == TxBuffer[3])
+ /* case 1 APDU */
+ && (4 == TxBuffer[15]))
+ {
+ RESPONSECODE return_value;
+ unsigned char cmd_tmp[] = { 0x80, 0x02, 0x00 };
+ unsigned char res_tmp[1];
+ unsigned int res_length = sizeof(res_tmp);
+
+ /* the SPR532 will append the PIN code without any padding */
+ return_value = CmdEscape(reader_index, cmd_tmp, sizeof(cmd_tmp),
+ res_tmp, &res_length, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* we need to set bSeq again to avoid a "Duplicate frame detected"
+ * error since the bSeq of CmdEscape is now greater than bSeq set at
+ * the beginning of this function */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ }
+
+ i2dw(a - 10, cmd + 1); /* CCID message length */
+
+ old_read_timeout = ccid_descriptor -> readTimeout;
+ ccid_descriptor -> readTimeout = max(90, TxBuffer[0]+10)*1000; /* at least 90 seconds */
+
+ res = WritePort(reader_index, a, cmd);
+ if (STATUS_SUCCESS != res)
+ {
+ if (STATUS_NO_SUCH_DEVICE == res)
+ ret = IFD_NO_SUCH_DEVICE;
+ else
+ ret = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ /* timeout and cancel cases are faked by CCID_Receive() */
+ if ((2 == *RxLength)
+ /* the CCID command is rejected or failed */
+ || (IFD_SUCCESS != ret))
+ {
+ /* Decrement the sequence numbers since no TPDU was sent */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+ }
+ else
+ {
+ /* FIXME: manage T=1 error blocks */
+
+ /* defines from openct/proto-t1.c */
+ #define PCB 1
+ #define DATA 3
+ #define T1_S_BLOCK 0xC0
+ #define T1_S_RESPONSE 0x20
+ #define T1_S_TYPE(pcb) ((pcb) & 0x0F)
+ #define T1_S_WTX 0x03
+
+ /* WTX S-block */
+ if ((T1_S_BLOCK | T1_S_WTX) == RxBuffer[PCB])
+ {
+/*
+ * The Swiss health care card sends a WTX request before returning the
+ * SW code. If the reader is in TPDU the driver must manage the request
+ * itself.
+ *
+ * received: 00 C3 01 09 CB
+ * openct/proto-t1.c:432:t1_transceive() S-Block request received
+ * openct/proto-t1.c:489:t1_transceive() CT sent S-block with wtx=9
+ * sending: 00 E3 01 09 EB
+ * openct/proto-t1.c:667:t1_xcv() New timeout at WTX request: 23643 sec
+ * received: 00 40 02 90 00 D2
+*/
+ ct_buf_t tbuf;
+ unsigned char sblk[1]; /* we only need 1 byte of data */
+ t1_state_t *t1 = &get_ccid_slot(reader_index)->t1;
+ unsigned int slen;
+ int oldReadTimeout;
+
+ DEBUG_COMM2("CT sent S-block with wtx=%u", RxBuffer[DATA]);
+ t1->wtx = RxBuffer[DATA];
+
+ oldReadTimeout = ccid_descriptor->readTimeout;
+ if (t1->wtx > 1)
+ {
+ /* set the new temporary timeout at WTX card request */
+ ccid_descriptor->readTimeout *= t1->wtx;
+ DEBUG_INFO2("New timeout at WTX request: %d sec",
+ ccid_descriptor->readTimeout);
+ }
+
+ ct_buf_init(&tbuf, sblk, sizeof(sblk));
+ t1->wtx = RxBuffer[DATA];
+ ct_buf_putc(&tbuf, RxBuffer[DATA]);
+
+ slen = t1_build(t1, RxBuffer, 0,
+ T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(RxBuffer[PCB]),
+ &tbuf, NULL);
+
+ ret = CCID_Transmit(t1 -> lun, slen, RxBuffer, 0, t1->wtx);
+ if (ret != IFD_SUCCESS)
+ return ret;
+
+ /* I guess we have at least 6 bytes in RxBuffer */
+ *RxLength = 6;
+ ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
+ if (ret != IFD_SUCCESS)
+ return ret;
+
+ /* Restore initial timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+ }
+
+ /* get only the T=1 data */
+ memmove(RxBuffer, RxBuffer+3, *RxLength -4);
+ *RxLength -= 4; /* remove NAD, PCB, LEN and CRC */
+ }
+ }
+
+end:
+ ccid_descriptor -> readTimeout = old_read_timeout;
+ return ret;
+} /* SecurePINVerify */
+
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+/*****************************************************************************
+ *
+ * has_gemalto_modify_pin_bug
+ *
+ ****************************************************************************/
+static int has_gemalto_modify_pin_bug(_ccid_descriptor *ccid_descriptor)
+{
+ /* Bug not present by default */
+ int has_bug = 0;
+
+ /* Covadis Véga-Alpha reader */
+ if (VEGAALPHA == ccid_descriptor->readerID)
+ {
+ /* This reader has the bug (uses a Gemalto firmware) */
+ has_bug = 1;
+ }
+ else
+ {
+ /* Gemalto reader */
+ if ((GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO))
+ {
+ has_bug = 1; /* assume it has the bug */
+
+ if (ccid_descriptor->gemalto_firmware_features &&
+ ccid_descriptor->gemalto_firmware_features->bNumberMessageFix)
+ {
+ /* A Gemalto reader has the ModifyPIN structure bug */
+ /* unless it explicitly reports it has been fixed */
+ has_bug = 0;
+ }
+ }
+ }
+
+ return has_bug;
+} /* has_gemalto_modify_pin_bug */
+#endif
+
+/*****************************************************************************
+ *
+ * SecurePINModify
+ *
+ ****************************************************************************/
+RESPONSECODE SecurePINModify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength)
+{
+ unsigned char cmd[11+19+TxLength];
+ unsigned int a, b;
+ PIN_MODIFY_STRUCTURE *pms;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ int old_read_timeout;
+ RESPONSECODE ret;
+ status_t res;
+#ifdef BOGUS_PINPAD_FIRMWARE
+ int bNumberMessage = 0; /* for GemPC Pinpad */
+ int gemalto_modify_pin_bug;
+#endif
+
+ pms = (PIN_MODIFY_STRUCTURE *)TxBuffer;
+ cmd[0] = 0x69; /* Secure */
+ 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] = 1; /* bPINOperation: PIN Modification */
+
+ if (TxLength < 24+4 /* 4 = APDU size */) /* command too short? */
+ {
+ DEBUG_INFO3("Command too short: %d < %d", TxLength, 24+4);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* On little endian machines we are all set. */
+ /* If on big endian machine and caller is using host byte order */
+ if ((pms->ulDataLength + 24 == TxLength) &&
+ (bei2i((unsigned char*)(&pms->ulDataLength)) == pms->ulDataLength))
+ {
+ DEBUG_INFO1("Reversing order from big to little endian");
+ /* If ulDataLength is big endian, assume others are too */
+ /* reverse the byte order for 3 fields */
+ pms->wPINMaxExtraDigit = BSWAP_16(pms->wPINMaxExtraDigit);
+ pms->wLangId = BSWAP_16(pms->wLangId);
+ pms->ulDataLength = BSWAP_32(pms->ulDataLength);
+ }
+ /* At this point we now have the above 3 variables in little endian */
+
+
+ if (dw2i(TxBuffer, 20) + 24 != TxLength) /* ulDataLength field coherency */
+ {
+ DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 20) + 24, TxLength);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* Make sure in the beginning if bNumberMessage is valid or not.
+ * 0xFF is the default value. */
+ if ((TxBuffer[11] > 3) && (TxBuffer[11] != 0xFF))
+ {
+ DEBUG_INFO2("Wrong bNumberMessage: %d", TxBuffer[11]);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* Make sure bEntryValidationCondition is valid
+ * The Cherry XX44 reader crashes with a wrong value */
+ if ((0x00 == TxBuffer[10]) || (TxBuffer[10] > 0x07))
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition (was 0x%02X)",
+ TxBuffer[10]);
+ TxBuffer[10] = 0x02;
+ }
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+ /* some firmwares are buggy so we try to "correct" the frame */
+ /*
+ * SPR 532 and Cherry ST 2000C has no display but requires _all_
+ * bMsgIndex fields with bNumberMessage set to 0.
+ */
+ if ((SPR532 == ccid_descriptor->readerID)
+ || (CHERRYST2000 == ccid_descriptor->readerID))
+ {
+ TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that
+ all bMsgIndex123 are filled */
+ TxBuffer[14] = TxBuffer[15] = TxBuffer[16] = 0; /* bMsgIndex123 */
+ }
+
+ /* the bug is a bit different than for the Cherry ST 2000C
+ * with bNumberMessage < 3 the command seems to be accepted
+ * and the card sends 6B 80 */
+ if (CHERRYXX44 == ccid_descriptor->readerID)
+ {
+ TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that
+ all bMsgIndex123 are filled */
+ }
+
+ /* bug circumvention for the GemPC Pinpad */
+ if ((GEMPCPINPAD == ccid_descriptor->readerID)
+ || (VEGAALPHA == ccid_descriptor->readerID))
+ {
+ /* The reader does not support, and actively reject, "max size reached"
+ * and "timeout occured" validation conditions */
+ if (0x02 != TxBuffer[10])
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
+ TxBuffer[10]);
+ TxBuffer[10] = 0x02; /* validation key pressed */
+ }
+ }
+
+ gemalto_modify_pin_bug = has_gemalto_modify_pin_bug(ccid_descriptor);
+ if (gemalto_modify_pin_bug)
+ {
+ DEBUG_INFO1("Gemalto CCID Modify Pin Bug");
+
+ /* The reader requests a value for bMsgIndex2 and bMsgIndex3
+ * even if they should not be present. So we fake
+ * bNumberMessage=3. The real number of messages will be
+ * corrected later in the code */
+ bNumberMessage = TxBuffer[11];
+ if (0x03 != TxBuffer[11])
+ {
+ DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
+ TxBuffer[11]);
+ TxBuffer[11] = 0x03; /* 3 messages */
+ }
+ }
+#endif
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ ct_buf_t sbuf;
+ unsigned char sdata[T1_BUFFER_SIZE];
+
+ /* Initialize send buffer with the APDU */
+ ct_buf_set(&sbuf,
+ (void *)(TxBuffer + offsetof(PIN_MODIFY_STRUCTURE, abData)),
+ TxLength - offsetof(PIN_MODIFY_STRUCTURE, abData));
+
+ /* Create T=1 block */
+ (void)t1_build(&((get_ccid_slot(reader_index))->t1),
+ sdata, 0, T1_I_BLOCK, &sbuf, NULL);
+
+ /* Increment the sequence numbers */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+
+ /* Copy the generated T=1 block prologue into the teoprologue
+ * of the CCID command */
+ memcpy(TxBuffer + offsetof(PIN_MODIFY_STRUCTURE, bTeoPrologue),
+ sdata, 3);
+ }
+
+ /* Build a CCID block from a PC/SC V2.02.05 Part 10 block */
+
+ /* Do adjustments as needed - CCID spec is not exact with some
+ * details in the format of the structure, per-reader adaptions
+ * might be needed.
+ */
+ for (a = 11, b = 0; b < TxLength; b++)
+ {
+ if (1 == b) /* bTimeOut2 */
+ /* Ignore the second timeout as there's nothing we can do with it
+ * currently */
+ continue;
+
+ if (15 == b) /* bMsgIndex2 */
+ {
+ /* in CCID the bMsgIndex2 is present only if bNumberMessage != 0 */
+ if (0 == TxBuffer[11])
+ continue;
+ }
+
+ if (16 == b) /* bMsgIndex3 */
+ {
+ /* in CCID the bMsgIndex3 is present only if bNumberMessage == 3 */
+ if (TxBuffer[11] < 3)
+ continue;
+ }
+
+ if ((b >= 20) && (b <= 23)) /* ulDataLength field (4 bytes) */
+ /* the ulDataLength field is not present in the CCID frame
+ * so do not copy */
+ continue;
+
+ /* copy to the CCID block 'verbatim' */
+ cmd[a] = TxBuffer[b];
+ a++;
+ }
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+ if ((SPR532 == ccid_descriptor->readerID)
+ || (CHERRYST2000 == ccid_descriptor->readerID))
+ {
+ cmd[21] = 0x00; /* set bNumberMessage to 0 */
+ }
+
+ if (gemalto_modify_pin_bug)
+ cmd[21] = bNumberMessage; /* restore the real value */
+#endif
+
+ /* We know the size of the CCID message now */
+ i2dw(a - 10, cmd + 1); /* command length (includes bPINOperation) */
+
+ old_read_timeout = ccid_descriptor -> readTimeout;
+ ccid_descriptor -> readTimeout = max(90, TxBuffer[0]+10)*1000; /* at least 90 seconds */
+
+ res = WritePort(reader_index, a, cmd);
+ if (STATUS_SUCCESS != res)
+ {
+ if (STATUS_NO_SUCH_DEVICE == res)
+ ret = IFD_NO_SUCH_DEVICE;
+ else
+ ret = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ /* timeout and cancel cases are faked by CCID_Receive() */
+ if ((2 == *RxLength)
+ /* the CCID command is rejected or failed */
+ || (IFD_SUCCESS != ret))
+ {
+ /* Decrement the sequence numbers since no TPDU was sent */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+ }
+ else
+ {
+ /* get only the T=1 data */
+ /* FIXME: manage T=1 error blocks */
+ memmove(RxBuffer, RxBuffer+3, *RxLength -4);
+ *RxLength -= 4; /* remove NAD, PCB, LEN and CRC */
+ }
+ }
+
+end:
+ ccid_descriptor -> readTimeout = old_read_timeout;
+ return ret;
+} /* SecurePINModify */
+
+
+/*****************************************************************************
+ *
+ * Escape
+ *
+ ****************************************************************************/
+RESPONSECODE CmdEscape(unsigned int reader_index,
+ const unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout)
+{
+ unsigned char *cmd_in, *cmd_out;
+ status_t res;
+ unsigned int length_in, length_out;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ int old_read_timeout;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ /* a value of 0 do not change the default read timeout */
+ if (timeout > 0)
+ {
+ old_read_timeout = ccid_descriptor -> readTimeout;
+ ccid_descriptor -> readTimeout = timeout;
+ }
+
+again:
+ /* allocate buffers */
+ length_in = 10 + TxLength;
+ if (NULL == (cmd_in = malloc(length_in)))
+ {
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ length_out = 10 + *RxLength;
+ if (NULL == (cmd_out = malloc(length_out)))
+ {
+ free(cmd_in);
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ cmd_in[0] = 0x6B; /* PC_to_RDR_Escape */
+ i2dw(length_in - 10, cmd_in+1); /* dwLength */
+ cmd_in[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd_in[6] = (*ccid_descriptor->pbSeq)++;
+ cmd_in[7] = cmd_in[8] = cmd_in[9] = 0; /* RFU */
+
+ /* copy the command */
+ memcpy(&cmd_in[10], TxBuffer, TxLength);
+
+ res = WritePort(reader_index, length_in, cmd_in);
+ free(cmd_in);
+ if (res != STATUS_SUCCESS)
+ {
+ free(cmd_out);
+ if (STATUS_NO_SUCH_DEVICE == res)
+ return_value = IFD_NO_SUCH_DEVICE;
+ else
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+time_request:
+ length_out = 10 + *RxLength;
+ res = ReadPort(reader_index, &length_out, cmd_out);
+
+ /* replay the command if NAK
+ * This (generally) happens only for the first command sent to the reader
+ * with the serial protocol so it is not really needed for all the other
+ * ReadPort() calls */
+ if (STATUS_COMM_NAK == res)
+ {
+ free(cmd_out);
+ goto again;
+ }
+
+ if (res != STATUS_SUCCESS)
+ {
+ free(cmd_out);
+ if (STATUS_NO_SUCH_DEVICE == res)
+ return_value = IFD_NO_SUCH_DEVICE;
+ else
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ if (length_out < STATUS_OFFSET+1)
+ {
+ free(cmd_out);
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length_out);
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ if (cmd_out[STATUS_OFFSET] & CCID_TIME_EXTENSION)
+ {
+ DEBUG_COMM2("Time extension requested: 0x%02X", cmd_out[ERROR_OFFSET]);
+ goto time_request;
+ }
+
+ if (cmd_out[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(cmd_out[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ /* copy the response */
+ length_out = dw2i(cmd_out, 1);
+ if (length_out > *RxLength)
+ length_out = *RxLength;
+ *RxLength = length_out;
+ memcpy(RxBuffer, &cmd_out[10], length_out);
+
+ free(cmd_out);
+
+end:
+ if (timeout > 0)
+ ccid_descriptor -> readTimeout = old_read_timeout;
+
+ return return_value;
+} /* Escape */
+
+
+/*****************************************************************************
+ *
+ * CmdPowerOff
+ *
+ ****************************************************************************/
+RESPONSECODE CmdPowerOff(unsigned int reader_index)
+{
+ unsigned char cmd[10];
+ status_t res;
+ unsigned int length;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* PowerOff */
+ r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char buffer[3];
+
+ /* PowerOff */
+ r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer, sizeof(buffer));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC SlotStatus failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ cmd[0] = 0x63; /* IccPowerOff */
+ cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
+
+ res = WritePort(reader_index, sizeof(cmd), cmd);
+ CHECK_STATUS(res)
+
+ length = sizeof(cmd);
+ res = ReadPort(reader_index, &length, cmd);
+ CHECK_STATUS(res)
+
+ 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_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ return return_value;
+} /* CmdPowerOff */
+
+
+/*****************************************************************************
+ *
+ * CmdGetSlotStatus
+ *
+ ****************************************************************************/
+RESPONSECODE CmdGetSlotStatus(unsigned int reader_index, unsigned char buffer[])
+{
+ unsigned char cmd[10];
+ status_t res;
+ unsigned int length;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char status[1];
+
+again_status:
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0xA0, 0, status, sizeof(status));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
+ if (ENODEV == errno)
+ return IFD_NO_SUCH_DEVICE;
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* busy */
+ if (status[0] & 0x40)
+ {
+ DEBUG_INFO2("Busy: 0x%02X", status[0]);
+ (void)usleep(1000 * 10);
+ goto again_status;
+ }
+
+ /* simulate a CCID bStatus */
+ /* present and active by default */
+ buffer[7] = CCID_ICC_PRESENT_ACTIVE;
+
+ /* mute */
+ if (0x80 == status[0])
+ buffer[7] = CCID_ICC_ABSENT;
+
+ /* store the status for CmdXfrBlockCHAR_T0() */
+ buffer[0] = status[0];
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char buffer_tmp[3];
+
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer_tmp,
+ sizeof(buffer_tmp));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
+ if (ENODEV == errno)
+ return IFD_NO_SUCH_DEVICE;
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* simulate a CCID bStatus */
+ switch (buffer_tmp[1] & 0x03)
+ {
+ case 0:
+ buffer[7] = CCID_ICC_PRESENT_ACTIVE;
+ break;
+ case 1:
+ buffer[7] = CCID_ICC_PRESENT_INACTIVE;
+ break;
+ case 2:
+ case 3:
+ buffer[7] = CCID_ICC_ABSENT;
+ }
+ return IFD_SUCCESS;
+ }
+#endif
+
+ cmd[0] = 0x65; /* GetSlotStatus */
+ cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
+
+ res = WritePort(reader_index, sizeof(cmd), cmd);
+ CHECK_STATUS(res)
+
+ length = SIZE_GET_SLOT_STATUS;
+ res = ReadPort(reader_index, &length, buffer);
+ CHECK_STATUS(res)
+
+ if (length < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if ((buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ /* card absent or mute is not an communication error */
+ && (buffer[ERROR_OFFSET] != 0xFE))
+ {
+ return_value = IFD_COMMUNICATION_ERROR;
+ ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ }
+
+ return return_value;
+} /* CmdGetSlotStatus */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlock
+ *
+ ****************************************************************************/
+RESPONSECODE CmdXfrBlock(unsigned int reader_index, unsigned int tx_length,
+ unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[], int protocol)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ /* APDU or TPDU? */
+ switch (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)
+ {
+ case CCID_CLASS_TPDU:
+ if (protocol == T_0)
+ return_value = CmdXfrBlockTPDU_T0(reader_index,
+ tx_length, tx_buffer, rx_length, rx_buffer);
+ else
+ if (protocol == T_1)
+ return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ return_value = IFD_PROTOCOL_NOT_SUPPORTED;
+ break;
+
+ case CCID_CLASS_SHORT_APDU:
+ return_value = CmdXfrBlockTPDU_T0(reader_index,
+ tx_length, tx_buffer, rx_length, rx_buffer);
+ break;
+
+ case CCID_CLASS_EXTENDED_APDU:
+ return_value = CmdXfrBlockAPDU_extended(reader_index,
+ tx_length, tx_buffer, rx_length, rx_buffer);
+ break;
+
+ case CCID_CLASS_CHARACTER:
+ if (protocol == T_0)
+ return_value = CmdXfrBlockCHAR_T0(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ if (protocol == T_1)
+ return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ return_value = IFD_PROTOCOL_NOT_SUPPORTED;
+ break;
+
+ default:
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ return return_value;
+} /* CmdXfrBlock */
+
+
+/*****************************************************************************
+ *
+ * CCID_Transmit
+ *
+ ****************************************************************************/
+RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
+ const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI)
+{
+ unsigned char cmd[10+tx_length]; /* CCID + APDU buffer */
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ status_t ret;
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* Xfr Block */
+ r = ControlUSB(reader_index, 0x21, 0x65, 0,
+ (unsigned char *)tx_buffer, tx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* nul block so we are chaining */
+ if (NULL == tx_buffer)
+ rx_length = 0x10; /* bLevelParameter */
+
+ /* Xfr Block */
+ DEBUG_COMM2("chain parameter: %d", rx_length);
+ r = ControlUSB(reader_index, 0x21, 0x65, rx_length << 8,
+ (unsigned char *)tx_buffer, tx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ cmd[0] = 0x6F; /* XfrBlock */
+ i2dw(tx_length, cmd+1); /* APDU length */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = bBWI; /* extend block waiting timeout */
+ cmd[8] = rx_length & 0xFF; /* Expected length, in character mode only */
+ cmd[9] = (rx_length >> 8) & 0xFF;
+
+ memcpy(cmd+10, tx_buffer, tx_length);
+
+ ret = WritePort(reader_index, 10+tx_length, cmd);
+ CHECK_STATUS(ret)
+
+ return IFD_SUCCESS;
+} /* CCID_Transmit */
+
+
+/*****************************************************************************
+ *
+ * CCID_Receive
+ *
+ ****************************************************************************/
+RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
+ unsigned char rx_buffer[], unsigned char *chain_parameter)
+{
+ unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
+ unsigned int length;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ status_t ret;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ unsigned int old_timeout;
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ int r;
+
+ /* wait for ready */
+ r = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* we need to store returned value */
+ *rx_length = r;
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char rx_tmp[4];
+ unsigned char *old_rx_buffer = NULL;
+ int old_rx_length = 0;
+
+ /* read a nul block. buffer need to be at least 4-bytes */
+ if (NULL == rx_buffer)
+ {
+ rx_buffer = rx_tmp;
+ *rx_length = sizeof(rx_tmp);
+ }
+
+ /* the buffer must be 4 bytes minimum for ICCD-B */
+ if (*rx_length < 4)
+ {
+ old_rx_buffer = rx_buffer;
+ old_rx_length = *rx_length;
+ rx_buffer = rx_tmp;
+ *rx_length = sizeof(rx_tmp);
+ }
+
+time_request_ICCD_B:
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* copy from the 4 bytes buffer if used */
+ if (old_rx_buffer)
+ {
+ memcpy(old_rx_buffer, rx_buffer, min(r, old_rx_length));
+ rx_buffer = old_rx_buffer;
+ }
+
+ /* bResponseType */
+ switch (rx_buffer[0])
+ {
+ case 0x00:
+ /* the abData field contains the information created by the
+ * preceding request */
+ break;
+
+ case 0x40:
+ /* Status Information */
+ ccid_error(rx_buffer[2], __FILE__, __LINE__, __FUNCTION__);
+ return IFD_COMMUNICATION_ERROR;
+
+ case 0x80:
+ /* Polling */
+ {
+ int delay;
+
+ delay = (rx_buffer[2] << 8) + rx_buffer[1];
+ DEBUG_COMM2("Pooling delay: %d", delay);
+
+ if (0 == delay)
+ /* host select the delay */
+ delay = 1;
+ (void)usleep(delay * 1000 * 10);
+ goto time_request_ICCD_B;
+ }
+
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x10:
+ /* Extended case
+ * Only valid for Data Block frames */
+ if (chain_parameter)
+ *chain_parameter = rx_buffer[0];
+ break;
+
+ default:
+ DEBUG_CRITICAL2("Unknown bResponseType: 0x%02X", rx_buffer[0]);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ memmove(rx_buffer, rx_buffer+1, r-1);
+ *rx_length = r-1;
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ /* store the original value of read timeout*/
+ old_timeout = ccid_descriptor -> readTimeout;
+
+time_request:
+ length = sizeof(cmd);
+ ret = ReadPort(reader_index, &length, cmd);
+
+ /* restore the original value of read timeout */
+ ccid_descriptor -> readTimeout = old_timeout;
+ CHECK_STATUS(ret)
+
+ 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 */
+ switch (cmd[ERROR_OFFSET])
+ {
+ case 0xEF: /* cancel */
+ if (*rx_length < 2)
+ return IFD_COMMUNICATION_ERROR;
+ rx_buffer[0]= 0x64;
+ rx_buffer[1]= 0x01;
+ *rx_length = 2;
+ return IFD_SUCCESS;
+
+ case 0xF0: /* timeout */
+ if (*rx_length < 2)
+ return IFD_COMMUNICATION_ERROR;
+ rx_buffer[0]= 0x64;
+ rx_buffer[1]= 0x00;
+ *rx_length = 2;
+ return IFD_SUCCESS;
+
+ case 0xFD: /* Parity error during exchange */
+ return IFD_PARITY_ERROR;
+
+ default:
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+
+ if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
+ {
+ DEBUG_COMM2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
+
+ /* compute the new value of read timeout */
+ if (cmd[ERROR_OFFSET] > 0)
+ ccid_descriptor -> readTimeout *= cmd[ERROR_OFFSET];
+
+ DEBUG_COMM2("New timeout: %d ms", ccid_descriptor -> readTimeout);
+ goto time_request;
+ }
+
+ /* 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_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ length = dw2i(cmd, 1);
+ if (length <= *rx_length)
+ *rx_length = length;
+ else
+ {
+ DEBUG_CRITICAL2("overrun by %d bytes", length - *rx_length);
+ length = *rx_length;
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ /* Kobil firmware bug. No support for chaining */
+ if (length && (NULL == rx_buffer))
+ {
+ DEBUG_CRITICAL2("Nul block expected but got %d bytes", length);
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ memcpy(rx_buffer, cmd+10, length);
+
+ /* Extended case?
+ * Only valid for RDR_to_PC_DataBlock frames */
+ if (chain_parameter)
+ *chain_parameter = cmd[CHAIN_PARAMETER_OFFSET];
+
+ return return_value;
+} /* CCID_Receive */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockAPDU_extended
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[])
+{
+ RESPONSECODE return_value;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ unsigned char chain_parameter;
+ unsigned int local_tx_length, sent_length;
+ unsigned int local_rx_length = 0, received_length;
+ int buffer_overflow = 0;
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ /* length is on 16-bits only
+ * if a size > 0x1000 is used then usb_control_msg() fails with
+ * "Invalid argument" */
+ if (*rx_length > 0x1000)
+ *rx_length = 0x1000;
+ }
+
+ DEBUG_COMM2("T=0 (extended): %d bytes", tx_length);
+
+ /* send the APDU */
+ sent_length = 0;
+
+ /* we suppose one command is enough */
+ chain_parameter = 0x00;
+
+ local_tx_length = tx_length - sent_length;
+ if (local_tx_length > CMD_BUF_SIZE)
+ {
+ local_tx_length = CMD_BUF_SIZE;
+ /* the command APDU begins with this command, and continue in the next
+ * PC_to_RDR_XfrBlock */
+ chain_parameter = 0x01;
+ }
+ if (local_tx_length > ccid_descriptor->dwMaxCCIDMessageLength-10)
+ {
+ local_tx_length = ccid_descriptor->dwMaxCCIDMessageLength-10;
+ chain_parameter = 0x01;
+ }
+
+send_next_block:
+ return_value = CCID_Transmit(reader_index, local_tx_length, tx_buffer,
+ chain_parameter, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ sent_length += local_tx_length;
+ tx_buffer += local_tx_length;
+
+ /* we just sent the last block (0x02) or only one block was needded (0x00) */
+ if ((0x02 == chain_parameter) || (0x00 == chain_parameter))
+ goto receive_block;
+
+ /* read a nul block */
+ return_value = CCID_Receive(reader_index, &local_rx_length, NULL, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* size of the next block */
+ if (tx_length - sent_length > local_tx_length)
+ {
+ /* the abData field continues a command APDU and
+ * another block is to follow */
+ chain_parameter = 0x03;
+ }
+ else
+ {
+ /* this abData field continues a command APDU and ends
+ * the APDU command */
+ chain_parameter = 0x02;
+
+ /* last (smaller) block */
+ local_tx_length = tx_length - sent_length;
+ }
+
+ goto send_next_block;
+
+receive_block:
+ /* receive the APDU */
+ received_length = 0;
+
+receive_next_block:
+ local_rx_length = *rx_length - received_length;
+ return_value = CCID_Receive(reader_index, &local_rx_length, rx_buffer,
+ &chain_parameter);
+ if (IFD_ERROR_INSUFFICIENT_BUFFER == return_value)
+ {
+ buffer_overflow = 1;
+
+ /* we continue to read all the response APDU */
+ return_value = IFD_SUCCESS;
+ }
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* advance in the reiceiving buffer */
+ rx_buffer += local_rx_length;
+ received_length += local_rx_length;
+
+ switch (chain_parameter)
+ {
+ /* the response APDU begins and ends in this command */
+ case 0x00:
+ /* this abData field continues the response APDU and ends the response
+ * APDU */
+ case 0x02:
+ break;
+
+ /* the response APDU begins with this command and is to continue */
+ case 0x01:
+ /* this abData field continues the response APDU and another block is
+ * to follow */
+ case 0x03:
+ /* empty abData field, continuation of the command APDU is expected in
+ * next PC_to_RDR_XfrBlock command */
+ case 0x10:
+ /* send a nul block */
+ /* set wLevelParameter to 0010h: empty abData field,
+ * continuation of response APDU is
+ * expected in the next RDR_to_PC_DataBlock. */
+ return_value = CCID_Transmit(reader_index, 0, NULL, 0x10, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ goto receive_next_block;
+ }
+
+ *rx_length = received_length;
+
+ /* generate an overflow detected by pcscd */
+ if (buffer_overflow)
+ (*rx_length)++;
+
+ return IFD_SUCCESS;
+} /* CmdXfrBlockAPDU_extended */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockTPDU_T0
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[])
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ DEBUG_COMM2("T=0: %d bytes", tx_length);
+
+ /* command length too big for CCID reader? */
+ if (tx_length > ccid_descriptor->dwMaxCCIDMessageLength-10)
+ {
+#ifdef BOGUS_SCM_FIRMWARE_FOR_dwMaxCCIDMessageLength
+ if (263 == ccid_descriptor->dwMaxCCIDMessageLength)
+ {
+ DEBUG_INFO3("Command too long (%d bytes) for max: %d bytes."
+ " SCM reader with bogus firmware?",
+ tx_length, ccid_descriptor->dwMaxCCIDMessageLength-10);
+ }
+ else
+#endif
+ {
+ DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
+ tx_length, ccid_descriptor->dwMaxCCIDMessageLength-10);
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+
+ /* command length too big for CCID driver? */
+ if (tx_length > CMD_BUF_SIZE)
+ {
+ DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
+ tx_length, CMD_BUF_SIZE);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return_value = CCID_Transmit(reader_index, tx_length, tx_buffer, 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return CCID_Receive(reader_index, rx_length, rx_buffer, NULL);
+} /* CmdXfrBlockTPDU_T0 */
+
+
+/*****************************************************************************
+ *
+ * T0CmdParsing
+ *
+ ****************************************************************************/
+static RESPONSECODE T0CmdParsing(unsigned char *cmd, unsigned int cmd_len,
+ /*@out@*/ unsigned int *exp_len)
+{
+ *exp_len = 0;
+
+ /* Ref: 7816-4 Annex A */
+ switch (cmd_len)
+ {
+ case 4: /* Case 1 */
+ *exp_len = 2; /* SW1 and SW2 only */
+ break;
+
+ case 5: /* Case 2 */
+ if (cmd[4] != 0)
+ *exp_len = cmd[4] + 2;
+ else
+ *exp_len = 256 + 2;
+ break;
+
+ default: /* Case 3 */
+ if (cmd_len > 5 && cmd_len == (unsigned int)(cmd[4] + 5))
+ *exp_len = 2; /* SW1 and SW2 only */
+ else
+ return IFD_COMMUNICATION_ERROR; /* situation not supported */
+ break;
+ }
+
+ return IFD_SUCCESS;
+} /* T0CmdParsing */
+
+
+/*****************************************************************************
+ *
+ * T0ProcACK
+ *
+ ****************************************************************************/
+static RESPONSECODE T0ProcACK(unsigned int reader_index,
+ unsigned char **snd_buf, unsigned int *snd_len,
+ unsigned char **rcv_buf, unsigned int *rcv_len,
+ unsigned char **in_buf, unsigned int *in_len,
+ unsigned int proc_len, int is_rcv)
+{
+ RESPONSECODE return_value;
+ unsigned int ret_len;
+
+ DEBUG_COMM2("Enter, is_rcv = %d", is_rcv);
+
+ if (is_rcv == 1)
+ { /* Receiving mode */
+ unsigned int remain_len;
+ unsigned char tmp_buf[512];
+
+ if (*in_len > 0)
+ { /* There are still available data in our buffer */
+ if (*in_len >= proc_len)
+ {
+ /* We only need to get the data from our buffer */
+ memcpy(*rcv_buf, *in_buf, proc_len);
+ *rcv_buf += proc_len;
+ *in_buf += proc_len;
+ *rcv_len += proc_len;
+ *in_len -= proc_len;
+
+ return IFD_SUCCESS;
+ }
+ else
+ {
+ /* Move all data in the input buffer to the reply buffer */
+ remain_len = proc_len - *in_len;
+ memcpy(*rcv_buf, *in_buf, *in_len);
+ *rcv_buf += *in_len;
+ *in_buf += *in_len;
+ *rcv_len += *in_len;
+ *in_len = 0;
+ }
+ }
+ else
+ /* There is no data in our tmp_buf,
+ * we have to read all data we needed */
+ remain_len = proc_len;
+
+ /* Read the expected data from the smartcard */
+ if (*in_len != 0)
+ {
+ DEBUG_CRITICAL("*in_len != 0");
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ memset(tmp_buf, 0, sizeof(tmp_buf));
+
+#ifdef O2MICRO_OZ776_PATCH
+ if((0 != remain_len) && (0 == (remain_len + 10) % 64))
+ {
+ /* special hack to avoid a command of size modulo 64
+ * we send two commands instead */
+ ret_len = 1;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ return_value = CCID_Receive(reader_index, &ret_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ ret_len = remain_len - 1;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ return_value = CCID_Receive(reader_index, &ret_len, &tmp_buf[1],
+ NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ ret_len += 1;
+ }
+ else
+#endif
+ {
+ ret_len = remain_len;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return_value = CCID_Receive(reader_index, &ret_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ memcpy(*rcv_buf, tmp_buf, remain_len);
+ *rcv_buf += remain_len, *rcv_len += remain_len;
+
+ /* If ret_len != remain_len, our logic is erroneous */
+ if (ret_len != remain_len)
+ {
+ DEBUG_CRITICAL("ret_len != remain_len");
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+ else
+ { /* Sending mode */
+
+ return_value = CCID_Transmit(reader_index, proc_len, *snd_buf, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ *snd_len -= proc_len;
+ *snd_buf += proc_len;
+ }
+
+ DEBUG_COMM("Exit");
+
+ return IFD_SUCCESS;
+} /* T0ProcACK */
+
+
+/*****************************************************************************
+ *
+ * T0ProcSW1
+ *
+ ****************************************************************************/
+static RESPONSECODE T0ProcSW1(unsigned int reader_index,
+ unsigned char *rcv_buf, unsigned int *rcv_len,
+ unsigned char *in_buf, unsigned int in_len)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ UCHAR tmp_buf[512];
+ unsigned char sw1, sw2;
+
+ /* store the SW1 */
+ sw1 = *rcv_buf = *in_buf;
+ rcv_buf++;
+ in_buf++;
+ in_len--;
+ (*rcv_len)++;
+
+ /* store the SW2 */
+ if (0 == in_len)
+ {
+ return_value = CCID_Transmit(reader_index, 0, rcv_buf, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ in_len = 1;
+
+ return_value = CCID_Receive(reader_index, &in_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ in_buf = tmp_buf;
+ }
+ sw2 = *rcv_buf = *in_buf;
+ in_len--;
+ (*rcv_len)++;
+
+ DEBUG_COMM3("Exit: SW=%02X %02X", sw1, sw2);
+
+ return return_value;
+} /* T0ProcSW1 */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockCHAR_T0
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index,
+ unsigned int snd_len, unsigned char snd_buf[], unsigned int *rcv_len,
+ unsigned char rcv_buf[])
+{
+ int is_rcv;
+ unsigned char cmd[5];
+ unsigned char tmp_buf[512];
+ unsigned int exp_len, in_len;
+ unsigned char ins, *in_buf;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ DEBUG_COMM2("T=0: %d bytes", snd_len);
+
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ unsigned int backup_len;
+
+ /* length is on 16-bits only
+ * if a size > 0x1000 is used then usb_control_msg() fails with
+ * "Invalid argument" */
+ if (*rcv_len > 0x1000)
+ *rcv_len = 0x1000;
+
+ backup_len = *rcv_len;
+
+ /* Command to send to the smart card (must be 5 bytes) */
+ memset(cmd, 0, sizeof(cmd));
+ if (snd_len == 4)
+ {
+ memcpy(cmd, snd_buf, 4);
+ snd_buf += 4;
+ snd_len -= 4;
+ }
+ else
+ {
+ memcpy(cmd, snd_buf, 5);
+ snd_buf += 5;
+ snd_len -= 5;
+ }
+
+ /* at most 5 bytes */
+ return_value = CCID_Transmit(reader_index, 5, cmd, 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* wait for ready */
+ pcbuffer[0] = 0;
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ if (0x10 == pcbuffer[0])
+ {
+ if (snd_len > 0)
+ {
+ /* continue sending the APDU */
+ return_value = CCID_Transmit(reader_index, snd_len, snd_buf,
+ 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ else
+ {
+ /* read apdu data */
+ return_value = CCID_Receive(reader_index, rcv_len, rcv_buf,
+ NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ }
+
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* SW1-SW2 available */
+ if (0x20 == pcbuffer[0])
+ {
+ /* backup apdu data length */
+ /* if no data recieved before - backup length must be zero */
+ backup_len = (backup_len == *rcv_len) ? 0 : *rcv_len;
+
+ /* wait for 2 bytes (SW1-SW2) */
+ *rcv_len = 2;
+
+ return_value = CCID_Receive(reader_index, rcv_len,
+ rcv_buf + backup_len, NULL);
+ if (return_value != IFD_SUCCESS)
+ DEBUG_CRITICAL("CCID_Receive failed");
+
+ /* restore recieved length */
+ *rcv_len += backup_len;
+ }
+ return return_value;
+ }
+
+ in_buf = tmp_buf;
+ in_len = 0;
+ *rcv_len = 0;
+
+ return_value = T0CmdParsing(snd_buf, snd_len, &exp_len);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("T0CmdParsing failed");
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (snd_len == 5 || snd_len == 4)
+ is_rcv = 1;
+ else
+ is_rcv = 0;
+
+ /* Command to send to the smart card (must be 5 bytes, from 7816 p.15) */
+ memset(cmd, 0, sizeof(cmd));
+ if (snd_len == 4)
+ {
+ memcpy(cmd, snd_buf, 4);
+ snd_buf += 4;
+ snd_len -= 4;
+ }
+ else
+ {
+ memcpy(cmd, snd_buf, 5);
+ snd_buf += 5;
+ snd_len -= 5;
+ }
+
+ /* Make sure this is a valid command by checking the INS field */
+ ins = cmd[1];
+ if ((ins & 0xF0) == 0x60 || /* 7816-3 8.3.2 */
+ (ins & 0xF0) == 0x90)
+ {
+ DEBUG_CRITICAL2("fatal: INS (0x%02X) = 0x6X or 0x9X", ins);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return_value = CCID_Transmit(reader_index, 5, cmd, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ while (1)
+ {
+ if (in_len == 0)
+ {
+ in_len = 1;
+ return_value = CCID_Receive(reader_index, &in_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("CCID_Receive failed");
+ return return_value;
+ }
+ in_buf = tmp_buf;
+ }
+ if (in_len == 0)
+ {
+ /* Suppose we should be able to get data.
+ * If not, error. Set the time-out error */
+ DEBUG_CRITICAL("error: in_len = 0");
+ return IFD_RESPONSE_TIMEOUT;
+ }
+
+ /* Start to process the procedure bytes */
+ if (*in_buf == 0x60)
+ {
+ in_len = 0;
+ return_value = CCID_Transmit(reader_index, 0, cmd, 1, 0);
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ continue;
+ }
+ else if (*in_buf == ins || *in_buf == (ins ^ 0x01))
+ {
+ /* ACK => To transfer all remaining data bytes */
+ in_buf++, in_len--;
+ if (is_rcv)
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, exp_len - *rcv_len, 1);
+ else
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, snd_len, 0);
+
+ if (*rcv_len == exp_len)
+ return return_value;
+
+ continue;
+ }
+ else if (*in_buf == (ins ^ 0xFF) || *in_buf == (ins ^ 0xFE))
+ {
+ /* ACK => To transfer 1 remaining bytes */
+ in_buf++, in_len--;
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, 1, is_rcv);
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ continue;
+ }
+ else if ((*in_buf & 0xF0) == 0x60 || (*in_buf & 0xF0) == 0x90)
+ /* SW1 */
+ return T0ProcSW1(reader_index, rcv_buf, rcv_len, in_buf, in_len);
+
+ /* Error, unrecognized situation found */
+ DEBUG_CRITICAL2("Unrecognized Procedure byte (0x%02X) found!", *in_buf);
+ return return_value;
+ }
+
+ return return_value;
+} /* CmdXfrBlockCHAR_T0 */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockTPDU_T1
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[])
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ int ret;
+
+ DEBUG_COMM3("T=1: %d and %d bytes", tx_length, *rx_length);
+
+ ret = t1_transceive(&((get_ccid_slot(reader_index)) -> t1), 0,
+ tx_buffer, tx_length, rx_buffer, *rx_length);
+
+ if (ret < 0)
+ return_value = IFD_COMMUNICATION_ERROR;
+ else
+ *rx_length = ret;
+
+ return return_value;
+} /* CmdXfrBlockTPDU_T1 */
+
+
+/*****************************************************************************
+ *
+ * SetParameters
+ *
+ ****************************************************************************/
+RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
+ unsigned int length, unsigned char buffer[])
+{
+ unsigned char cmd[10+length]; /* CCID + APDU buffer */
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ status_t res;
+
+ DEBUG_COMM2("length: %d bytes", length);
+
+ cmd[0] = 0x61; /* SetParameters */
+ i2dw(length, cmd+1); /* APDU length */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = protocol; /* bProtocolNum */
+ cmd[8] = cmd[9] = 0; /* RFU */
+
+ memcpy(cmd+10, buffer, length);
+
+ res = WritePort(reader_index, 10+length, cmd);
+ CHECK_STATUS(res)
+
+ length = sizeof(cmd);
+ res = ReadPort(reader_index, &length, cmd);
+ CHECK_STATUS(res)
+
+ 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 */
+ if (0x00 == cmd[ERROR_OFFSET]) /* command not supported */
+ return IFD_NOT_SUPPORTED;
+ else
+ if ((cmd[ERROR_OFFSET] >= 1) && (cmd[ERROR_OFFSET] <= 127))
+ /* a parameter is not changeable */
+ return IFD_SUCCESS;
+ else
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+} /* SetParameters */
+
+
+/*****************************************************************************
+ *
+ * isCharLevel
+ *
+ ****************************************************************************/
+int isCharLevel(int reader_index)
+{
+ return CCID_CLASS_CHARACTER == (get_ccid_descriptor(reader_index)->dwFeatures & CCID_CLASS_EXCHANGE_MASK);
+} /* isCharLevel */
+
+
+/*****************************************************************************
+ *
+ * i2dw
+ *
+ ****************************************************************************/
+static void i2dw(int value, unsigned char buffer[])
+{
+ buffer[0] = value & 0xFF;
+ buffer[1] = (value >> 8) & 0xFF;
+ buffer[2] = (value >> 16) & 0xFF;
+ buffer[3] = (value >> 24) & 0xFF;
+} /* i2dw */
+
+/*****************************************************************************
+*
+* bei2i (big endian integer to host order interger)
+*
+****************************************************************************/
+
+static unsigned int bei2i(unsigned char buffer[])
+{
+ return (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
+}
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/commands.h b/MdeModulePkg/Library/SmartCardReader/libccid/commands.h
new file mode 100644
index 0000000..c082bf2
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/commands.h
@@ -0,0 +1,64 @@
+/*
+ commands.h: Commands sent to the card
+ Copyright (C) 2003-2009 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: commands.h 6783 2013-10-24 09:36:52Z rousseau $
+ */
+
+#define SIZE_GET_SLOT_STATUS 10
+#define STATUS_OFFSET 7
+#define ERROR_OFFSET 8
+#define CHAIN_PARAMETER_OFFSET 9
+
+RESPONSECODE CmdPowerOn(unsigned int reader_index, unsigned int * nlength,
+ /*@out@*/ unsigned char buffer[], int voltage);
+
+RESPONSECODE SecurePINVerify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength);
+
+RESPONSECODE SecurePINModify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength);
+
+RESPONSECODE CmdEscape(unsigned int reader_index,
+ const unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout);
+
+RESPONSECODE CmdPowerOff(unsigned int reader_index);
+
+RESPONSECODE CmdGetSlotStatus(unsigned int reader_index,
+ /*@out@*/ unsigned char buffer[]);
+
+RESPONSECODE CmdXfrBlock(unsigned int reader_index, unsigned int tx_length,
+ unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[], int protoccol);
+
+RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
+ const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI);
+
+RESPONSECODE CCID_Receive(unsigned int reader_index,
+ /*@out@*/ unsigned int *rx_length,
+ /*@out@*/ unsigned char rx_buffer[], unsigned char *chain_parameter);
+
+RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
+ unsigned int length, unsigned char buffer[]);
+
+int isCharLevel(int reader_index);
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/debug.c b/MdeModulePkg/Library/SmartCardReader/libccid/debug.c
new file mode 100644
index 0000000..3c8d8e5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/debug.c
@@ -0,0 +1,157 @@
+/*
+ debug.c: log (or not) messages
+ Copyright (C) 2003-2011 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: debug.c 6975 2014-09-04 11:33:05Z rousseau $
+ */
+
+
+#include <config.h>
+#include "misc.h"
+#include "debug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <stdlib.h>
+
+#include "strlcpycat.h"
+
+#undef LOG_TO_STDERR
+
+#ifdef LOG_TO_STDERR
+#define LOG_STREAM stderr
+#else
+#define LOG_STREAM stdout
+#endif
+
+void log_msg(const int priority, const char *fmt, ...)
+{
+ char debug_buffer[160]; /* up to 2 lines of 80 characters */
+ va_list argptr;
+ static struct timeval last_time = { 0, 0 };
+ struct timeval new_time = { 0, 0 };
+ struct timeval tmp;
+ int delta;
+ const char *color_pfx = "", *color_sfx = "";
+ const char *time_pfx = "", *time_sfx = "";
+ static int initialized = 0;
+ static int LogDoColor = 0;
+
+ if (!initialized)
+ {
+ char *term;
+
+ initialized = 1;
+ term = getenv("TERM");
+ if (term)
+ {
+ const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
+ unsigned int i;
+
+ /* for each known color terminal */
+ for (i = 0; i < COUNT_OF(terms); i++)
+ {
+ /* we found a supported term? */
+ if (0 == strcmp(terms[i], term))
+ {
+ LogDoColor = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (LogDoColor)
+ {
+ color_sfx = "\33[0m";
+ time_sfx = color_sfx;
+ time_pfx = "\33[36m"; /* Cyan */
+
+ switch (priority)
+ {
+ case PCSC_LOG_CRITICAL:
+ color_pfx = "\33[01;31m"; /* bright + Red */
+ break;
+
+ case PCSC_LOG_ERROR:
+ color_pfx = "\33[35m"; /* Magenta */
+ break;
+
+ case PCSC_LOG_INFO:
+ color_pfx = "\33[34m"; /* Blue */
+ break;
+
+ case PCSC_LOG_DEBUG:
+ color_pfx = ""; /* normal (black) */
+ color_sfx = "";
+ break;
+ }
+ }
+
+ gettimeofday(&new_time, NULL);
+ if (0 == last_time.tv_sec)
+ last_time = new_time;
+
+ tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
+ tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
+ if (tmp.tv_usec < 0)
+ {
+ tmp.tv_sec--;
+ tmp.tv_usec += 1000000;
+ }
+ if (tmp.tv_sec < 100)
+ delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
+ else
+ delta = 99999999;
+
+ last_time = new_time;
+
+ va_start(argptr, fmt);
+ (void)vsnprintf(debug_buffer, sizeof debug_buffer, fmt, argptr);
+ va_end(argptr);
+
+ (void)fprintf(LOG_STREAM, "%s%.8d%s %s%s%s\n", time_pfx, delta, time_sfx,
+ color_pfx, debug_buffer, color_sfx);
+ fflush(LOG_STREAM);
+} /* log_msg */
+
+void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
+ const int len)
+{
+ int i;
+ char *c, debug_buffer[len*3 + strlen(msg) +1];
+ size_t l;
+
+ (void)priority;
+
+ l = strlcpy(debug_buffer, msg, sizeof debug_buffer);
+ c = debug_buffer + l;
+
+ for (i = 0; i < len; ++i)
+ {
+ /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
+ (void)snprintf(c, 4, "%02X ", buffer[i]);
+ c += 3;
+ }
+
+ (void)fprintf(LOG_STREAM, "%s\n", debug_buffer);
+ fflush(LOG_STREAM);
+} /* log_xxd */
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/debug.h b/MdeModulePkg/Library/SmartCardReader/libccid/debug.h
new file mode 100644
index 0000000..001e41d
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/debug.h
@@ -0,0 +1,100 @@
+/*
+ debug.h: log (or not) messages using syslog
+ Copyright (C) 2003-2008 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: debug.h 6967 2014-09-02 13:50:50Z rousseau $
+ */
+
+/*
+ * DEBUG_CRITICAL("text");
+ * log "text" if (LogLevel & DEBUG_LEVEL_CRITICAL) is TRUE
+ *
+ * DEBUG_CRITICAL2("text: %d", 1234);
+ * log "text: 1234" if (DEBUG_LEVEL_CRITICAL & DEBUG_LEVEL_CRITICAL) is TRUE
+ * the format string can be anything printf() can understand
+ *
+ * same thing for DEBUG_INFO, DEBUG_COMM and DEBUG_PERIODIC
+ *
+ * DEBUG_XXD(msg, buffer, size);
+ * log a dump of buffer if (LogLevel & DEBUG_LEVEL_COMM) is TRUE
+ *
+ */
+
+#ifndef _GCDEBUG_H_
+#define _GCDEBUG_H_
+
+/* You can't do #ifndef __FUNCTION__ */
+#if !defined(__GNUC__) && !defined(__IBMC__)
+#define __FUNCTION__ ""
+#endif
+
+extern int LogLevel;
+
+#define DEBUG_LEVEL_CRITICAL 1
+#define DEBUG_LEVEL_INFO 2
+#define DEBUG_LEVEL_COMM 4
+#define DEBUG_LEVEL_PERIODIC 8
+
+#include <debuglog.h> /* from pcsc-lite */
+
+/* DEBUG_CRITICAL */
+#define DEBUG_CRITICAL(fmt) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log1(PCSC_LOG_CRITICAL, fmt)
+
+#define DEBUG_CRITICAL2(fmt, data) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log2(PCSC_LOG_CRITICAL, fmt, data)
+
+#define DEBUG_CRITICAL3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log3(PCSC_LOG_CRITICAL, fmt, data1, data2)
+
+#define DEBUG_CRITICAL4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log4(PCSC_LOG_CRITICAL, fmt, data1, data2, data3)
+
+#define DEBUG_CRITICAL5(fmt, data1, data2, data3, data4) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log5(PCSC_LOG_CRITICAL, fmt, data1, data2, data3, data4)
+
+/* DEBUG_INFO */
+#define DEBUG_INFO1(fmt) if (LogLevel & DEBUG_LEVEL_INFO) Log1(PCSC_LOG_INFO, fmt)
+
+#define DEBUG_INFO2(fmt, data) if (LogLevel & DEBUG_LEVEL_INFO) Log2(PCSC_LOG_INFO, fmt, data)
+
+#define DEBUG_INFO3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_INFO) Log3(PCSC_LOG_INFO, fmt, data1, data2)
+
+#define DEBUG_INFO4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_INFO) Log4(PCSC_LOG_INFO, fmt, data1, data2, data3)
+
+#define DEBUG_INFO5(fmt, data1, data2, data3, data4) if (LogLevel & DEBUG_LEVEL_INFO) Log5(PCSC_LOG_INFO, fmt, data1, data2, data3, data4)
+
+#define DEBUG_INFO_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_INFO) LogXxd(PCSC_LOG_INFO, msg, buffer, size)
+
+/* DEBUG_PERIODIC */
+#define DEBUG_PERIODIC(fmt) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log1(PCSC_LOG_DEBUG, fmt)
+
+#define DEBUG_PERIODIC2(fmt, data) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log2(PCSC_LOG_DEBUG, fmt, data)
+
+#define DEBUG_PERIODIC3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log3(PCSC_LOG_DEBUG, fmt, data1, data2)
+
+/* DEBUG_COMM */
+#define DEBUG_COMM(fmt) if (LogLevel & DEBUG_LEVEL_COMM) Log1(PCSC_LOG_DEBUG, fmt)
+
+#define DEBUG_COMM2(fmt, data) if (LogLevel & DEBUG_LEVEL_COMM) Log2(PCSC_LOG_DEBUG, fmt, data)
+
+#define DEBUG_COMM3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_COMM) Log3(PCSC_LOG_DEBUG, fmt, data1, data2)
+
+#define DEBUG_COMM4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_COMM) Log4(PCSC_LOG_DEBUG, fmt, data1, data2, data3)
+
+/* DEBUG_XXD */
+#define DEBUG_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_COMM) LogXxd(PCSC_LOG_DEBUG, msg, buffer, size)
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/defs.h b/MdeModulePkg/Library/SmartCardReader/libccid/defs.h
new file mode 100644
index 0000000..50877bb
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/defs.h
@@ -0,0 +1,126 @@
+/*
+ defs.h:
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: defs.h 6926 2014-06-17 09:22:00Z rousseau $
+ */
+
+#include <pcsclite.h>
+
+#include "openct/proto-t1.h"
+
+typedef struct CCID_DESC
+{
+ /*
+ * ATR
+ */
+ int nATRLength;
+ unsigned char pcATRBuffer[MAX_ATR_SIZE];
+
+ /*
+ * Card state
+ */
+ unsigned char bPowerFlags;
+
+ /*
+ * T=1 Protocol context
+ */
+ t1_state_t t1;
+
+ /* reader name passed to IFDHCreateChannelByName() */
+#ifdef UEFI_DRIVER
+ CHAR16 *readerName;
+#else
+ char *readerName;
+#endif
+} CcidDesc;
+
+typedef enum {
+ STATUS_NO_SUCH_DEVICE = 0xF9,
+ STATUS_SUCCESS = 0xFA,
+ STATUS_UNSUCCESSFUL = 0xFB,
+ STATUS_COMM_ERROR = 0xFC,
+ STATUS_DEVICE_PROTOCOL_ERROR = 0xFD,
+ STATUS_COMM_NAK = 0xFE,
+ STATUS_SECONDARY_SLOT = 0xFF
+} status_t;
+
+/* Powerflag (used to detect quick insertion removals unnoticed by the
+ * resource manager) */
+/* Initial value */
+#define POWERFLAGS_RAZ 0x00
+/* Flag set when a power up has been requested */
+#define MASK_POWERFLAGS_PUP 0x01
+/* Flag set when a power down is requested */
+#define MASK_POWERFLAGS_PDWN 0x02
+
+/* Communication buffer size (max=adpu+Lc+data+Le)
+ * we use a 64kB for extended APDU on APDU mode readers */
+#define CMD_BUF_SIZE (4 +3 +64*1024 +3)
+
+/* Protocols */
+#define T_0 0
+#define T_1 1
+
+/* Default communication read timeout in milliseconds */
+#define DEFAULT_COM_READ_TIMEOUT (3*1000)
+
+/* DWORD type formating */
+#ifdef __APPLE__
+/* Apple defines DWORD as uint32_t */
+#define DWORD_X "%X"
+#define DWORD_D "%d"
+#else
+/* pcsc-lite defines DWORD as unsigned long */
+#define DWORD_X "%lX"
+#define DWORD_D "%ld"
+#endif
+
+/*
+ * communication ports abstraction
+ */
+#ifdef TWIN_SERIAL
+
+#define OpenPortByName OpenSerialByName
+#define OpenPort OpenSerial
+#define ClosePort CloseSerial
+#define ReadPort ReadSerial
+#define WritePort WriteSerial
+#include "ccid_serial.h"
+
+#elif defined(UEFI_DRIVER)
+
+#define OpenPortByName OpenUEFIByName
+#define OpenPort OpenUEFI
+#define ClosePort CloseUEFI
+#define ReadPort ReadUEFI
+#define WritePort WriteUEFI
+#include "ccid_uefi.h"
+
+#else
+
+#define OpenPortByName OpenUSBByName
+#define OpenPort OpenUSB
+#define ClosePort CloseUSB
+#define ReadPort ReadUSB
+#define WritePort WriteUSB
+#include "ccid_usb.h"
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c b/MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
new file mode 100644
index 0000000..26e4400
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
@@ -0,0 +1,2265 @@
+/*
+ ifdhandler.c: IFDH API
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* $Id: ifdhandler.c 6977 2014-09-04 11:36:54Z rousseau $ */
+
+#include <config.h>
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifndef UEFI_DRIVER
+#include "parser.h"
+#endif
+
+#include "misc.h"
+#include <pcsclite.h>
+#include <ifdhandler.h>
+#include <reader.h>
+
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "debug.h"
+#include "utils.h"
+#include "commands.h"
+#include "towitoko/atr.h"
+#include "towitoko/pps.h"
+#ifndef UEFI_DRIVER
+#include "strlcpycat.h"
+#endif
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+/* Array of structures to hold the ATR and other state value of each slot */
+static CcidDesc CcidSlots[CCID_DRIVER_MAX_READERS];
+
+/* global mutex */
+#ifdef HAVE_PTHREAD
+static pthread_mutex_t ifdh_context_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+int LogLevel = DEBUG_LEVEL_CRITICAL | DEBUG_LEVEL_INFO;
+int DriverOptions = 0;
+int PowerOnVoltage = VOLTAGE_5V;
+static int DebugInitialized = FALSE;
+
+/* local functions */
+static void init_driver(void);
+static void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol);
+static char find_baud_rate(unsigned int baudrate, unsigned int *list);
+static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
+ int clock_frequency);
+static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI,
+ int CWI, int clock_frequency);
+static int get_IFSC(ATR_t *atr, int *i);
+
+
+static RESPONSECODE CreateChannelByNameOrChannel(DWORD Lun,
+ LPSTR lpcDevice, DWORD Channel)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ int reader_index;
+ status_t ret;
+
+ if (! DebugInitialized)
+ init_driver();
+
+ if (lpcDevice)
+ {
+ DEBUG_INFO3("Lun: " DWORD_X ", device: %s", Lun, lpcDevice);
+ }
+ else
+ {
+ DEBUG_INFO3("Lun: " DWORD_X ", Channel: " DWORD_X, Lun, Channel);
+ }
+
+ if (-1 == (reader_index = GetNewReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ /* Reset ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Reset PowerFlags */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+
+ /* reader name */
+#ifdef UEFI_DRIVER
+ CcidSlots[reader_index].readerName = NULL;
+#else
+ if (lpcDevice)
+ CcidSlots[reader_index].readerName = strdup(lpcDevice);
+ else
+ CcidSlots[reader_index].readerName = strdup("no name");
+#endif
+
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_lock(&ifdh_context_mutex);
+#endif
+
+ if (lpcDevice)
+ ret = OpenPortByName(reader_index, lpcDevice);
+ else
+ ret = OpenPort(reader_index, Channel);
+
+ if (ret != STATUS_SUCCESS)
+ {
+ DEBUG_CRITICAL("failed");
+ if (STATUS_NO_SUCH_DEVICE == ret)
+ return_value = IFD_NO_SUCH_DEVICE;
+ else
+ return_value = IFD_COMMUNICATION_ERROR;
+
+ goto error;
+ }
+ else
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ unsigned int oldReadTimeout;
+ RESPONSECODE cmd_ret;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ /* Maybe we have a special treatment for this reader */
+ (void)ccid_open_hack_pre(reader_index);
+
+ /* Try to access the reader */
+ /* This "warm up" sequence is sometimes needed when pcscd is
+ * restarted with the reader already connected. We get some
+ * "usb_bulk_read: Resource temporarily unavailable" on the first
+ * few tries. It is an empirical hack */
+
+ /* The reader may have to start here so give it some time */
+ cmd_ret = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (IFD_NO_SUCH_DEVICE == cmd_ret)
+ {
+ return_value = cmd_ret;
+ goto error;
+ }
+
+ /* save the current read timeout computed from card capabilities */
+ oldReadTimeout = ccid_descriptor->readTimeout;
+
+ /* 100 ms just to resync the USB toggle bits */
+ ccid_descriptor->readTimeout = 100;
+
+ if ((IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer))
+ && (IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer)))
+ {
+ DEBUG_CRITICAL("failed");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ {
+ /* Maybe we have a special treatment for this reader */
+ return_value = ccid_open_hack_post(reader_index);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("failed");
+ }
+ }
+
+ /* set back the old timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+ }
+
+error:
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_unlock(&ifdh_context_mutex);
+#endif
+
+ if (return_value != IFD_SUCCESS)
+ {
+ /* release the allocated resources */
+#ifndef UEFI_DRIVER
+ free(CcidSlots[reader_index].readerName);
+#endif
+ ReleaseReaderIndex(reader_index);
+ }
+
+ return return_value;
+} /* CreateChannelByNameOrChannel */
+
+
+EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice)
+{
+ return CreateChannelByNameOrChannel(Lun, lpcDevice, -1);
+}
+
+EXTERNAL RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel)
+{
+ /*
+ * Lun - Logical Unit Number, use this for multiple card slots or
+ * multiple readers. 0xXXXXYYYY - XXXX multiple readers, YYYY multiple
+ * slots. The resource manager will set these automatically. By
+ * default the resource manager loads a new instance of the driver so
+ * if your reader does not have more than one smartcard slot then
+ * ignore the Lun in all the functions. Future versions of PC/SC might
+ * support loading multiple readers through one instance of the driver
+ * in which XXXX would be important to implement if you want this.
+ */
+
+ /*
+ * Channel - Channel ID. This is denoted by the following: 0x000001 -
+ * /dev/pcsc/1 0x000002 - /dev/pcsc/2 0x000003 - /dev/pcsc/3
+ *
+ * USB readers may choose to ignore this parameter and query the bus
+ * for the particular reader.
+ */
+
+ /*
+ * This function is required to open a communications channel to the
+ * port listed by Channel. For example, the first serial reader on
+ * COM1 would link to /dev/pcsc/1 which would be a sym link to
+ * /dev/ttyS0 on some machines This is used to help with intermachine
+ * independance.
+ *
+ * Once the channel is opened the reader must be in a state in which
+ * it is possible to query IFDHICCPresence() for card status.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_COMMUNICATION_ERROR
+ */
+ return CreateChannelByNameOrChannel(Lun, NULL, Channel);
+} /* IFDHCreateChannel */
+
+
+EXTERNAL RESPONSECODE IFDHCloseChannel(DWORD Lun)
+{
+ /*
+ * This function should close the reader communication channel for the
+ * particular reader. Prior to closing the communication channel the
+ * reader should make sure the card is powered down and the terminal
+ * is also powered down.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_COMMUNICATION_ERROR
+ */
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
+ Lun);
+
+ /* Restore the default timeout
+ * No need to wait too long if the reader disapeared */
+ get_ccid_descriptor(reader_index)->readTimeout = DEFAULT_COM_READ_TIMEOUT;
+
+ (void)CmdPowerOff(reader_index);
+ /* No reader status check, if it failed, what can you do ? :) */
+
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_lock(&ifdh_context_mutex);
+#endif
+
+ (void)ClosePort(reader_index);
+ ReleaseReaderIndex(reader_index);
+
+#ifndef UEFI_DRIVER
+ free(CcidSlots[reader_index].readerName);
+#endif
+ memset(&CcidSlots[reader_index], 0, sizeof(CcidSlots[reader_index]));
+
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_unlock(&ifdh_context_mutex);
+#endif
+
+ return IFD_SUCCESS;
+} /* IFDHCloseChannel */
+
+
+#if !defined(TWIN_SERIAL) && !defined(UEFI_DRIVER)
+static RESPONSECODE IFDHPolling(DWORD Lun, int timeout)
+{
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ /* log only if DEBUG_LEVEL_PERIODIC is set */
+ if (LogLevel & DEBUG_LEVEL_PERIODIC)
+ DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
+ CcidSlots[reader_index].readerName, Lun, timeout);
+
+ return InterruptRead(reader_index, timeout);
+}
+
+/* on an ICCD device the card is always inserted
+ * so no card movement will ever happen: just do nothing */
+static RESPONSECODE IFDHSleep(DWORD Lun, int timeout)
+{
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
+ CcidSlots[reader_index].readerName, Lun, timeout);
+
+ /* just sleep for 5 seconds since the polling thread is NOT killable
+ * so pcscd event thread must loop to exit cleanly
+ *
+ * Once the driver (libusb in fact) will support
+ * TAG_IFD_POLLING_THREAD_KILLABLE then we could use a much longer delay
+ * and be killed before pcscd exits
+ */
+ (void)usleep(timeout);
+ return IFD_SUCCESS;
+}
+
+static RESPONSECODE IFDHStopPolling(DWORD Lun)
+{
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO3("%s (lun: " DWORD_X ")",
+ CcidSlots[reader_index].readerName, Lun);
+
+ (void)InterruptStop(reader_index);
+ return IFD_SUCCESS;
+}
+#endif
+
+
+EXTERNAL RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag,
+ PDWORD Length, PUCHAR Value)
+{
+ /*
+ * This function should get the slot/card capabilities for a
+ * particular slot/card specified by Lun. Again, if you have only 1
+ * card slot and don't mind loading a new driver for each reader then
+ * ignore Lun.
+ *
+ * Tag - the tag for the information requested example: TAG_IFD_ATR -
+ * return the Atr and it's size (required). these tags are defined in
+ * ifdhandler.h
+ *
+ * Length - the length of the returned data Value - the value of the
+ * data
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_ERROR_TAG
+ */
+ int reader_index;
+ RESPONSECODE return_value = IFD_SUCCESS;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
+ CcidSlots[reader_index].readerName, Lun);
+
+ switch (Tag)
+ {
+ case TAG_IFD_ATR:
+ case SCARD_ATTR_ATR_STRING:
+ /* If Length is not zero, powerICC has been performed.
+ * Otherwise, return NULL pointer
+ * Buffer size is stored in *Length */
+ if ((int)*Length >= CcidSlots[reader_index].nATRLength)
+ {
+ *Length = CcidSlots[reader_index].nATRLength;
+
+ memcpy(Value, CcidSlots[reader_index].pcATRBuffer, *Length);
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case SCARD_ATTR_ICC_INTERFACE_STATUS:
+ *Length = 1;
+ if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
+ /* nonzero if contact is active */
+ *Value = 1;
+ else
+ /* smart card electrical contact is not active */
+ *Value = 0;
+ break;
+
+ case SCARD_ATTR_ICC_PRESENCE:
+ *Length = 1;
+ /* Single byte indicating smart card presence:
+ * 0 = not present
+ * 1 = card present but not swallowed (applies only if
+ * reader supports smart card swallowing)
+ * 2 = card present (and swallowed if reader supports smart
+ * card swallowing)
+ * 4 = card confiscated. */
+ if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
+ /* Card present */
+ *Value = 2;
+ else
+ /* Not present */
+ *Value = 0;
+ break;
+
+#ifdef HAVE_PTHREAD
+ case TAG_IFD_SIMULTANEOUS_ACCESS:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+ *Value = CCID_DRIVER_MAX_READERS;
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case TAG_IFD_THREAD_SAFE:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+#ifdef __APPLE__
+ *Value = 0; /* Apple pcscd is bogus (rdar://problem/5697388) */
+#else
+ *Value = 1; /* Can talk to multiple readers at the same time */
+#endif
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+#endif
+
+ case TAG_IFD_SLOTS_NUMBER:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+ *Value = 1 + get_ccid_descriptor(reader_index) -> bMaxSlotIndex;
+#ifdef USE_COMPOSITE_AS_MULTISLOT
+ {
+ /* On MacOS X or Linux+libusb we can simulate a
+ * composite device with 2 CCID interfaces by a
+ * multi-slot reader */
+ int readerID = get_ccid_descriptor(reader_index) -> readerID;
+
+ if ((GEMALTOPROXDU == readerID) || (GEMALTOPROXSU == readerID))
+ *Value = 2;
+ }
+#endif
+ DEBUG_INFO2("Reader supports %d slot(s)", *Value);
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case TAG_IFD_SLOT_THREAD_SAFE:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+ *Value = 0; /* Can NOT talk to multiple slots at the same time */
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case SCARD_ATTR_VENDOR_IFD_VERSION:
+ {
+ int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice;
+
+ /* Vendor-supplied interface device version (DWORD in the form
+ * 0xMMmmbbbb where MM = major version, mm = minor version, and
+ * bbbb = build number). */
+ *Length = 4;
+ if (Value)
+ *(uint32_t *)Value = IFD_bcdDevice << 16;
+ }
+ break;
+
+#ifndef UEFI_DRIVER
+ case SCARD_ATTR_VENDOR_NAME:
+ {
+ const char *sIFD_iManufacturer = get_ccid_descriptor(reader_index) -> sIFD_iManufacturer;
+
+ if (sIFD_iManufacturer)
+ {
+ strlcpy((char *)Value, sIFD_iManufacturer, *Length);
+ *Length = strlen((char *)Value) +1;
+ }
+ else
+ {
+ /* not supported */
+ *Length = 0;
+ }
+ }
+ break;
+#endif
+
+ case SCARD_ATTR_MAXINPUT:
+ *Length = sizeof(uint32_t);
+ if (Value)
+ *(uint32_t *)Value = get_ccid_descriptor(reader_index) -> dwMaxCCIDMessageLength -10;
+ break;
+
+#if !defined(TWIN_SERIAL) && !defined(UEFI_DRIVER)
+ case TAG_IFD_POLLING_THREAD_WITH_TIMEOUT:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ /* default value: not supported */
+ *Length = 0;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+
+ /* CCID and not ICCD */
+ if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
+ /* 3 end points */
+ && (3 == ccid_desc -> bNumEndpoints))
+ {
+ *Length = sizeof(void *);
+ if (Value)
+ *(void **)Value = IFDHPolling;
+ }
+
+ if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
+ || (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
+ {
+ *Length = sizeof(void *);
+ if (Value)
+ *(void **)Value = IFDHSleep;
+ }
+ }
+ break;
+
+ case TAG_IFD_POLLING_THREAD_KILLABLE:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ /* default value: not supported */
+ *Length = 0;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+ if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
+ || (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
+ {
+ *Length = 1; /* 1 char */
+ if (Value)
+ *Value = 1; /* TRUE */
+ }
+ }
+ break;
+
+ case TAG_IFD_STOP_POLLING_THREAD:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ /* default value: not supported */
+ *Length = 0;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+ /* CCID and not ICCD */
+ if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
+ /* 3 end points */
+ && (3 == ccid_desc -> bNumEndpoints))
+ {
+ *Length = sizeof(void *);
+ if (Value)
+ *(void **)Value = IFDHStopPolling;
+ }
+ }
+ break;
+#endif
+
+#ifndef UEFI_DRIVER
+ case SCARD_ATTR_VENDOR_IFD_SERIAL_NO:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+ if (ccid_desc->sIFD_serial_number)
+ {
+ strlcpy((char *)Value, ccid_desc->sIFD_serial_number, *Length);
+ *Length = strlen((char *)Value);
+ }
+ else
+ {
+ /* not supported */
+ *Length = 0;
+ }
+ }
+ break;
+#endif
+
+ default:
+ return_value = IFD_ERROR_TAG;
+ }
+
+ return return_value;
+} /* IFDHGetCapabilities */
+
+
+EXTERNAL RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
+ /*@unused@*/ DWORD Length, /*@unused@*/ PUCHAR Value)
+{
+ /*
+ * This function should set the slot/card capabilities for a
+ * particular slot/card specified by Lun. Again, if you have only 1
+ * card slot and don't mind loading a new driver for each reader then
+ * ignore Lun.
+ *
+ * Tag - the tag for the information needing set
+ *
+ * Length - the length of the returned data Value - the value of the
+ * data
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
+ * IFD_ERROR_VALUE_READ_ONLY
+ */
+
+ (void)Length;
+ (void)Value;
+
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
+ CcidSlots[reader_index].readerName, Lun);
+
+ return IFD_NOT_SUPPORTED;
+} /* IFDHSetCapabilities */
+
+
+EXTERNAL RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
+ UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
+{
+ /*
+ * This function should set the PTS of a particular card/slot using
+ * the three PTS parameters sent
+ *
+ * Protocol - SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
+ * Flags - Logical OR of possible values:
+ * IFD_NEGOTIATE_PTS1
+ * IFD_NEGOTIATE_PTS2
+ * IFD_NEGOTIATE_PTS3
+ * to determine which PTS values to negotiate.
+ * PTS1,PTS2,PTS3 - PTS Values.
+ *
+ * returns:
+ * IFD_SUCCESS
+ * IFD_ERROR_PTS_FAILURE
+ * IFD_COMMUNICATION_ERROR
+ * IFD_PROTOCOL_NOT_SUPPORTED
+ */
+
+ BYTE pps[PPS_MAX_LENGTH];
+ ATR_t atr;
+ unsigned int len;
+ int convention;
+ int reader_index;
+ int atr_ret;
+
+ /* Set ccid desc params */
+ CcidDesc *ccid_slot;
+ _ccid_descriptor *ccid_desc;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("protocol T=" DWORD_D ", %s (lun: " DWORD_X ")",
+ Protocol-SCARD_PROTOCOL_T0, CcidSlots[reader_index].readerName, Lun);
+
+ /* Set to zero buffer */
+ memset(pps, 0, sizeof(pps));
+ memset(&atr, 0, sizeof(atr));
+
+ /* Get ccid params */
+ ccid_slot = get_ccid_slot(reader_index);
+ ccid_desc = get_ccid_descriptor(reader_index);
+
+ /* Do not send CCID command SetParameters or PPS to the CCID
+ * The CCID will do this himself */
+ if (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_PROP)
+ {
+ DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
+ goto end;
+ }
+
+ /* Get ATR of the card */
+ atr_ret = ATR_InitFromArray(&atr, ccid_slot->pcATRBuffer,
+ ccid_slot->nATRLength);
+ if (ATR_MALFORMED == atr_ret)
+ return IFD_PROTOCOL_NOT_SUPPORTED;
+
+ /* Apply Extra EGT patch for bogus cards */
+ extra_egt(&atr, ccid_desc, Protocol);
+
+ if (SCARD_PROTOCOL_T0 == Protocol)
+ pps[1] |= ATR_PROTOCOL_TYPE_T0;
+ else
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ pps[1] |= ATR_PROTOCOL_TYPE_T1;
+ else
+ return IFD_PROTOCOL_NOT_SUPPORTED;
+
+ /* TA2 present -> specific mode */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
+ {
+ if (pps[1] != (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F))
+ {
+ /* wrong protocol */
+ DEBUG_COMM3("Specific mode in T=%d and T=%d requested",
+ atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F, pps[1]);
+
+ return IFD_PROTOCOL_NOT_SUPPORTED;
+ }
+ }
+
+ /* TCi (i>2) indicates CRC instead of LRC */
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ t1_state_t *t1 = &(ccid_slot -> t1);
+ int i;
+
+ /* TCi (i>2) present? */
+ for (i=2; i<ATR_MAX_PROTOCOLS; i++)
+ if (atr.ib[i][ATR_INTERFACE_BYTE_TC].present)
+ {
+ if (0 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
+ {
+ DEBUG_COMM("Use LRC");
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
+ }
+ else
+ if (1 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
+ {
+ DEBUG_COMM("Use CRC");
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_CRC, 0);
+ }
+ else
+ DEBUG_COMM2("Wrong value for TCi: %d",
+ atr.ib[i][ATR_INTERFACE_BYTE_TC].value);
+
+ /* only the first TCi (i>2) must be used */
+ break;
+ }
+ }
+
+ /* PTS1? */
+ if (Flags & IFD_NEGOTIATE_PTS1)
+ {
+ /* just use the value passed in argument */
+ pps[1] |= 0x10; /* PTS1 presence */
+ pps[2] = PTS1;
+ }
+ else
+ {
+ /* TA1 present */
+ if (atr.ib[0][ATR_INTERFACE_BYTE_TA].present)
+ {
+ unsigned int card_baudrate;
+ unsigned int default_baudrate;
+ double f, d;
+
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d))
+ {
+ /* values for TA1=11 */
+ f = 372;
+ d = 1;
+ }
+
+ /* Baudrate = f x D/F */
+ card_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
+ * d / f);
+
+ default_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
+ * ATR_DEFAULT_D / ATR_DEFAULT_F);
+
+ /* if the card does not try to lower the default speed */
+ if ((card_baudrate > default_baudrate)
+ /* and the reader is fast enough */
+ && (card_baudrate <= ccid_desc->dwMaxDataRate))
+ {
+ /* the reader has no baud rates table */
+ if ((NULL == ccid_desc->arrayOfSupportedDataRates)
+ /* or explicitely support it */
+ || find_baud_rate(card_baudrate,
+ ccid_desc->arrayOfSupportedDataRates))
+ {
+ pps[1] |= 0x10; /* PTS1 presence */
+ pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
+
+ DEBUG_COMM2("Set speed to %d bauds", card_baudrate);
+ }
+ else
+ {
+ DEBUG_COMM2("Reader does not support %d bauds",
+ card_baudrate);
+
+ /* TA2 present -> specific mode: the card is supporting
+ * only the baud rate specified in TA1 but reader does not
+ * support this value. Reject the card. */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+ else
+ {
+ /* the card is too fast for the reader */
+ if ((card_baudrate > ccid_desc->dwMaxDataRate +2)
+ /* but TA1 <= 97 */
+ && (atr.ib[0][ATR_INTERFACE_BYTE_TA].value <= 0x97)
+ /* and the reader has a baud rate table */
+ && ccid_desc->arrayOfSupportedDataRates)
+ {
+ unsigned char old_TA1;
+
+ old_TA1 = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
+ while (atr.ib[0][ATR_INTERFACE_BYTE_TA].value > 0x94)
+ {
+ /* use a lower TA1 */
+ atr.ib[0][ATR_INTERFACE_BYTE_TA].value--;
+
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+
+ /* Baudrate = f x D/F */
+ card_baudrate = (unsigned int) (1000 *
+ ccid_desc->dwDefaultClock * d / f);
+
+ if (find_baud_rate(card_baudrate,
+ ccid_desc->arrayOfSupportedDataRates))
+ {
+ pps[1] |= 0x10; /* PTS1 presence */
+ pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
+
+ DEBUG_COMM2("Set adapted speed to %d bauds",
+ card_baudrate);
+
+ break;
+ }
+ }
+
+ /* restore original TA1 value */
+ atr.ib[0][ATR_INTERFACE_BYTE_TA].value = old_TA1;
+ }
+ }
+ }
+ }
+
+ /* PTS2? */
+ if (Flags & IFD_NEGOTIATE_PTS2)
+ {
+ pps[1] |= 0x20; /* PTS2 presence */
+ pps[3] = PTS2;
+ }
+
+ /* PTS3? */
+ if (Flags & IFD_NEGOTIATE_PTS3)
+ {
+ pps[1] |= 0x40; /* PTS3 presence */
+ pps[4] = PTS3;
+ }
+
+ /* Generate PPS */
+ pps[0] = 0xFF;
+
+ /* Automatic PPS made by the ICC? */
+ if ((! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_CUR))
+ /* TA2 absent: negociable mode */
+ && (! atr.ib[1][ATR_INTERFACE_BYTE_TA].present))
+ {
+ int default_protocol;
+
+ ATR_GetDefaultProtocol(&atr, &default_protocol, NULL);
+
+ /* if the requested protocol is not the default one
+ * or a TA1/PPS1 is present */
+ if (((pps[1] & 0x0F) != default_protocol) || (PPS_HAS_PPS1(pps)))
+ {
+#ifdef O2MICRO_OZ776_PATCH
+ if ((OZ776 == ccid_desc->readerID)
+ || (OZ776_7772 == ccid_desc->readerID))
+ {
+ /* convert from ATR_PROTOCOL_TYPE_T? to SCARD_PROTOCOL_T? */
+ Protocol = default_protocol +
+ (SCARD_PROTOCOL_T0 - ATR_PROTOCOL_TYPE_T0);
+ DEBUG_INFO2("PPS not supported on O2Micro readers. Using T=" DWORD_D,
+ Protocol - SCARD_PROTOCOL_T0);
+ }
+ else
+#endif
+ if (PPS_Exchange(reader_index, pps, &len, &pps[2]) != PPS_OK)
+ {
+ DEBUG_INFO1("PPS_Exchange Failed");
+
+ return IFD_ERROR_PTS_FAILURE;
+ }
+ }
+ }
+
+ /* Now we must set the reader parameters */
+ (void)ATR_GetConvention(&atr, &convention);
+
+ /* specific mode and implicit parameters? (b5 of TA2) */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present
+ && (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x10))
+ return IFD_COMMUNICATION_ERROR;
+
+ /* T=1 */
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ BYTE param[] = {
+ 0x11, /* Fi/Di */
+ 0x10, /* TCCKS */
+ 0x00, /* GuardTime */
+ 0x4D, /* BWI/CWI */
+ 0x00, /* ClockStop */
+ 0x20, /* IFSC */
+ 0x00 /* NADValue */
+ };
+ int i;
+ t1_state_t *t1 = &(ccid_slot -> t1);
+ RESPONSECODE ret;
+ double f, d;
+ int ifsc;
+
+ /* TA1 is not default */
+ if (PPS_HAS_PPS1(pps))
+ param[0] = pps[2];
+
+ /* CRC checksum? */
+ if (2 == t1->rc_bytes)
+ param[1] |= 0x01;
+
+ /* the CCID should ignore this bit */
+ if (ATR_CONVENTION_INVERSE == convention)
+ param[1] |= 0x02;
+
+ /* get TC1 Extra guard time */
+ if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
+ param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
+
+ /* TBi (i>2) present? BWI/CWI */
+ for (i=2; i<ATR_MAX_PROTOCOLS; i++)
+ if (atr.ib[i][ATR_INTERFACE_BYTE_TB].present)
+ {
+ DEBUG_COMM3("BWI/CWI (TB%d) present: 0x%02X", i+1,
+ atr.ib[i][ATR_INTERFACE_BYTE_TB].value);
+ param[3] = atr.ib[i][ATR_INTERFACE_BYTE_TB].value;
+
+ {
+ /* Hack for OpenPGP card */
+ unsigned char openpgp_atr[] = { 0x3B, 0xFA, 0x13,
+ 0x00, 0xFF, 0x81, 0x31, 0x80, 0x45, 0x00, 0x31,
+ 0xC1, 0x73, 0xC0, 0x01, 0x00, 0x00, 0x90, 0x00, 0xB1 };
+
+ if (0 == memcmp(ccid_slot->pcATRBuffer, openpgp_atr,
+ ccid_slot->nATRLength))
+ /* change BWI from 4 to 7 to increase BWT from
+ * 1.4s to 11s and avoid a timeout during on
+ * board key generation (bogus card) */
+ {
+ param[3] = 0x75;
+ DEBUG_COMM2("OpenPGP hack, using 0x%02X", param[3]);
+ }
+ }
+
+ /* only the first TBi (i>2) must be used */
+ break;
+ }
+
+ /* compute communication timeout */
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+ ccid_desc->readTimeout = T1_card_timeout(f, d, param[2],
+ (param[3] & 0xF0) >> 4 /* BWI */, param[3] & 0x0F /* CWI */,
+ ccid_desc->dwDefaultClock);
+
+ ifsc = get_IFSC(&atr, &i);
+ if (ifsc > 0)
+ {
+ DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
+ param[5] = ifsc;
+ }
+
+ DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
+
+ ret = SetParameters(reader_index, 1, sizeof(param), param);
+ if (IFD_SUCCESS != ret)
+ return ret;
+ }
+ else
+ /* T=0 */
+ {
+ BYTE param[] = {
+ 0x11, /* Fi/Di */
+ 0x00, /* TCCKS */
+ 0x00, /* GuardTime */
+ 0x0A, /* WaitingInteger */
+ 0x00 /* ClockStop */
+ };
+ RESPONSECODE ret;
+ double f, d;
+
+ /* TA1 is not default */
+ if (PPS_HAS_PPS1(pps))
+ param[0] = pps[2];
+
+ if (ATR_CONVENTION_INVERSE == convention)
+ param[1] |= 0x02;
+
+ /* get TC1 Extra guard time */
+ if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
+ param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
+
+ /* TC2 WWT */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TC].present)
+ param[3] = atr.ib[1][ATR_INTERFACE_BYTE_TC].value;
+
+ /* compute communication timeout */
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+
+ ccid_desc->readTimeout = T0_card_timeout(f, d, param[2] /* TC1 */,
+ param[3] /* TC2 */, ccid_desc->dwDefaultClock);
+
+ DEBUG_COMM2("Communication timeout: %d ms", ccid_desc->readTimeout);
+
+ ret = SetParameters(reader_index, 0, sizeof(param), param);
+ if (IFD_SUCCESS != ret)
+ return ret;
+ }
+
+ /* set IFSC & IFSD in T=1 */
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ t1_state_t *t1 = &(ccid_slot -> t1);
+ int i, ifsc;
+
+ ifsc = get_IFSC(&atr, &i);
+ if (ifsc > 0)
+ {
+ DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSC, ifsc);
+ }
+
+ /* IFSD not negociated by the reader? */
+ if (! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_IFSD))
+ {
+ DEBUG_COMM2("Negociate IFSD at %d", ccid_desc -> dwMaxIFSD);
+ if (t1_negotiate_ifsd(t1, 0, ccid_desc -> dwMaxIFSD) < 0)
+ return IFD_COMMUNICATION_ERROR;
+ }
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSD, ccid_desc -> dwMaxIFSD);
+
+ DEBUG_COMM3("T=1: IFSC=%d, IFSD=%d", t1->ifsc, t1->ifsd);
+ }
+
+end:
+ /* store used protocol for use by the secure commands (verify/change PIN) */
+ ccid_desc->cardProtocol = Protocol;
+
+ return IFD_SUCCESS;
+} /* IFDHSetProtocolParameters */
+
+
+EXTERNAL RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
+ PUCHAR Atr, PDWORD AtrLength)
+{
+ /*
+ * This function controls the power and reset signals of the smartcard
+ * reader at the particular reader/slot specified by Lun.
+ *
+ * Action - Action to be taken on the card.
+ *
+ * IFD_POWER_UP - Power and reset the card if not done so (store the
+ * ATR and return it and it's length).
+ *
+ * IFD_POWER_DOWN - Power down the card if not done already
+ * (Atr/AtrLength should be zero'd)
+ *
+ * IFD_RESET - Perform a quick reset on the card. If the card is not
+ * powered power up the card. (Store and return the Atr/Length)
+ *
+ * Atr - Answer to Reset of the card. The driver is responsible for
+ * caching this value in case IFDHGetCapabilities is called requesting
+ * the ATR and it's length. This should not exceed MAX_ATR_SIZE.
+ *
+ * AtrLength - Length of the Atr. This should not exceed
+ * MAX_ATR_SIZE.
+ *
+ * Notes:
+ *
+ * Memory cards without an ATR should return IFD_SUCCESS on reset but
+ * the Atr should be zero'd and the length should be zero
+ *
+ * Reset errors should return zero for the AtrLength and return
+ * IFD_ERROR_POWER_ACTION.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
+ * IFD_NOT_SUPPORTED
+ */
+
+ unsigned int nlength;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ unsigned char pcbuffer[10+MAX_ATR_SIZE];
+ int reader_index;
+#ifndef NO_LOG
+ const char *actions[] = { "PowerUp", "PowerDown", "Reset" };
+#endif
+ unsigned int oldReadTimeout;
+ _ccid_descriptor *ccid_descriptor;
+
+ /* By default, assume it won't work :) */
+ *AtrLength = 0;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+#ifdef UEFI_DRIVER
+ DEBUG_INFO4("action: %a, %s (lun: " DWORD_X ")",
+#else
+ DEBUG_INFO4("action: %s, %s (lun: " DWORD_X ")",
+#endif
+ actions[Action-IFD_POWER_UP], CcidSlots[reader_index].readerName, Lun);
+
+ switch (Action)
+ {
+ case IFD_POWER_DOWN:
+ /* Clear ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Memorise the request */
+ CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PDWN;
+
+ /* send the command */
+ if (IFD_SUCCESS != CmdPowerOff(reader_index))
+ {
+ DEBUG_CRITICAL("PowerDown failed");
+ return_value = IFD_ERROR_POWER_ACTION;
+ goto end;
+ }
+
+ /* clear T=1 context */
+ t1_release(&(get_ccid_slot(reader_index) -> t1));
+ break;
+
+ case IFD_POWER_UP:
+ case IFD_RESET:
+ /* save the current read timeout computed from card capabilities */
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+ oldReadTimeout = ccid_descriptor->readTimeout;
+
+ /* The German eID card is bogus and need to be powered off
+ * before a power on */
+ if (KOBIL_IDTOKEN == ccid_descriptor -> readerID)
+ {
+ /* send the command */
+ if (IFD_SUCCESS != CmdPowerOff(reader_index))
+ {
+ DEBUG_CRITICAL("PowerDown failed");
+ return_value = IFD_ERROR_POWER_ACTION;
+ goto end;
+ }
+ }
+
+ /* use a very long timeout since the card can use up to
+ * (9600+12)*33 ETU in total
+ * 12 ETU per byte
+ * 9600 ETU max between each byte
+ * 33 bytes max for ATR
+ * 1 ETU = 372 cycles during ATR
+ * with a 4 MHz clock => 29 seconds
+ */
+ ccid_descriptor->readTimeout = 60*1000;
+
+ nlength = sizeof(pcbuffer);
+ return_value = CmdPowerOn(reader_index, &nlength, pcbuffer,
+ PowerOnVoltage);
+
+ /* set back the old timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+
+ if (return_value != IFD_SUCCESS)
+ {
+ /* used by GemCore SIM PRO: no card is present */
+ if (GEMCORESIMPRO == ccid_descriptor -> readerID)
+ get_ccid_descriptor(reader_index)->dwSlotStatus
+ = IFD_ICC_NOT_PRESENT;
+
+ DEBUG_CRITICAL("PowerUp failed");
+ return_value = IFD_ERROR_POWER_ACTION;
+ goto end;
+ }
+
+ /* Power up successful, set state variable to memorise it */
+ CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PUP;
+ CcidSlots[reader_index].bPowerFlags &= ~MASK_POWERFLAGS_PDWN;
+
+ /* Reset is returned, even if TCK is wrong */
+ CcidSlots[reader_index].nATRLength = *AtrLength =
+ (nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
+ memcpy(Atr, pcbuffer, *AtrLength);
+ memcpy(CcidSlots[reader_index].pcATRBuffer, pcbuffer, *AtrLength);
+
+ /* initialise T=1 context */
+ (void)t1_init(&(get_ccid_slot(reader_index) -> t1), reader_index);
+ break;
+
+ default:
+ DEBUG_CRITICAL("Action not supported");
+ return_value = IFD_NOT_SUPPORTED;
+ }
+end:
+
+ return return_value;
+} /* IFDHPowerICC */
+
+
+EXTERNAL RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
+ PUCHAR TxBuffer, DWORD TxLength,
+ PUCHAR RxBuffer, PDWORD RxLength, /*@unused@*/ PSCARD_IO_HEADER RecvPci)
+{
+ /*
+ * This function performs an APDU exchange with the card/slot
+ * specified by Lun. The driver is responsible for performing any
+ * protocol specific exchanges such as T=0/1 ... differences. Calling
+ * this function will abstract all protocol differences.
+ *
+ * SendPci Protocol - 0, 1, .... 14 Length - Not used.
+ *
+ * TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
+ * 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
+ * example (0x61 0x14) RxLength - Length of the received APDU. This
+ * function will be passed the size of the buffer of RxBuffer and this
+ * function is responsible for setting this to the length of the
+ * received APDU. This should be ZERO on all errors. The resource
+ * manager will take responsibility of zeroing out any temporary APDU
+ * buffers for security reasons.
+ *
+ * RecvPci Protocol - 0, 1, .... 14 Length - Not used.
+ *
+ * Notes: The driver is responsible for knowing what type of card it
+ * has. If the current slot/card contains a memory card then this
+ * command should ignore the Protocol and use the MCT style commands
+ * for support for these style cards and transmit them appropriately.
+ * If your reader does not support memory cards or you don't want to
+ * then ignore this.
+ *
+ * RxLength should be set to zero on error.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
+ * IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
+ */
+
+ RESPONSECODE return_value;
+ unsigned int rx_length;
+ int reader_index;
+
+ (void)RecvPci;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
+ Lun);
+
+#ifndef UEFI_DRIVER
+ /* special APDU for the Kobil IDToken (CLASS = 0xFF) */
+ if (KOBIL_IDTOKEN == get_ccid_descriptor(reader_index) -> readerID)
+ {
+ char manufacturer[] = {0xFF, 0x9A, 0x01, 0x01, 0x00};
+ char product_name[] = {0xFF, 0x9A, 0x01, 0x03, 0x00};
+ char firmware_version[] = {0xFF, 0x9A, 0x01, 0x06, 0x00};
+ char driver_version[] = {0xFF, 0x9A, 0x01, 0x07, 0x00};
+
+ if ((sizeof manufacturer == TxLength)
+ && (memcmp(TxBuffer, manufacturer, sizeof manufacturer) == 0))
+ {
+ DEBUG_INFO1("IDToken: Manufacturer command");
+ memcpy(RxBuffer, "KOBIL systems\220\0", 15);
+ *RxLength = 15;
+ return IFD_SUCCESS;
+ }
+
+ if ((sizeof product_name == TxLength)
+ && (memcmp(TxBuffer, product_name, sizeof product_name) == 0))
+ {
+ DEBUG_INFO1("IDToken: Product name command");
+ memcpy(RxBuffer, "IDToken\220\0", 9);
+ *RxLength = 9;
+ return IFD_SUCCESS;
+ }
+
+ if ((sizeof firmware_version == TxLength)
+ && (memcmp(TxBuffer, firmware_version, sizeof firmware_version) == 0))
+ {
+ int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice;
+
+ DEBUG_INFO1("IDToken: Firmware version command");
+ *RxLength = sprintf((char *)RxBuffer, "%X.%02X",
+ IFD_bcdDevice >> 8, IFD_bcdDevice & 0xFF);
+ RxBuffer[(*RxLength)++] = 0x90;
+ RxBuffer[(*RxLength)++] = 0x00;
+ return IFD_SUCCESS;
+ }
+
+ if ((sizeof driver_version == TxLength)
+ && (memcmp(TxBuffer, driver_version, sizeof driver_version) == 0))
+ {
+ DEBUG_INFO1("IDToken: Driver version command");
+#define DRIVER_VERSION "2012.2.7\220\0"
+ memcpy(RxBuffer, DRIVER_VERSION, sizeof DRIVER_VERSION -1);
+ *RxLength = sizeof DRIVER_VERSION -1;
+ return IFD_SUCCESS;
+ }
+
+ }
+#endif
+
+ rx_length = *RxLength;
+ return_value = CmdXfrBlock(reader_index, TxLength, TxBuffer, &rx_length,
+ RxBuffer, SendPci.Protocol);
+ if (IFD_SUCCESS == return_value)
+ *RxLength = rx_length;
+ else
+ *RxLength = 0;
+
+ return return_value;
+} /* IFDHTransmitToICC */
+
+
+EXTERNAL RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode,
+ PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength,
+ PDWORD pdwBytesReturned)
+{
+ /*
+ * This function performs a data exchange with the reader (not the
+ * card) specified by Lun. Here XXXX will only be used. It is
+ * responsible for abstracting functionality such as PIN pads,
+ * biometrics, LCD panels, etc. You should follow the MCT, CTBCS
+ * specifications for a list of accepted commands to implement.
+ *
+ * TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
+ * - Receive data RxLength - Length of the received data. This
+ * function will be passed the length of the buffer RxBuffer and it
+ * must set this to the length of the received data.
+ *
+ * Notes: RxLength should be zero on error.
+ */
+ RESPONSECODE return_value = IFD_ERROR_NOT_SUPPORTED;
+ int reader_index;
+ _ccid_descriptor *ccid_descriptor;
+
+ reader_index = LunToReaderIndex(Lun);
+ if ((-1 == reader_index) || (NULL == pdwBytesReturned))
+ return IFD_COMMUNICATION_ERROR;
+
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ DEBUG_INFO4("ControlCode: 0x" DWORD_X ", %s (lun: " DWORD_X ")",
+ dwControlCode, CcidSlots[reader_index].readerName, Lun);
+ DEBUG_INFO_XXD("Control TxBuffer: ", TxBuffer, TxLength);
+
+ /* Set the return length to 0 to avoid problems */
+ *pdwBytesReturned = 0;
+
+ if (IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE == dwControlCode)
+ {
+ int allowed = (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED);
+ int readerID = ccid_descriptor -> readerID;
+
+ if (VENDOR_GEMALTO == GET_VENDOR(readerID))
+ {
+ unsigned char switch_interface[] = { 0x52, 0xF8, 0x04, 0x01, 0x00 };
+
+ /* get firmware version escape command */
+ if ((1 == TxLength) && (0x02 == TxBuffer[0]))
+ allowed = TRUE;
+
+ /* switch interface escape command on the GemProx DU
+ * the next byte in the command is the interface:
+ * 0x01 switch to contactless interface
+ * 0x02 switch to contact interface
+ */
+ if ((GEMALTOPROXDU == readerID)
+ && (6 == TxLength)
+ && (0 == memcmp(TxBuffer, switch_interface, sizeof(switch_interface))))
+ allowed = TRUE;
+ }
+
+ if (!allowed)
+ {
+ DEBUG_INFO1("ifd exchange (Escape command) not allowed");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ {
+ unsigned int iBytesReturned;
+
+ iBytesReturned = RxLength;
+ /* 30 seconds timeout for long commands */
+ return_value = CmdEscape(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned, 30*1000);
+ *pdwBytesReturned = iBytesReturned;
+ }
+ }
+
+ /* Implement the PC/SC v2.02.07 Part 10 IOCTL mechanism */
+
+ /* Query for features */
+ /* 0x313520 is the Windows value for SCARD_CTL_CODE(3400)
+ * This hack is needed for RDP applications */
+ if ((CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode)
+ || (0x313520 == dwControlCode))
+ {
+ unsigned int iBytesReturned = 0;
+ PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)RxBuffer;
+ int readerID = ccid_descriptor -> readerID;
+
+ /* we need room for up to five records */
+ if (RxLength < 6 * sizeof(PCSC_TLV_STRUCTURE))
+ return IFD_ERROR_INSUFFICIENT_BUFFER;
+
+ /* We can only support direct verify and/or modify currently */
+ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_VERIFY)
+ {
+ pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_MODIFY)
+ {
+ pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ /* Provide IFD_PIN_PROPERTIES only for pinpad readers */
+ if (ccid_descriptor -> bPINSupport)
+ {
+ pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_IFD_PIN_PROPERTIES);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ if ((KOBIL_TRIBANK == readerID)
+ || (KOBIL_MIDENTITY_VISUAL == readerID))
+ {
+ pcsc_tlv -> tag = FEATURE_MCT_READER_DIRECT;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_MCT_READER_DIRECT);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ pcsc_tlv -> tag = FEATURE_GET_TLV_PROPERTIES;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_GET_TLV_PROPERTIES);
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+
+ /* IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE */
+ if (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED)
+ {
+ pcsc_tlv -> tag = FEATURE_CCID_ESC_COMMAND;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ *pdwBytesReturned = iBytesReturned;
+ return_value = IFD_SUCCESS;
+ }
+
+ /* Get PIN handling capabilities */
+ if (IOCTL_FEATURE_IFD_PIN_PROPERTIES == dwControlCode)
+ {
+ PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)RxBuffer;
+ int validation;
+
+ if (RxLength < sizeof(PIN_PROPERTIES_STRUCTURE))
+ return IFD_ERROR_INSUFFICIENT_BUFFER;
+
+ /* Only give the LCD size for now */
+ caps -> wLcdLayout = ccid_descriptor -> wLcdLayout;
+
+ /* Hardcoded special reader cases */
+ switch (ccid_descriptor->readerID)
+ {
+ case GEMPCPINPAD:
+ case VEGAALPHA:
+ case CHERRYST2000:
+ validation = 0x02; /* Validation key pressed */
+ break;
+ default:
+ validation = 0x07; /* Default */
+ }
+
+ /* Gemalto readers providing firmware features */
+ if (ccid_descriptor -> gemalto_firmware_features)
+ validation = ccid_descriptor -> gemalto_firmware_features -> bEntryValidationCondition;
+
+ caps -> bEntryValidationCondition = validation;
+ caps -> bTimeOut2 = 0x00; /* We do not distinguish bTimeOut from TimeOut2 */
+
+ *pdwBytesReturned = sizeof(*caps);
+ return_value = IFD_SUCCESS;
+ }
+
+ /* Reader features */
+ if (IOCTL_FEATURE_GET_TLV_PROPERTIES == dwControlCode)
+ {
+ int p = 0;
+ int tmp;
+
+ /* wLcdLayout */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdLayout; /* tag */
+ RxBuffer[p++] = 2; /* length */
+ tmp = ccid_descriptor -> wLcdLayout;
+ RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
+ RxBuffer[p++] = (tmp >> 8) & 0xFF;
+
+ /* only if the reader has a display */
+ if (ccid_descriptor -> wLcdLayout)
+ {
+ /* wLcdMaxCharacters */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxCharacters; /* tag */
+ RxBuffer[p++] = 2; /* length */
+ tmp = ccid_descriptor -> wLcdLayout & 0xFF;
+ RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
+ RxBuffer[p++] = (tmp >> 8) & 0xFF;
+
+ /* wLcdMaxLines */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxLines; /* tag */
+ RxBuffer[p++] = 2; /* length */
+ tmp = ccid_descriptor -> wLcdLayout >> 8;
+ RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
+ RxBuffer[p++] = (tmp >> 8) & 0xFF;
+ }
+
+ /* bTimeOut2 */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bTimeOut2;
+ RxBuffer[p++] = 1; /* length */
+ /* IFD does not distinguish bTimeOut from bTimeOut2 */
+ RxBuffer[p++] = 0x00;
+
+ /* sFirmwareID */
+ if (VENDOR_GEMALTO == GET_VENDOR(ccid_descriptor -> readerID))
+ {
+ unsigned char firmware[256];
+ const unsigned char cmd[] = { 0x02 };
+ RESPONSECODE ret;
+ unsigned int len;
+
+ len = sizeof(firmware);
+ ret = CmdEscape(reader_index, cmd, sizeof(cmd), firmware, &len, 0);
+
+ if (IFD_SUCCESS == ret)
+ {
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_sFirmwareID;
+ RxBuffer[p++] = len;
+ memcpy(&RxBuffer[p], firmware, len);
+ p += len;
+ }
+ }
+
+ /* Gemalto PC Pinpad V1 */
+ if (((GEMPCPINPAD == ccid_descriptor -> readerID)
+ && (0x0100 == ccid_descriptor -> IFD_bcdDevice))
+ /* Covadis Véga-Alpha */
+ || (VEGAALPHA == ccid_descriptor->readerID))
+ {
+ /* bMinPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 4; /* min PIN size */
+
+ /* bMaxPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 8; /* max PIN size */
+
+ /* bEntryValidationCondition */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 0x02; /* validation key pressed */
+ }
+
+ /* Cherry GmbH SmartTerminal ST-2xxx */
+ if (CHERRYST2000 == ccid_descriptor -> readerID)
+ {
+ /* bMinPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 0; /* min PIN size */
+
+ /* bMaxPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 25; /* max PIN size */
+
+ /* bEntryValidationCondition */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 0x02; /* validation key pressed */
+ }
+
+ /* Gemalto readers providing firmware features */
+ if (ccid_descriptor -> gemalto_firmware_features)
+ {
+ struct GEMALTO_FIRMWARE_FEATURES *features = ccid_descriptor -> gemalto_firmware_features;
+
+ /* bMinPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = features -> MinimumPINSize; /* min PIN size */
+
+ /* bMaxPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = features -> MaximumPINSize; /* max PIN size */
+
+ /* bEntryValidationCondition */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = features -> bEntryValidationCondition; /* validation key pressed */
+ }
+
+ /* bPPDUSupport */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bPPDUSupport;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] =
+ (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED) ? 1 : 0;
+ /* bit0: PPDU is supported over SCardControl using
+ * FEATURE_CCID_ESC_COMMAND */
+
+ /* wIdVendor */
+ {
+ int idVendor = ccid_descriptor -> readerID >> 16;
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdVendor;
+ RxBuffer[p++] = 2; /* length */
+ RxBuffer[p++] = idVendor & 0xFF;
+ RxBuffer[p++] = idVendor >> 8;
+ }
+
+ /* wIdProduct */
+ {
+ int idProduct = ccid_descriptor -> readerID & 0xFFFF;
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdProduct;
+ RxBuffer[p++] = 2; /* length */
+ RxBuffer[p++] = idProduct & 0xFF;
+ RxBuffer[p++] = idProduct >> 8;
+ }
+
+ /* dwMaxAPDUDataSize */
+ {
+ int MaxAPDUDataSize = 0; /* short APDU only by default */
+
+ /* reader is TPDU or extended APDU */
+ if ((ccid_descriptor -> dwFeatures & CCID_CLASS_EXTENDED_APDU)
+ || (ccid_descriptor -> dwFeatures & CCID_CLASS_TPDU))
+ MaxAPDUDataSize = 0x10000;
+
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize;
+ RxBuffer[p++] = 4; /* length */
+ RxBuffer[p++] = MaxAPDUDataSize & 0xFF;
+ RxBuffer[p++] = (MaxAPDUDataSize >> 8) & 0xFF;
+ RxBuffer[p++] = (MaxAPDUDataSize >> 16) & 0xFF;
+ RxBuffer[p++] = (MaxAPDUDataSize >> 24) & 0xFF;
+ }
+
+ *pdwBytesReturned = p;
+ return_value = IFD_SUCCESS;
+ }
+
+ /* Verify a PIN, plain CCID */
+ if (IOCTL_FEATURE_VERIFY_PIN_DIRECT == dwControlCode)
+ {
+ unsigned int iBytesReturned;
+
+ iBytesReturned = RxLength;
+ return_value = SecurePINVerify(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned);
+ *pdwBytesReturned = iBytesReturned;
+ }
+
+ /* Modify a PIN, plain CCID */
+ if (IOCTL_FEATURE_MODIFY_PIN_DIRECT == dwControlCode)
+ {
+ unsigned int iBytesReturned;
+
+ iBytesReturned = RxLength;
+ return_value = SecurePINModify(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned);
+ *pdwBytesReturned = iBytesReturned;
+ }
+
+ /* MCT: Multifunctional Card Terminal */
+ if (IOCTL_FEATURE_MCT_READER_DIRECT == dwControlCode)
+ {
+ if ( (TxBuffer[0] != 0x20) /* CLA */
+ || ((TxBuffer[1] & 0xF0) != 0x70) /* INS */
+ /* valid INS are
+ * 0x70: SECODER INFO
+ * 0x71: SECODER SELECT APPLICATION
+ * 0x72: SECODER APPLICATION ACTIVE
+ * 0x73: SECODER DATA CONFIRMATION
+ * 0x74: SECODER PROCESS AUTHENTICATION TOKEN */
+ || ((TxBuffer[1] & 0x0F) > 4)
+ || (TxBuffer[2] != 0x00) /* P1 */
+ || (TxBuffer[3] != 0x00) /* P2 */
+ || (TxBuffer[4] != 0x00) /* Lind */
+ )
+ {
+ DEBUG_INFO1("MCT Command refused by driver");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ {
+ unsigned int iBytesReturned;
+
+ /* we just transmit the buffer as a CCID Escape command */
+ iBytesReturned = RxLength;
+ return_value = CmdEscape(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned, 0);
+ *pdwBytesReturned = iBytesReturned;
+ }
+ }
+
+ if (IFD_SUCCESS != return_value)
+ *pdwBytesReturned = 0;
+
+ DEBUG_INFO_XXD("Control RxBuffer: ", RxBuffer, *pdwBytesReturned);
+ return return_value;
+} /* IFDHControl */
+
+
+EXTERNAL RESPONSECODE IFDHICCPresence(DWORD Lun)
+{
+ /*
+ * This function returns the status of the card inserted in the
+ * reader/slot specified by Lun. It will return either:
+ *
+ * returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
+ * IFD_COMMUNICATION_ERROR
+ */
+
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ RESPONSECODE return_value = IFD_COMMUNICATION_ERROR;
+ int oldLogLevel;
+ int reader_index;
+ _ccid_descriptor *ccid_descriptor;
+ unsigned int oldReadTimeout;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_PERIODIC3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, Lun);
+
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ if ((GEMCORESIMPRO == ccid_descriptor->readerID)
+ && (ccid_descriptor->IFD_bcdDevice < 0x0200))
+ {
+ /* GemCore SIM Pro firmware 2.00 and up features
+ * a full independant second slot */
+ return_value = ccid_descriptor->dwSlotStatus;
+ goto end;
+ }
+
+ /* save the current read timeout computed from card capabilities */
+ oldReadTimeout = ccid_descriptor->readTimeout;
+
+ /* use default timeout since the reader may not be present anymore */
+ ccid_descriptor->readTimeout = DEFAULT_COM_READ_TIMEOUT;
+
+ /* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
+ oldLogLevel = LogLevel;
+ if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
+ LogLevel &= ~DEBUG_LEVEL_COMM;
+
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+
+ /* set back the old timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+
+ /* set back the old LogLevel */
+ LogLevel = oldLogLevel;
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return_value = IFD_COMMUNICATION_ERROR;
+ switch (pcbuffer[7] & CCID_ICC_STATUS_MASK) /* bStatus */
+ {
+ case CCID_ICC_PRESENT_ACTIVE:
+ return_value = IFD_ICC_PRESENT;
+ /* use default slot */
+ break;
+
+ case CCID_ICC_PRESENT_INACTIVE:
+ if ((CcidSlots[reader_index].bPowerFlags == POWERFLAGS_RAZ)
+ || (CcidSlots[reader_index].bPowerFlags & MASK_POWERFLAGS_PDWN))
+ /* the card was previously absent */
+ return_value = IFD_ICC_PRESENT;
+ else
+ {
+ /* the card was previously present but has been
+ * removed and inserted between two consecutive
+ * IFDHICCPresence() calls */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+ return_value = IFD_ICC_NOT_PRESENT;
+ }
+ break;
+
+ case CCID_ICC_ABSENT:
+ /* Reset ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Reset PowerFlags */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+
+ return_value = IFD_ICC_NOT_PRESENT;
+ break;
+ }
+
+#if 0
+ /* SCR331-DI contactless reader */
+ if (((SCR331DI == ccid_descriptor->readerID)
+ || (SDI010 == ccid_descriptor->readerID)
+ || (SCR331DINTTCOM == ccid_descriptor->readerID))
+ && (ccid_descriptor->bCurrentSlotIndex > 0))
+ {
+ unsigned char cmd[] = { 0x11 };
+ /* command: 11 ??
+ * response: 00 11 01 ?? no card
+ * 01 04 00 ?? card present */
+
+ unsigned char res[10];
+ unsigned int length_res = sizeof(res);
+ RESPONSECODE ret;
+
+ /* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
+ oldLogLevel = LogLevel;
+ if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
+ LogLevel &= ~DEBUG_LEVEL_COMM;
+
+ ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0);
+
+ /* set back the old LogLevel */
+ LogLevel = oldLogLevel;
+
+ if (ret != IFD_SUCCESS)
+ {
+ DEBUG_INFO1("CmdEscape failed");
+ /* simulate a card absent */
+ res[0] = 0;
+ }
+
+ if (0x01 == res[0])
+ return_value = IFD_ICC_PRESENT;
+ else
+ {
+ /* Reset ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Reset PowerFlags */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+
+ return_value = IFD_ICC_NOT_PRESENT;
+ }
+ }
+#endif
+
+end:
+ DEBUG_PERIODIC2("Card %s",
+ IFD_ICC_PRESENT == return_value ? "present" : "absent");
+
+ return return_value;
+} /* IFDHICCPresence */
+
+
+CcidDesc *get_ccid_slot(unsigned int reader_index)
+{
+ return &CcidSlots[reader_index];
+} /* get_ccid_slot */
+
+
+void init_driver(void)
+{
+#ifndef UEFI_DRIVER
+ char infofile[FILENAME_MAX];
+ char *e;
+ int rv;
+ list_t plist, *values;
+
+ DEBUG_INFO1("Driver version: " VERSION);
+
+ /* Info.plist full patch filename */
+ (void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
+ PCSCLITE_HP_DROPDIR, BUNDLE);
+
+ rv = bundleParse(infofile, &plist);
+ if (0 == rv)
+ {
+ /* Log level */
+ rv = LTPBundleFindValueWithKey(&plist, "ifdLogLevel", &values);
+ if (0 == rv)
+ {
+ /* convert from hex or dec or octal */
+ LogLevel = strtoul(list_get_at(values, 0), NULL, 0);
+
+ /* print the log level used */
+ DEBUG_INFO2("LogLevel: 0x%.4X", LogLevel);
+ }
+
+ /* Driver options */
+ rv = LTPBundleFindValueWithKey(&plist, "ifdDriverOptions", &values);
+ if (0 == rv)
+ {
+ /* convert from hex or dec or octal */
+ DriverOptions = strtoul(list_get_at(values, 0), NULL, 0);
+
+ /* print the log level used */
+ DEBUG_INFO2("DriverOptions: 0x%.4X", DriverOptions);
+ }
+
+ bundleRelease(&plist);
+ }
+
+ e = getenv("LIBCCID_ifdLogLevel");
+ if (e)
+ {
+ /* convert from hex or dec or octal */
+ LogLevel = strtoul(e, NULL, 0);
+
+ /* print the log level used */
+ DEBUG_INFO2("LogLevel from LIBCCID_ifdLogLevel: 0x%.4X", LogLevel);
+ }
+
+ /* get the voltage parameter */
+ switch ((DriverOptions >> 4) & 0x03)
+ {
+ case 0:
+ PowerOnVoltage = VOLTAGE_5V;
+ break;
+
+ case 1:
+ PowerOnVoltage = VOLTAGE_3V;
+ break;
+
+ case 2:
+ PowerOnVoltage = VOLTAGE_1_8V;
+ break;
+
+ case 3:
+ PowerOnVoltage = VOLTAGE_AUTO;
+ break;
+ }
+#else
+ /* full debug */
+ LogLevel = DEBUG_LEVEL_CRITICAL | DEBUG_LEVEL_INFO | DEBUG_LEVEL_PERIODIC | DEBUG_LEVEL_COMM;
+#endif
+
+ /* initialise the Lun to reader_index mapping */
+ InitReaderIndex();
+
+ DebugInitialized = TRUE;
+} /* init_driver */
+
+
+void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol)
+{
+ /* This function use an EGT value for cards who comply with followings
+ * criterias:
+ * - TA1 > 11
+ * - current EGT = 0x00 or 0xFF
+ * - T=0 or (T=1 and CWI >= 2)
+ *
+ * Without this larger EGT some non ISO 7816-3 smart cards may not
+ * communicate with the reader.
+ *
+ * This modification is harmless, the reader will just be less restrictive
+ */
+
+ unsigned int card_baudrate;
+ unsigned int default_baudrate;
+ double f, d;
+
+ /* if TA1 not present */
+ if (! atr->ib[0][ATR_INTERFACE_BYTE_TA].present)
+ return;
+
+ (void)ATR_GetParameter(atr, ATR_PARAMETER_D, &d);
+ (void)ATR_GetParameter(atr, ATR_PARAMETER_F, &f);
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d))
+ return;
+
+ /* Baudrate = f x D/F */
+ card_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock * d / f);
+
+ default_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
+ * ATR_DEFAULT_D / ATR_DEFAULT_F);
+
+ /* TA1 > 11? */
+ if (card_baudrate <= default_baudrate)
+ return;
+
+ /* Current EGT = 0 or FF? */
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TC].present &&
+ ((0x00 == atr->ib[0][ATR_INTERFACE_BYTE_TC].value) ||
+ (0xFF == atr->ib[0][ATR_INTERFACE_BYTE_TC].value)))
+ {
+ if (SCARD_PROTOCOL_T0 == Protocol)
+ {
+ /* Init TC1 */
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].present = TRUE;
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].value = 2;
+ DEBUG_INFO1("Extra EGT patch applied");
+ }
+
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ int i;
+
+ /* TBi (i>2) present? BWI/CWI */
+ for (i=2; i<ATR_MAX_PROTOCOLS; i++)
+ {
+ /* CWI >= 2 ? */
+ if (atr->ib[i][ATR_INTERFACE_BYTE_TB].present &&
+ ((atr->ib[i][ATR_INTERFACE_BYTE_TB].value & 0x0F) >= 2))
+ {
+ /* Init TC1 */
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].present = TRUE;
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].value = 2;
+ DEBUG_INFO1("Extra EGT patch applied");
+
+ /* only the first TBi (i>2) must be used */
+ break;
+ }
+ }
+ }
+ }
+} /* extra_egt */
+
+
+static char find_baud_rate(unsigned int baudrate, unsigned int *list)
+{
+ int i;
+
+ DEBUG_COMM2("Card baud rate: %d", baudrate);
+
+ /* Does the reader support the announced smart card data speed? */
+ for (i=0;; i++)
+ {
+ /* end of array marker */
+ if (0 == list[i])
+ break;
+
+ DEBUG_COMM2("Reader can do: %d", list[i]);
+
+ /* We must take into account that the card_baudrate integral value
+ * is an approximative result, computed from the d/f float result.
+ */
+ if ((baudrate < list[i] + 2) && (baudrate > list[i] - 2))
+ return TRUE;
+ }
+
+ return FALSE;
+} /* find_baud_rate */
+
+
+static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
+ int clock_frequency)
+{
+ unsigned int timeout = DEFAULT_COM_READ_TIMEOUT;
+ double EGT, WWT;
+ unsigned int t;
+
+ /* Timeout applied on ISO_IN or ISO_OUT card exchange
+ * we choose the maximum computed value.
+ *
+ * ISO_IN timeout is the sum of:
+ * Terminal: Smart card:
+ * 5 bytes header cmd ->
+ * <- Procedure byte
+ * 256 data bytes ->
+ * <- SW1-SW2
+ * = 261 EGT + 3 WWT + 3 WWT
+ *
+ * ISO_OUT Timeout is the sum of:
+ * Terminal: Smart card:
+ * 5 bytes header cmd ->
+ * <- Procedure byte + 256 data bytes + SW1-SW2
+ * = 5 EGT + 1 WWT + 259 WWT
+ */
+
+ /* clock_frequency is in kHz so the times are in milliseconds and not
+ * in seconds */
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d) || (0 == clock_frequency))
+ return 60 * 1000; /* 60 seconds */
+
+ /* EGT */
+ /* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
+ EGT = 12 * f / d / clock_frequency + (f / d) * TC1 / clock_frequency;
+
+ /* card WWT */
+ /* see ch. 8.2 Character level, page 15 of ISO 7816-3 */
+ WWT = 960 * TC2 * f / clock_frequency;
+
+ /* ISO in */
+ t = 261 * EGT + (3 + 3) * WWT;
+ if (timeout < t)
+ timeout = t;
+
+ /* ISO out */
+ t = 5 * EGT + (1 + 259) * WWT;
+ if (timeout < t)
+ timeout = t;
+
+ return timeout;
+} /* T0_card_timeout */
+
+
+static unsigned int T1_card_timeout(double f, double d, int TC1,
+ int BWI, int CWI, int clock_frequency)
+{
+ double EGT, BWT, CWT, etu;
+ unsigned int timeout;
+
+ /* Timeout applied on ISO in + ISO out card exchange
+ *
+ * Timeout is the sum of:
+ * - ISO in delay between leading edge of the first character sent by the
+ * interface device and the last one (NAD PCB LN APDU CKS) = 260 EGT,
+ * - delay between ISO in and ISO out = BWT,
+ * - ISO out delay between leading edge of the first character sent by the
+ * card and the last one (NAD PCB LN DATAS CKS) = 260 CWT.
+ */
+
+ /* clock_frequency is in kHz so the times are in milliseconds and not
+ * in seconds */
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d) || (0 == clock_frequency))
+ return 60 * 1000; /* 60 seconds */
+
+ /* see ch. 6.5.2 Transmission factors F and D, page 12 of ISO 7816-3 */
+ etu = f / d / clock_frequency;
+
+ /* EGT */
+ /* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
+ EGT = 12 * etu + (f / d) * TC1 / clock_frequency;
+
+ /* card BWT */
+ /* see ch. 9.5.3.2 Block Waiting Time, page 20 of ISO 7816-3 */
+ BWT = 11 * etu + (1<<BWI) * 960 * 372 / clock_frequency;
+
+ /* card CWT */
+ /* see ch. 9.5.3.1 Caracter Waiting Time, page 20 of ISO 7816-3 */
+ CWT = (11 + (1<<CWI)) * etu;
+
+ timeout = 260*EGT + BWT + 260*CWT;
+
+ /* This is the card/reader timeout. Add 1 second for the libusb
+ * timeout so we get the error from the reader. */
+ timeout += 1000;
+
+ return timeout;
+} /* T1_card_timeout */
+
+
+static int get_IFSC(ATR_t *atr, int *idx)
+{
+ int i, ifsc, protocol = -1;
+
+ /* default return values */
+ ifsc = -1;
+ *idx = -1;
+
+ for (i=0; i<ATR_MAX_PROTOCOLS; i++)
+ {
+ /* TAi (i>2) present and protocol=1 => IFSC */
+ if (i >= 2 && protocol == 1
+ && atr->ib[i][ATR_INTERFACE_BYTE_TA].present)
+ {
+ ifsc = atr->ib[i][ATR_INTERFACE_BYTE_TA].value;
+ *idx = i+1;
+ /* only the first TAi (i>2) must be used */
+ break;
+ }
+
+ /* protocol T=? */
+ if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present)
+ protocol = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F;
+ }
+
+ if (ifsc > 254)
+ {
+ /* 0xFF is not a valid value for IFSC */
+ DEBUG_INFO2("Non ISO IFSC: 0x%X", ifsc);
+ ifsc = 254;
+ }
+
+ return ifsc;
+} /* get_IFSC */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE b/MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
new file mode 100644
index 0000000..2b5c118
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
@@ -0,0 +1,28 @@
+OpenCT, a middleware framework for smart card terminals.
+
+Copyright (c) 2003, Olaf Kirch <***@suse.de>
+Copyright (c) 2003, Andreas Jellinghaus <***@dungeon.inka.de>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the authors nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/README b/MdeModulePkg/Library/SmartCardReader/libccid/openct/README
new file mode 100644
index 0000000..77d79b0
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/README
@@ -0,0 +1,7 @@
+The files buffer.[c|h], checksum.c and proto-t1.c comes from the OpenCT
+project <http://www.opensc.org/>
+
+I (Ludovic Rousseau) greatly patched proto-t1.c to add all the needed
+code to reach the quality level requested by the EMV standard.
+
+$Id: README 1021 2004-07-02 12:06:44Z rousseau $
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
new file mode 100644
index 0000000..db98684
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
@@ -0,0 +1,73 @@
+/*
+ * Buffer handling functions
+ *
+ * Copyright (C) 2003, Olaf Kirch <***@suse.de>
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <openct/buffer.h>
+
+void
+ct_buf_init(ct_buf_t *bp, void *mem, size_t len)
+{
+ memset(bp, 0, sizeof(*bp));
+ bp->base = (unsigned char *) mem;
+ bp->size = len;
+}
+
+void
+ct_buf_set(ct_buf_t *bp, void *mem, size_t len)
+{
+ ct_buf_init(bp, mem, len);
+ bp->tail = len;
+}
+
+int
+ct_buf_get(ct_buf_t *bp, void *mem, size_t len)
+{
+ if (len > bp->tail - bp->head)
+ return -1;
+ if (mem)
+ memcpy(mem, bp->base + bp->head, len);
+ bp->head += len;
+ return len;
+}
+
+int
+ct_buf_put(ct_buf_t *bp, const void *mem, size_t len)
+{
+ if (len > bp->size - bp->tail) {
+ bp->overrun = 1;
+ return -1;
+ }
+ if (mem)
+ memcpy(bp->base + bp->tail, mem, len);
+ bp->tail += len;
+ return len;
+}
+
+int
+ct_buf_putc(ct_buf_t *bp, int byte)
+{
+ unsigned char c = byte;
+
+ return ct_buf_put(bp, &c, 1);
+}
+
+unsigned int
+ct_buf_avail(ct_buf_t *bp)
+{
+ return bp->tail - bp->head;
+}
+
+void *
+ct_buf_head(ct_buf_t *bp)
+{
+ return bp->base + bp->head;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
new file mode 100644
index 0000000..c05e470
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
@@ -0,0 +1,36 @@
+/*
+ * Buffer handling functions of the IFD handler library
+ *
+ * Copyright (C) 2003, Olaf Kirch <***@suse.de>
+ */
+
+#ifndef OPENCT_BUFFER_H
+#define OPENCT_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+typedef struct ct_buf {
+ unsigned char * base;
+ unsigned int head, tail, size;
+ unsigned int overrun;
+} ct_buf_t;
+
+extern void ct_buf_init(ct_buf_t *, void *, size_t);
+extern void ct_buf_set(ct_buf_t *, void *, size_t);
+extern int ct_buf_get(ct_buf_t *, void *, size_t);
+extern int ct_buf_put(ct_buf_t *, const void *, size_t);
+extern int ct_buf_putc(ct_buf_t *, int);
+extern unsigned int ct_buf_avail(ct_buf_t *);
+extern void * ct_buf_head(ct_buf_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPENCT_BUFFER_H */
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
new file mode 100644
index 0000000..744d910
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
@@ -0,0 +1,95 @@
+/*
+ * Checksum handling
+ *
+ * Copyright Matthias Bruestle 1999-2002
+ * For licensing, see the file LICENCE
+ */
+
+#include <config.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include "checksum.h"
+
+#define min( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
+
+/* ISO STD 3309 */
+/* From: ***@catbyte.b30.ingr.com (Dave Medin)
+ * Subject: CCITT checksums
+ * Newsgroups: sci.electronics
+ * Date: Mon, 7 Dec 1992 17:33:39 GMT
+ */
+
+/* Correct Table? */
+
+static unsigned short crctab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*
+ * Returns LRC of data.
+ */
+unsigned int
+csum_lrc_compute(const uint8_t *in, size_t len, unsigned char *rc)
+{
+ unsigned char lrc = 0;
+
+ while (len--)
+ lrc ^= *in++;
+
+ if (rc)
+ *rc = lrc;
+ return 1;
+}
+
+/*
+ * Compute CRC of data.
+ */
+unsigned int
+csum_crc_compute(const uint8_t * data, size_t len, unsigned char *rc)
+{
+ unsigned short v = 0xFFFF;
+
+ while (len--) {
+ v = ((v >> 8) & 0xFF) ^ crctab[(v ^ *data++) & 0xFF];
+ }
+
+ if (rc) {
+ rc[0] = (v >> 8) & 0xFF;
+ rc[1] = v & 0xFF;
+ }
+
+ return 2;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
new file mode 100644
index 0000000..68445f0
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
@@ -0,0 +1,37 @@
+/*
+ proto-t1.h: header file for proto-t1.c
+ Copyright (C) 2004 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* $Id: checksum.h 6975 2014-09-04 11:33:05Z rousseau $ */
+
+#ifndef __CHECKSUM_H__
+#define __CHECKSUM_H__
+
+#include <config.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern unsigned int csum_lrc_compute(const uint8_t *, size_t, unsigned char *);
+extern unsigned int csum_crc_compute(const uint8_t *, size_t, unsigned char *);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
new file mode 100644
index 0000000..912a1b5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
@@ -0,0 +1,800 @@
+/*
+ * Implementation of T=1
+ *
+ * Copyright (C) 2003, Olaf Kirch <***@suse.de>
+ *
+ * improvements by:
+ * Copyright (C) 2004 Ludovic Rousseau <***@free.fr>
+ */
+
+#include <config.h>
+
+#include <pcsclite.h>
+#include <ifdhandler.h>
+#include "commands.h"
+#include "buffer.h"
+#include "debug.h"
+#include "proto-t1.h"
+#include "checksum.h"
+
+#include "ccid.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+/* I block */
+#define T1_I_SEQ_SHIFT 6
+
+/* R block */
+#define T1_IS_ERROR(pcb) ((pcb) & 0x0F)
+#define T1_EDC_ERROR 0x01
+#define T1_OTHER_ERROR 0x02
+#define T1_R_SEQ_SHIFT 4
+
+/* S block stuff */
+#define T1_S_IS_RESPONSE(pcb) ((pcb) & T1_S_RESPONSE)
+#define T1_S_TYPE(pcb) ((pcb) & 0x0F)
+#define T1_S_RESPONSE 0x20
+#define T1_S_RESYNC 0x00
+#define T1_S_IFS 0x01
+#define T1_S_ABORT 0x02
+#define T1_S_WTX 0x03
+
+#define swap_nibbles(x) ( (x >> 4) | ((x & 0xF) << 4) )
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define NAD 0
+#define PCB 1
+#define LEN 2
+#define DATA 3
+
+/* internal state, do not mess with it. */
+/* should be != DEAD after reset/init */
+enum {
+ SENDING, RECEIVING, RESYNCH, DEAD
+};
+
+static void t1_set_checksum(t1_state_t *, int);
+static unsigned int t1_block_type(unsigned char);
+static unsigned int t1_seq(unsigned char);
+static unsigned int t1_rebuild(t1_state_t *t1, unsigned char *block);
+static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
+static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
+static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
+
+/*
+ * Set default T=1 protocol parameters
+ */
+static void t1_set_defaults(t1_state_t * t1)
+{
+ t1->retries = 3;
+ /* This timeout is rather insane, but we need this right now
+ * to support cryptoflex keygen */
+ t1->ifsc = 32;
+ t1->ifsd = 32;
+ t1->nr = 0;
+ t1->ns = 0;
+ t1->wtx = 0;
+}
+
+static void t1_set_checksum(t1_state_t * t1, int csum)
+{
+ switch (csum) {
+ case IFD_PROTOCOL_T1_CHECKSUM_LRC:
+ t1->rc_bytes = 1;
+ t1->checksum = csum_lrc_compute;
+ break;
+ case IFD_PROTOCOL_T1_CHECKSUM_CRC:
+ t1->rc_bytes = 2;
+ t1->checksum = csum_crc_compute;
+ break;
+ }
+}
+
+/*
+ * Attach t1 protocol
+ */
+int t1_init(t1_state_t * t1, int lun)
+{
+ t1_set_defaults(t1);
+ t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
+ t1_set_param(t1, IFD_PROTOCOL_T1_STATE, SENDING);
+ t1_set_param(t1, IFD_PROTOCOL_T1_MORE, FALSE);
+
+ t1->lun = lun;
+
+ return 0;
+}
+
+/*
+ * Detach t1 protocol
+ */
+void t1_release(/*@unused@*/ t1_state_t * t1)
+{
+ (void)t1;
+ /* NOP */
+}
+
+/*
+ * Get/set parmaters for T1 protocol
+ */
+int t1_set_param(t1_state_t * t1, int type, long value)
+{
+ switch (type) {
+ case IFD_PROTOCOL_T1_CHECKSUM_LRC:
+ case IFD_PROTOCOL_T1_CHECKSUM_CRC:
+ t1_set_checksum(t1, type);
+ break;
+ case IFD_PROTOCOL_T1_IFSC:
+ t1->ifsc = value;
+ break;
+ case IFD_PROTOCOL_T1_IFSD:
+ t1->ifsd = value;
+ break;
+ case IFD_PROTOCOL_T1_STATE:
+ t1->state = value;
+ break;
+ case IFD_PROTOCOL_T1_MORE:
+ t1->more = value;
+ break;
+ default:
+ DEBUG_INFO2("Unsupported parameter %d", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Send an APDU through T=1
+ */
+int t1_transceive(t1_state_t * t1, unsigned int dad,
+ const void *snd_buf, size_t snd_len,
+ void *rcv_buf, size_t rcv_len)
+{
+ ct_buf_t sbuf, rbuf, tbuf;
+ unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
+ unsigned int slen, retries, resyncs;
+ size_t last_send = 0;
+
+ if (snd_len == 0)
+ return -1;
+
+ /* we can't talk to a dead card / reader. Reset it! */
+ if (t1->state == DEAD)
+ {
+ DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card first.");
+ return -1;
+ }
+
+ t1->state = SENDING;
+ retries = t1->retries;
+ resyncs = 3;
+
+ /* Initialize send/recv buffer */
+ ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
+ ct_buf_init(&rbuf, rcv_buf, rcv_len);
+
+ /* Send the first block */
+ slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);
+
+ while (1) {
+ unsigned char pcb;
+ int n;
+
+ retries--;
+
+ n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+ if (-2 == n)
+ {
+ DEBUG_COMM("Parity error");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_EDC_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (n < 0) {
+ DEBUG_CRITICAL("fatal: transmit/receive failed");
+ t1->state = DEAD;
+ goto error;
+ }
+
+ if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+ || (sdata[LEN] == 0xFF)) /* length == 0xFF (illegal) */
+ {
+ DEBUG_COMM("R-BLOCK required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (!t1_verify_checksum(t1, sdata, n)) {
+ DEBUG_COMM("checksum failed");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_EDC_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ pcb = sdata[PCB];
+ switch (t1_block_type(pcb)) {
+ case T1_R_BLOCK:
+ if ((sdata[LEN] != 0x00) /* length != 0x00 (illegal) */
+ || (pcb & 0x20) /* b6 of pcb is set */
+ )
+ {
+ DEBUG_COMM("R-Block required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (((t1_seq(pcb) != t1->ns) /* wrong sequence number & no bit more */
+ && ! t1->more)
+ )
+ {
+ DEBUG_COMM4("received: %d, expected: %d, more: %d",
+ t1_seq(pcb), t1->ns, t1->more);
+
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_COMM("R-Block required");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (t1->state == RECEIVING) {
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
+ {
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_COMM("");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK,
+ NULL, NULL);
+ break;
+ }
+
+ /* If the card terminal requests the next
+ * sequence number, it received the previous
+ * block successfully */
+ if (t1_seq(pcb) != t1->ns) {
+ ct_buf_get(&sbuf, NULL, last_send);
+ last_send = 0;
+ t1->ns ^= 1;
+ }
+
+ /* If there's no data available, the ICC
+ * shouldn't be asking for more */
+ if (ct_buf_avail(&sbuf) == 0)
+ goto resync;
+
+ slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
+ &sbuf, &last_send);
+ break;
+
+ case T1_I_BLOCK:
+ /* The first I-block sent by the ICC indicates
+ * the last block we sent was received successfully. */
+ if (t1->state == SENDING) {
+ DEBUG_COMM("");
+ ct_buf_get(&sbuf, NULL, last_send);
+ last_send = 0;
+ t1->ns ^= 1;
+ }
+
+ t1->state = RECEIVING;
+
+ /* If the block sent by the card doesn't match
+ * what we expected it to send, reply with
+ * an R block */
+ if (t1_seq(pcb) != t1->nr) {
+ DEBUG_COMM("wrong nr");
+
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ t1->nr ^= 1;
+
+ if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
+ {
+ DEBUG_CRITICAL2("buffer overrun by %d bytes", sdata[LEN] - (rbuf.size - rbuf.tail));
+ goto error;
+ }
+
+ if ((pcb & T1_MORE_BLOCKS) == 0)
+ goto done;
+
+ slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
+ break;
+
+ case T1_S_BLOCK:
+ if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
+ /* ISO 7816-3 Rule 6.2 */
+ DEBUG_COMM("S-Block answer received");
+ /* ISO 7816-3 Rule 6.3 */
+ t1->state = SENDING;
+ last_send = 0;
+ resyncs = 3;
+ retries = t1->retries;
+ ct_buf_init(&rbuf, rcv_buf, rcv_len);
+ slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
+ &sbuf, &last_send);
+ continue;
+ }
+
+ if (T1_S_IS_RESPONSE(pcb))
+ {
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_CRITICAL("wrong response S-BLOCK received");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ ct_buf_init(&tbuf, sblk, sizeof(sblk));
+
+ DEBUG_COMM("S-Block request received");
+ switch (T1_S_TYPE(pcb)) {
+ case T1_S_RESYNC:
+ if (sdata[LEN] != 0)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_COMM("Resync requested");
+ /* the card is not allowed to send a resync. */
+ goto resync;
+
+ case T1_S_ABORT:
+ if (sdata[LEN] != 0)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ /* ISO 7816-3 Rule 9 */
+ DEBUG_CRITICAL("abort requested");
+ break;
+
+ case T1_S_IFS:
+ if (sdata[LEN] != 1)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_CRITICAL2("CT sent S-block with ifs=%u", sdata[DATA]);
+ if (sdata[DATA] == 0)
+ goto resync;
+ t1->ifsc = sdata[DATA];
+ ct_buf_putc(&tbuf, sdata[DATA]);
+ break;
+
+ case T1_S_WTX:
+ if (sdata[LEN] != 1)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
+ t1->wtx = sdata[DATA];
+ ct_buf_putc(&tbuf, sdata[DATA]);
+ break;
+
+ default:
+ DEBUG_CRITICAL2("T=1: Unknown S block type 0x%02x", T1_S_TYPE(pcb));
+ goto resync;
+ }
+
+ slen = t1_build(t1, sdata, dad,
+ T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
+ &tbuf, NULL);
+ }
+
+ /* Everything went just splendid */
+ retries = t1->retries;
+ continue;
+
+resync:
+ /* the number or resyncs is limited, too */
+ /* ISO 7816-3 Rule 6.4 */
+ if (resyncs == 0)
+ goto error;
+
+ /* ISO 7816-3 Rule 6 */
+ resyncs--;
+ t1->ns = 0;
+ t1->nr = 0;
+ slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
+ NULL);
+ t1->state = RESYNCH;
+ t1->more = FALSE;
+ retries = 1;
+ continue;
+ }
+
+done:
+ return ct_buf_avail(&rbuf);
+
+error:
+ t1->state = DEAD;
+ return -1;
+}
+
+static unsigned t1_block_type(unsigned char pcb)
+{
+ switch (pcb & 0xC0) {
+ case T1_R_BLOCK:
+ return T1_R_BLOCK;
+ case T1_S_BLOCK:
+ return T1_S_BLOCK;
+ default:
+ return T1_I_BLOCK;
+ }
+}
+
+static unsigned int t1_seq(unsigned char pcb)
+{
+ switch (pcb & 0xC0) {
+ case T1_R_BLOCK:
+ return (pcb >> T1_R_SEQ_SHIFT) & 1;
+ case T1_S_BLOCK:
+ return 0;
+ default:
+ return (pcb >> T1_I_SEQ_SHIFT) & 1;
+ }
+}
+
+unsigned int t1_build(t1_state_t * t1, unsigned char *block,
+ unsigned char dad, unsigned char pcb,
+ ct_buf_t *bp, size_t *lenp)
+{
+ unsigned int len;
+ char more = FALSE;
+
+ len = bp ? ct_buf_avail(bp) : 0;
+ if (len > t1->ifsc) {
+ pcb |= T1_MORE_BLOCKS;
+ len = t1->ifsc;
+ more = TRUE;
+ }
+
+ /* Add the sequence number */
+ switch (t1_block_type(pcb)) {
+ case T1_R_BLOCK:
+ pcb |= t1->nr << T1_R_SEQ_SHIFT;
+ break;
+ case T1_I_BLOCK:
+ pcb |= t1->ns << T1_I_SEQ_SHIFT;
+ t1->more = more;
+ DEBUG_COMM2("more bit: %d", more);
+ break;
+ }
+
+ block[0] = dad;
+ block[1] = pcb;
+ block[2] = len;
+
+ if (len)
+ memcpy(block + 3, ct_buf_head(bp), len);
+ if (lenp)
+ *lenp = len;
+
+ len = t1_compute_checksum(t1, block, len + 3);
+
+ /* memorize the last sent block */
+ /* only 4 bytes since we are only interesed in R-blocks */
+ memcpy(t1->previous_block, block, 4);
+
+ return len;
+}
+
+static unsigned int
+t1_rebuild(t1_state_t *t1, unsigned char *block)
+{
+ unsigned char pcb = t1 -> previous_block[1];
+
+ /* copy the last sent block */
+ if (T1_R_BLOCK == t1_block_type(pcb))
+ memcpy(block, t1 -> previous_block, 4);
+ else
+ {
+ DEBUG_CRITICAL2("previous block was not R-Block: %02X", pcb);
+ return 0;
+ }
+
+ return 4;
+}
+
+/*
+ * Build/verify checksum
+ */
+static unsigned int t1_compute_checksum(t1_state_t * t1,
+ unsigned char *data, size_t len)
+{
+ return len + t1->checksum(data, len, data + len);
+}
+
+static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf,
+ size_t len)
+{
+ unsigned char csum[2];
+ int m, n;
+
+ m = len - t1->rc_bytes;
+ n = t1->rc_bytes;
+
+ if (m < 0)
+ return 0;
+
+ t1->checksum(rbuf, m, csum);
+ if (!memcmp(rbuf + m, csum, n))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Send/receive block
+ */
+static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
+ size_t rmax)
+{
+ int n;
+ _ccid_descriptor *ccid_desc ;
+ int oldReadTimeout;
+ unsigned int rmax_int;
+
+ DEBUG_XXD("sending: ", block, slen);
+
+ ccid_desc = get_ccid_descriptor(t1->lun);
+ oldReadTimeout = ccid_desc->readTimeout;
+
+ if (t1->wtx > 1)
+ {
+ /* set the new temporary timeout at WTX card request */
+ ccid_desc->readTimeout *= t1->wtx;
+ DEBUG_INFO2("New timeout at WTX request: %d sec",
+ ccid_desc->readTimeout);
+ }
+
+ if (isCharLevel(t1->lun))
+ {
+ rmax = 3;
+
+ n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx);
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ /* the second argument of CCID_Receive() is (unsigned int *)
+ * so we can't use &rmax since &rmax is a (size_t *) and may not
+ * be the same on 64-bits architectures for example (iMac G5) */
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
+
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ rmax = block[2] + 1;
+
+ n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx);
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL);
+ rmax = rmax_int;
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ n = rmax + 3;
+ }
+ else
+ {
+ n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx);
+ t1->wtx = 0; /* reset to default value */
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ /* Get the response en bloc */
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
+ rmax = rmax_int;
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ n = rmax;
+ }
+
+ if (n >= 0)
+ {
+ int m;
+
+ m = block[2] + 3 + t1->rc_bytes;
+ if (m < n)
+ n = m;
+ }
+
+ if (n >= 0)
+ DEBUG_XXD("received: ", block, n);
+
+ /* Restore initial timeout */
+ ccid_desc->readTimeout = oldReadTimeout;
+
+ return n;
+}
+
+int t1_negotiate_ifsd(t1_state_t * t1, unsigned int dad, int ifsd)
+{
+ ct_buf_t sbuf;
+ unsigned char sdata[T1_BUFFER_SIZE];
+ unsigned int slen;
+ unsigned int retries;
+ size_t snd_len;
+ int n;
+ unsigned char snd_buf[1];
+
+ retries = t1->retries;
+
+ /* S-block IFSD request */
+ snd_buf[0] = ifsd;
+ snd_len = 1;
+
+ /* Initialize send/recv buffer */
+ ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
+
+ while (TRUE)
+ {
+ /* Build the block */
+ slen = t1_build(t1, sdata, 0, T1_S_BLOCK | T1_S_IFS, &sbuf, NULL);
+
+ /* Send the block */
+ n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+
+ retries--;
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto error;
+
+ if (-1 == n)
+ {
+ DEBUG_CRITICAL("fatal: transmit/receive failed");
+ goto error;
+ }
+
+ if ((-2 == n) /* Parity error */
+ || (sdata[DATA] != ifsd) /* Wrong ifsd received */
+ || (sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+ || (!t1_verify_checksum(t1, sdata, n)) /* checksum failed */
+ || (n != 4 + (int)t1->rc_bytes) /* wrong frame length */
+ || (sdata[LEN] != 1) /* wrong data length */
+ || (sdata[PCB] != (T1_S_BLOCK | T1_S_RESPONSE | T1_S_IFS))) /* wrong PCB */
+ continue;
+
+ /* no more error */
+ goto done;
+ }
+
+done:
+ return n;
+
+error:
+ t1->state = DEAD;
+ return -1;
+}
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
new file mode 100644
index 0000000..a4732ed
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
@@ -0,0 +1,85 @@
+/*
+ proto-t1.h: header file for proto-t1.c
+ Copyright (C) 2004 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* $Id: proto-t1.h 6975 2014-09-04 11:33:05Z rousseau $ */
+
+#ifndef __PROTO_T1_H__
+#define __PROTO_T1_H__
+
+#include <config.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "buffer.h"
+
+/* T=1 protocol constants */
+#define T1_I_BLOCK 0x00
+#define T1_R_BLOCK 0x80
+#define T1_S_BLOCK 0xC0
+#define T1_MORE_BLOCKS 0x20
+
+enum {
+ IFD_PROTOCOL_RECV_TIMEOUT = 0x0000,
+ IFD_PROTOCOL_T1_BLOCKSIZE,
+ IFD_PROTOCOL_T1_CHECKSUM_CRC,
+ IFD_PROTOCOL_T1_CHECKSUM_LRC,
+ IFD_PROTOCOL_T1_IFSC,
+ IFD_PROTOCOL_T1_IFSD,
+ IFD_PROTOCOL_T1_STATE,
+ IFD_PROTOCOL_T1_MORE
+};
+
+#define T1_BUFFER_SIZE (3 + 254 + 2)
+
+/* see /usr/include/PCSC/ifdhandler.h for other values
+ * this one is for internal use only */
+#define IFD_PARITY_ERROR 699
+
+typedef struct {
+ int lun;
+ int state;
+
+ unsigned char ns; /* reader side */
+ unsigned char nr; /* card side */
+ unsigned int ifsc;
+ unsigned int ifsd;
+
+ unsigned char wtx;
+ unsigned int retries;
+ unsigned int rc_bytes;
+
+ unsigned int (*checksum)(const uint8_t *, size_t, unsigned char *);
+
+ char more; /* more data bit */
+ unsigned char previous_block[4]; /* to store the last R-block */
+} t1_state_t;
+
+int t1_transceive(t1_state_t *t1, unsigned int dad,
+ const void *snd_buf, size_t snd_len,
+ void *rcv_buf, size_t rcv_len);
+int t1_init(t1_state_t *t1, int lun);
+void t1_release(t1_state_t *t1);
+int t1_set_param(t1_state_t *t1, int type, long value);
+int t1_negotiate_ifsd(t1_state_t *t1, unsigned int dad, int ifsd);
+unsigned int t1_build(t1_state_t *, unsigned char *,
+ unsigned char, unsigned char, ct_buf_t *, size_t *);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
new file mode 100644
index 0000000..68dc4c5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
@@ -0,0 +1,505 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
new file mode 100644
index 0000000..49c38bc
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
@@ -0,0 +1,14 @@
+All the files in the src/protocol_t1/ directory comes from Carlos
+Prados Towitoko smartcard readers driver.
+
+I (Ludovic Rousseau) hacked the source files a bit to include them in my
+CCID driver. So bugs are mine and not Carlos' fault. As indicated in
+the source files headers this code is protected by the GNU Lesser
+General Public License.
+
+I used version 2.0.7 of Carlos driver available at
+http://www.geocities.com/cprados/
+
+I added the function ATR_GetDefaultProtocol() in towitoko/atr.c
+
+$Id: README 1001 2004-06-30 13:49:38Z rousseau $
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
new file mode 100644
index 0000000..6968a5c
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
@@ -0,0 +1,365 @@
+/*
+ atr.c
+ ISO 7816 ICC's answer to reset abstract data type implementation
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 Carlos Prados <***@yahoo.com>
+
+ 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <config.h>
+
+#include "atr.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "debug.h"
+
+/*
+ * Not exported variables definition
+ */
+
+static unsigned
+atr_num_ib_table[16] =
+{
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+
+/*
+ * Exported variables definition
+ */
+
+static unsigned
+atr_f_table[16] =
+{
+ 372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768, 1024, 1536, 2048, 0, 0
+};
+
+static unsigned
+atr_d_table[16] =
+{
+ 0, 1, 2, 4, 8, 16, 32, 64, 12, 20, 0, 0, 0, 0, 0, 0
+};
+
+static unsigned
+atr_i_table[4] =
+{
+ 25, 50, 100, 0
+};
+
+/*
+ * Exported functions definition
+ */
+
+int
+ATR_InitFromArray (ATR_t * atr, const BYTE atr_buffer[ATR_MAX_SIZE], unsigned length)
+{
+ BYTE TDi;
+ unsigned pointer = 0, pn = 0;
+
+ /* Check size of buffer */
+ if (length < 2)
+ return (ATR_MALFORMED);
+
+ /* Store T0 and TS */
+ atr->TS = atr_buffer[0];
+
+ atr->T0 = TDi = atr_buffer[1];
+ pointer = 1;
+
+ /* Store number of historical bytes */
+ atr->hbn = TDi & 0x0F;
+
+ /* TCK is not present by default */
+ (atr->TCK).present = FALSE;
+
+ /* Extract interface bytes */
+ while (pointer < length)
+ {
+ /* Check buffer is long enought */
+ if (pointer + atr_num_ib_table[(0xF0 & TDi) >> 4] >= length)
+ {
+ return (ATR_MALFORMED);
+ }
+ /* Check TAi is present */
+ if ((TDi | 0xEF) == 0xFF)
+ {
+ pointer++;
+ atr->ib[pn][ATR_INTERFACE_BYTE_TA].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TA].present = TRUE;
+ }
+ else
+ atr->ib[pn][ATR_INTERFACE_BYTE_TA].present = FALSE;
+ /* Check TBi is present */
+ if ((TDi | 0xDF) == 0xFF)
+ {
+ pointer++;
+ atr->ib[pn][ATR_INTERFACE_BYTE_TB].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TB].present = TRUE;
+ }
+ else
+ atr->ib[pn][ATR_INTERFACE_BYTE_TB].present = FALSE;
+
+ /* Check TCi is present */
+ if ((TDi | 0xBF) == 0xFF)
+ {
+ pointer++;
+ atr->ib[pn][ATR_INTERFACE_BYTE_TC].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TC].present = TRUE;
+ }
+ else
+ atr->ib[pn][ATR_INTERFACE_BYTE_TC].present = FALSE;
+
+ /* Read TDi if present */
+ if ((TDi | 0x7F) == 0xFF)
+ {
+ pointer++;
+ TDi = atr->ib[pn][ATR_INTERFACE_BYTE_TD].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TD].present = TRUE;
+ (atr->TCK).present = ((TDi & 0x0F) != ATR_PROTOCOL_TYPE_T0);
+ pn++;
+ if (pn >= ATR_MAX_PROTOCOLS)
+ return (ATR_MALFORMED);
+ }
+ else
+ {
+ atr->ib[pn][ATR_INTERFACE_BYTE_TD].present = FALSE;
+ break;
+ }
+ }
+
+ /* Store number of protocols */
+ atr->pn = pn + 1;
+
+ /* Store historical bytes */
+ if (pointer + atr->hbn >= length)
+ return (ATR_MALFORMED);
+
+ memcpy (atr->hb, atr_buffer + pointer + 1, atr->hbn);
+ pointer += (atr->hbn);
+
+ /* Store TCK */
+ if ((atr->TCK).present)
+ {
+
+ if (pointer + 1 >= length)
+ return (ATR_MALFORMED);
+
+ pointer++;
+
+ (atr->TCK).value = atr_buffer[pointer];
+ }
+
+ atr->length = pointer + 1;
+ return (ATR_OK);
+}
+
+int
+ATR_GetConvention (ATR_t * atr, int *convention)
+{
+ if (atr->TS == 0x3B)
+ (*convention) = ATR_CONVENTION_DIRECT;
+ else if (atr->TS == 0x3F)
+ (*convention) = ATR_CONVENTION_INVERSE;
+ else
+ return (ATR_MALFORMED);
+ return (ATR_OK);
+}
+
+int
+ATR_GetIntegerValue (ATR_t * atr, int name, BYTE * value)
+{
+ int ret;
+
+ if (name == ATR_INTEGER_VALUE_FI)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TA].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TA].value & 0xF0) >> 4;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_DI)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TA].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TA].value & 0x0F);
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_II)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TB].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TB].value & 0x60) >> 5;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_PI1)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TB].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TB].value & 0x1F);
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_PI2)
+ {
+ if (atr->ib[1][ATR_INTERFACE_BYTE_TB].present)
+ {
+ (*value) = atr->ib[1][ATR_INTERFACE_BYTE_TB].value;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_N)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TC].present)
+ {
+ (*value) = atr->ib[0][ATR_INTERFACE_BYTE_TC].value;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+
+ return ret;
+}
+
+int
+ATR_GetParameter (ATR_t * atr, int name, double *parameter)
+{
+ BYTE FI, DI, II, PI1, PI2, N;
+
+ if (name == ATR_PARAMETER_F)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_FI, &FI) == ATR_OK)
+ (*parameter) = (double) (atr_f_table[FI]);
+ else
+ (*parameter) = (double) ATR_DEFAULT_F;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_D)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_DI, &DI) == ATR_OK)
+ (*parameter) = (double) (atr_d_table[DI]);
+ else
+ (*parameter) = (double) ATR_DEFAULT_D;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_I)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_II, &II) == ATR_OK)
+ (*parameter) = (double) (atr_i_table[II]);
+ else
+ (*parameter) = ATR_DEFAULT_I;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_P)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_PI2, &PI2) == ATR_OK)
+ (*parameter) = (double) PI2;
+ else if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_PI1, &PI1) == ATR_OK)
+ (*parameter) = (double) PI1;
+ else
+ (*parameter) = (double) ATR_DEFAULT_P;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_N)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_N, &N) == ATR_OK)
+ (*parameter) = (double) N;
+ else
+ (*parameter) = (double) ATR_DEFAULT_N;
+ return (ATR_OK);
+ }
+
+ return (ATR_NOT_FOUND);
+}
+
+/*
+ * This function was greatly inspired by ATRDecodeAtr() and
+ * PHGetDefaultProtocol() from pcsc-lite
+ *
+ * It was rewritten by Ludovic Rousseau, 2004
+ */
+#define PROTOCOL_UNSET -1
+int ATR_GetDefaultProtocol(ATR_t * atr, int *protocol, int *availableProtocols)
+{
+ int i;
+
+ /* default value */
+ *protocol = PROTOCOL_UNSET;
+ if (availableProtocols)
+ *availableProtocols = 0;
+
+ for (i=0; i<ATR_MAX_PROTOCOLS; i++)
+ if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present)
+ {
+ int T = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F;
+
+ DEBUG_COMM2("T=%d Protocol Found", T);
+ if (availableProtocols)
+ *availableProtocols |= 1 << T;
+
+ if (PROTOCOL_UNSET == *protocol)
+ {
+ /* set to the first protocol byte found */
+ *protocol = T;
+ DEBUG_COMM2("default protocol: T=%d", *protocol);
+ }
+ }
+
+ /* specific mode if TA2 present */
+ if (atr->ib[1][ATR_INTERFACE_BYTE_TA].present)
+ {
+ *protocol = atr->ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F;
+ if (availableProtocols)
+ *availableProtocols = 1 << *protocol;
+ DEBUG_COMM2("specific mode found: T=%d", *protocol);
+ }
+
+ if (PROTOCOL_UNSET == *protocol)
+ {
+ DEBUG_INFO1("no default protocol found in ATR. Using T=0");
+ *protocol = ATR_PROTOCOL_TYPE_T0;
+ if (availableProtocols)
+ *availableProtocols = 1 << *protocol;
+ }
+
+ return ATR_OK;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
new file mode 100644
index 0000000..23207f6
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
@@ -0,0 +1,111 @@
+/*
+ atr.h
+ ISO 7816 ICC's answer to reset abstract data type definitions
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 Carlos Prados <***@yahoo.com>
+
+ 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef _ATR_
+#define _ATR_
+
+#include "defines.h"
+
+/*
+ * Exported constants definition
+ */
+
+/* Return values */
+#define ATR_OK 0 /* ATR could be parsed and data returned */
+#define ATR_NOT_FOUND 1 /* Data not present in ATR */
+#define ATR_MALFORMED 2 /* ATR could not be parsed */
+#define ATR_IO_ERROR 3 /* I/O stream error */
+
+/* Paramenters */
+#define ATR_MAX_SIZE 33 /* Maximum size of ATR byte array */
+#define ATR_MAX_HISTORICAL 15 /* Maximum number of historical bytes */
+#define ATR_MAX_PROTOCOLS 7 /* Maximun number of protocols */
+#define ATR_MAX_IB 4 /* Maximum number of interface bytes per protocol */
+#define ATR_CONVENTION_DIRECT 0 /* Direct convention */
+#define ATR_CONVENTION_INVERSE 1 /* Inverse convention */
+#define ATR_PROTOCOL_TYPE_T0 0 /* Protocol type T=0 */
+#define ATR_PROTOCOL_TYPE_T1 1 /* Protocol type T=1 */
+#define ATR_PROTOCOL_TYPE_T2 2 /* Protocol type T=2 */
+#define ATR_PROTOCOL_TYPE_T3 3 /* Protocol type T=3 */
+#define ATR_PROTOCOL_TYPE_T14 14 /* Protocol type T=14 */
+#define ATR_INTERFACE_BYTE_TA 0 /* Interface byte TAi */
+#define ATR_INTERFACE_BYTE_TB 1 /* Interface byte TBi */
+#define ATR_INTERFACE_BYTE_TC 2 /* Interface byte TCi */
+#define ATR_INTERFACE_BYTE_TD 3 /* Interface byte TDi */
+#define ATR_PARAMETER_F 0 /* Parameter F */
+#define ATR_PARAMETER_D 1 /* Parameter D */
+#define ATR_PARAMETER_I 2 /* Parameter I */
+#define ATR_PARAMETER_P 3 /* Parameter P */
+#define ATR_PARAMETER_N 4 /* Parameter N */
+#define ATR_INTEGER_VALUE_FI 0 /* Integer value FI */
+#define ATR_INTEGER_VALUE_DI 1 /* Integer value DI */
+#define ATR_INTEGER_VALUE_II 2 /* Integer value II */
+#define ATR_INTEGER_VALUE_PI1 3 /* Integer value PI1 */
+#define ATR_INTEGER_VALUE_N 4 /* Integer value N */
+#define ATR_INTEGER_VALUE_PI2 5 /* Integer value PI2 */
+
+/* Default values for paramenters */
+#define ATR_DEFAULT_F 372
+#define ATR_DEFAULT_D 1
+#define ATR_DEFAULT_I 50
+#define ATR_DEFAULT_N 0
+#define ATR_DEFAULT_P 5
+
+/*
+ * Exported data types definition
+ */
+
+typedef struct
+{
+ unsigned length;
+ BYTE TS;
+ BYTE T0;
+ struct
+ {
+ BYTE value;
+ bool present;
+ }
+ ib[ATR_MAX_PROTOCOLS][ATR_MAX_IB], TCK;
+ unsigned pn;
+ BYTE hb[ATR_MAX_HISTORICAL];
+ unsigned hbn;
+}
+ATR_t;
+
+/*
+ * Exported functions declaraton
+ */
+
+/* Initialization */
+extern int ATR_InitFromArray(ATR_t * atr, const BYTE buffer[ATR_MAX_SIZE],
+ unsigned length);
+
+/* General smartcard characteristics */
+extern int ATR_GetConvention(ATR_t * atr, /*@out@*/ int *convention);
+extern int ATR_GetDefaultProtocol(ATR_t * atr, /*@out@*/ int *protocol, int *availableProtocols);
+
+/* ATR parameters and integer values */
+extern int ATR_GetIntegerValue(ATR_t * atr, int name, BYTE * value);
+extern int ATR_GetParameter(ATR_t * atr, int name, /*@out@*/ double *parameter);
+
+#endif /* _ATR_ */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
new file mode 100644
index 0000000..abd5dbe
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
@@ -0,0 +1,56 @@
+/*
+ defines.h
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 Carlos Prados <***@yahoo.com>
+
+ 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef DEFINES_H
+#define DEFINES_H
+
+/*
+ * Get configuration information
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * Boolean constants
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * Type definitions
+ */
+
+#include <wintypes.h>
+
+#ifndef __cplusplus
+typedef int bool;
+#endif
+
+#endif /* DEFINES_H */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
new file mode 100644
index 0000000..cfe8e8d
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
@@ -0,0 +1,136 @@
+/*
+ pps.c
+ Protocol Parameters Selection
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 2001 Carlos Prados <***@yahoo.com>
+
+ 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "pps.h"
+#include "atr.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ifdhandler.h>
+
+#include "commands.h"
+#include "defs.h"
+#include "debug.h"
+
+/*
+ * Not exported funtions declaration
+ */
+
+static bool PPS_Match (BYTE * request, unsigned len_request, BYTE * reply, unsigned len_reply);
+
+static unsigned PPS_GetLength (BYTE * block);
+
+static BYTE PPS_GetPCK (BYTE * block, unsigned length);
+
+int
+PPS_Exchange (int lun, BYTE * params, unsigned *length, unsigned char *pps1)
+{
+ BYTE confirm[PPS_MAX_LENGTH];
+ unsigned len_request, len_confirm;
+ int ret;
+
+ len_request = PPS_GetLength (params);
+ params[len_request - 1] = PPS_GetPCK(params, len_request - 1);
+
+ DEBUG_XXD ("PPS: Sending request: ", params, len_request);
+
+ /* Send PPS request */
+ if (CCID_Transmit (lun, len_request, params, isCharLevel(lun) ? 4 : 0, 0)
+ != IFD_SUCCESS)
+ return PPS_ICC_ERROR;
+
+ /* Get PPS confirm */
+ len_confirm = sizeof(confirm);
+ if (CCID_Receive (lun, &len_confirm, confirm, NULL) != IFD_SUCCESS)
+ return PPS_ICC_ERROR;
+
+ DEBUG_XXD ("PPS: Receiving confirm: ", confirm, len_confirm);
+
+ if (!PPS_Match (params, len_request, confirm, len_confirm))
+ ret = PPS_HANDSAKE_ERROR;
+ else
+ ret = PPS_OK;
+
+ *pps1 = 0x11; /* default TA1 */
+
+ /* if PPS1 is echoed */
+ if (PPS_HAS_PPS1 (params) && PPS_HAS_PPS1 (confirm))
+ *pps1 = confirm[2];
+
+ /* Copy PPS handsake */
+ memcpy (params, confirm, len_confirm);
+ (*length) = len_confirm;
+
+ return ret;
+}
+
+static bool
+PPS_Match (BYTE * request, unsigned len_request, BYTE * confirm, unsigned len_confirm)
+{
+ /* See if the reply differs from request */
+ if ((len_request == len_confirm) && /* same length */
+ memcmp (request, confirm, len_request)) /* different contents */
+ return FALSE;
+
+ if (len_request < len_confirm) /* confirm longer than request */
+ return FALSE;
+
+ /* See if the card specifies other than default FI and D */
+ if ((PPS_HAS_PPS1 (confirm)) && (confirm[2] != request[2]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static unsigned
+PPS_GetLength (BYTE * block)
+{
+ unsigned length = 3;
+
+ if (PPS_HAS_PPS1 (block))
+ length++;
+
+ if (PPS_HAS_PPS2 (block))
+ length++;
+
+ if (PPS_HAS_PPS3 (block))
+ length++;
+
+ return length;
+}
+
+static BYTE
+PPS_GetPCK (BYTE * block, unsigned length)
+{
+ BYTE pck;
+ unsigned i;
+
+ pck = block[0];
+ for (i = 1; i < length; i++)
+ pck ^= block[i];
+
+ return pck;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
new file mode 100644
index 0000000..d9c2ae6
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
@@ -0,0 +1,71 @@
+/*
+ pps.h
+ Protocol Parameters Selection
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 2001 Carlos Prados <***@yahoo.com>
+
+ 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _PPS_
+#define _PPS_
+
+#include "defines.h"
+
+/*
+ * Exported constants definition
+ */
+
+#define PPS_OK 0 /* Negotiation OK */
+#define PPS_ICC_ERROR 1 /* Comunication error */
+#define PPS_HANDSAKE_ERROR 2 /* Agreement not reached */
+#define PPS_PROTOCOL_ERROR 3 /* Error starting protocol */
+#define PPS_MAX_LENGTH 6
+
+#define PPS_HAS_PPS1(block) ((block[1] & 0x10) == 0x10)
+#define PPS_HAS_PPS2(block) ((block[1] & 0x20) == 0x20)
+#define PPS_HAS_PPS3(block) ((block[1] & 0x40) == 0x40)
+
+/*
+ * Exported data types definition
+ */
+
+typedef struct
+{
+ double f;
+ double d;
+ double n;
+ BYTE t;
+}
+PPS_ProtocolParameters;
+
+typedef struct
+{
+ int icc;
+ void *protocol;
+ PPS_ProtocolParameters parameters;
+}
+PPS;
+
+/*
+ * Exported functions declaration
+ */
+
+int PPS_Exchange (int lun, BYTE * params, /*@out@*/ unsigned *length,
+ unsigned char *pps1);
+
+#endif /* _PPS_ */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/utils.c b/MdeModulePkg/Library/SmartCardReader/libccid/utils.c
new file mode 100644
index 0000000..9b35ee7
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/utils.c
@@ -0,0 +1,85 @@
+/*
+ utils.c:
+ Copyright (C) 2003-2008 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: utils.c 6975 2014-09-04 11:33:05Z rousseau $
+ */
+
+#include <pcsclite.h>
+
+#include <config.h>
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "utils.h"
+#include "debug.h"
+
+int ReaderIndex[CCID_DRIVER_MAX_READERS];
+
+void InitReaderIndex(void)
+{
+ int i;
+
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ ReaderIndex[i] = -1;
+} /* InitReaderIndex */
+
+int GetNewReaderIndex(const int Lun)
+{
+ int i;
+
+ /* check that Lun is NOT already used */
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ if (Lun == ReaderIndex[i])
+ break;
+
+ if (i < CCID_DRIVER_MAX_READERS)
+ {
+ DEBUG_CRITICAL2("Lun: %d is already used", Lun);
+ return -1;
+ }
+
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ if (-1 == ReaderIndex[i])
+ {
+ ReaderIndex[i] = Lun;
+ return i;
+ }
+
+ DEBUG_CRITICAL("ReaderIndex[] is full");
+ return -1;
+} /* GetReaderIndex */
+
+int LunToReaderIndex(const int Lun)
+{
+ int i;
+
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ if (Lun == ReaderIndex[i])
+ return i;
+
+ DEBUG_CRITICAL2("Lun: %X not found", Lun);
+ return -1;
+} /* LunToReaderIndex */
+
+void ReleaseReaderIndex(const int index)
+{
+ ReaderIndex[index] = -1;
+} /* ReleaseReaderIndex */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/utils.h b/MdeModulePkg/Library/SmartCardReader/libccid/utils.h
new file mode 100644
index 0000000..3f21302
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/utils.h
@@ -0,0 +1,33 @@
+/*
+ utils.c:
+ Copyright (C) 2003-2009 Ludovic Rousseau
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: utils.h 4973 2010-06-01 09:43:29Z rousseau $
+ */
+
+#ifndef TRUE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+void InitReaderIndex(void);
+int GetNewReaderIndex(const int Lun);
+int LunToReaderIndex(int Lun);
+void ReleaseReaderIndex(const int idx);
+
--
2.1.4
------------------------------------------------------------------------------