|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
ifdhandler.c: IFDH API
|
|
Packit |
9f0df5 |
Copyright (C) 2003-2010 Ludovic Rousseau
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
This library is free software; you can redistribute it and/or
|
|
Packit |
9f0df5 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
9f0df5 |
License as published by the Free Software Foundation; either
|
|
Packit |
9f0df5 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
This library is distributed in the hope that it will be useful,
|
|
Packit |
9f0df5 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
9f0df5 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
9f0df5 |
Lesser General Public License for more details.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
9f0df5 |
along with this library; if not, write to the Free Software Foundation,
|
|
Packit |
9f0df5 |
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#include <config.h>
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#ifdef HAVE_STDIO_H
|
|
Packit |
9f0df5 |
#include <stdio.h>
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
#ifdef HAVE_STRING_H
|
|
Packit |
9f0df5 |
#include <string.h>
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
#ifdef HAVE_STDLIB_H
|
|
Packit |
9f0df5 |
#include <stdlib.h>
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
9f0df5 |
#include <unistd.h>
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
#ifdef HAVE_ARPA_INET_H
|
|
Packit |
9f0df5 |
#include <arpa/inet.h>
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#include "misc.h"
|
|
Packit |
9f0df5 |
#include <pcsclite.h>
|
|
Packit |
9f0df5 |
#include <ifdhandler.h>
|
|
Packit |
9f0df5 |
#include <reader.h>
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#include "ccid.h"
|
|
Packit |
9f0df5 |
#include "defs.h"
|
|
Packit |
9f0df5 |
#include "ccid_ifdhandler.h"
|
|
Packit |
9f0df5 |
#include "debug.h"
|
|
Packit |
9f0df5 |
#include "utils.h"
|
|
Packit |
9f0df5 |
#include "commands.h"
|
|
Packit |
9f0df5 |
#include "towitoko/atr.h"
|
|
Packit |
9f0df5 |
#include "towitoko/pps.h"
|
|
Packit |
9f0df5 |
#include "parser.h"
|
|
Packit |
9f0df5 |
#include "strlcpycat.h"
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
#include <pthread.h>
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Array of structures to hold the ATR and other state value of each slot */
|
|
Packit |
9f0df5 |
static CcidDesc CcidSlots[CCID_DRIVER_MAX_READERS];
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* global mutex */
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
static pthread_mutex_t ifdh_context_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
int LogLevel = DEBUG_LEVEL_CRITICAL | DEBUG_LEVEL_INFO;
|
|
Packit |
9f0df5 |
int DriverOptions = 0;
|
|
Packit |
9f0df5 |
int PowerOnVoltage = -1;
|
|
Packit |
9f0df5 |
static int DebugInitialized = FALSE;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* local functions */
|
|
Packit |
9f0df5 |
static void init_driver(void);
|
|
Packit |
9f0df5 |
static char find_baud_rate(unsigned int baudrate, unsigned int *list);
|
|
Packit |
9f0df5 |
static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
|
|
Packit |
9f0df5 |
int clock_frequency);
|
|
Packit |
9f0df5 |
static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI,
|
|
Packit |
9f0df5 |
int CWI, int clock_frequency);
|
|
Packit |
9f0df5 |
static int get_IFSC(ATR_t *atr, int *i);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static void FreeChannel(int reader_index)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
(void)pthread_mutex_lock(&ifdh_context_mutex);
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)ClosePort(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
free(CcidSlots[reader_index].readerName);
|
|
Packit |
9f0df5 |
memset(&CcidSlots[reader_index], 0, sizeof(CcidSlots[reader_index]));
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ReleaseReaderIndex(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
(void)pthread_mutex_unlock(&ifdh_context_mutex);
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static RESPONSECODE CreateChannelByNameOrChannel(DWORD Lun,
|
|
Packit |
9f0df5 |
LPSTR lpcDevice, DWORD Channel)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
RESPONSECODE return_value = IFD_SUCCESS;
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
status_t ret;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (! DebugInitialized)
|
|
Packit |
9f0df5 |
init_driver();
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (lpcDevice)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO3("Lun: " DWORD_X ", device: %s", Lun, lpcDevice);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO3("Lun: " DWORD_X ", Channel: " DWORD_X, Lun, Channel);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
(void)pthread_mutex_lock(&ifdh_context_mutex);
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
reader_index = GetNewReaderIndex(Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
(void)pthread_mutex_unlock(&ifdh_context_mutex);
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == reader_index)
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Reset ATR buffer */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].nATRLength = 0;
|
|
Packit |
9f0df5 |
*CcidSlots[reader_index].pcATRBuffer = '\0';
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Reset PowerFlags */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* reader name */
|
|
Packit |
9f0df5 |
if (lpcDevice)
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName = strdup(lpcDevice);
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName = strdup("no name");
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (lpcDevice)
|
|
Packit |
9f0df5 |
ret = OpenPortByName(reader_index, lpcDevice);
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
ret = OpenPort(reader_index, Channel);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (ret != STATUS_SUCCESS)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("failed");
|
|
Packit |
9f0df5 |
if (STATUS_NO_SUCH_DEVICE == ret)
|
|
Packit |
9f0df5 |
return_value = IFD_NO_SUCH_DEVICE;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return_value = IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
goto error;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
|
|
Packit |
9f0df5 |
unsigned int oldReadTimeout;
|
|
Packit |
9f0df5 |
RESPONSECODE cmd_ret;
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Maybe we have a special treatment for this reader */
|
|
Packit |
9f0df5 |
(void)ccid_open_hack_pre(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Try to access the reader */
|
|
Packit |
9f0df5 |
/* This "warm up" sequence is sometimes needed when pcscd is
|
|
Packit |
9f0df5 |
* restarted with the reader already connected. We get some
|
|
Packit |
9f0df5 |
* "usb_bulk_read: Resource temporarily unavailable" on the first
|
|
Packit |
9f0df5 |
* few tries. It is an empirical hack */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* The reader may have to start here so give it some time */
|
|
Packit |
9f0df5 |
cmd_ret = CmdGetSlotStatus(reader_index, pcbuffer);
|
|
Packit |
9f0df5 |
if (IFD_NO_SUCH_DEVICE == cmd_ret)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
return_value = cmd_ret;
|
|
Packit |
9f0df5 |
goto error;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* save the current read timeout computed from card capabilities */
|
|
Packit |
9f0df5 |
oldReadTimeout = ccid_descriptor->readTimeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* 100 ms just to resync the USB toggle bits */
|
|
Packit |
9f0df5 |
/* Do not use a fixed 100 ms value but compute it from the
|
|
Packit |
9f0df5 |
* default timeout. It is now possible to use a different value
|
|
Packit |
9f0df5 |
* by changing readTimeout in ccid_open_hack_pre() */
|
|
Packit |
9f0df5 |
ccid_descriptor->readTimeout = ccid_descriptor->readTimeout * 100.0 / DEFAULT_COM_READ_TIMEOUT;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer))
|
|
Packit |
9f0df5 |
&& (IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer)))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("failed");
|
|
Packit |
9f0df5 |
return_value = IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* Maybe we have a special treatment for this reader */
|
|
Packit |
9f0df5 |
return_value = ccid_open_hack_post(reader_index);
|
|
Packit |
9f0df5 |
if (return_value != IFD_SUCCESS)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("failed");
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* set back the old timeout */
|
|
Packit |
9f0df5 |
ccid_descriptor->readTimeout = oldReadTimeout;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
error:
|
|
Packit |
9f0df5 |
if (return_value != IFD_SUCCESS)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* release the allocated resources */
|
|
Packit |
9f0df5 |
FreeChannel(reader_index);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
} /* CreateChannelByNameOrChannel */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
return CreateChannelByNameOrChannel(Lun, lpcDevice, -1);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* Lun - Logical Unit Number, use this for multiple card slots or
|
|
Packit |
9f0df5 |
* multiple readers. 0xXXXXYYYY - XXXX multiple readers, YYYY multiple
|
|
Packit |
9f0df5 |
* slots. The resource manager will set these automatically. By
|
|
Packit |
9f0df5 |
* default the resource manager loads a new instance of the driver so
|
|
Packit |
9f0df5 |
* if your reader does not have more than one smartcard slot then
|
|
Packit |
9f0df5 |
* ignore the Lun in all the functions. Future versions of PC/SC might
|
|
Packit |
9f0df5 |
* support loading multiple readers through one instance of the driver
|
|
Packit |
9f0df5 |
* in which XXXX would be important to implement if you want this.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* Channel - Channel ID. This is denoted by the following: 0x000001 -
|
|
Packit |
9f0df5 |
* /dev/pcsc/1 0x000002 - /dev/pcsc/2 0x000003 - /dev/pcsc/3
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* USB readers may choose to ignore this parameter and query the bus
|
|
Packit |
9f0df5 |
* for the particular reader.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function is required to open a communications channel to the
|
|
Packit |
9f0df5 |
* port listed by Channel. For example, the first serial reader on
|
|
Packit |
9f0df5 |
* COM1 would link to /dev/pcsc/1 which would be a sym link to
|
|
Packit |
9f0df5 |
* /dev/ttyS0 on some machines This is used to help with intermachine
|
|
Packit |
9f0df5 |
* independance.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Once the channel is opened the reader must be in a state in which
|
|
Packit |
9f0df5 |
* it is possible to query IFDHICCPresence() for card status.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_SUCCESS IFD_COMMUNICATION_ERROR
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
return CreateChannelByNameOrChannel(Lun, NULL, Channel);
|
|
Packit |
9f0df5 |
} /* IFDHCreateChannel */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHCloseChannel(DWORD Lun)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function should close the reader communication channel for the
|
|
Packit |
9f0df5 |
* particular reader. Prior to closing the communication channel the
|
|
Packit |
9f0df5 |
* reader should make sure the card is powered down and the terminal
|
|
Packit |
9f0df5 |
* is also powered down.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_SUCCESS IFD_COMMUNICATION_ERROR
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
|
|
Packit |
9f0df5 |
Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Restore the default timeout
|
|
Packit |
9f0df5 |
* No need to wait too long if the reader disapeared */
|
|
Packit |
9f0df5 |
get_ccid_descriptor(reader_index)->readTimeout = DEFAULT_COM_READ_TIMEOUT;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)CmdPowerOff(reader_index);
|
|
Packit |
9f0df5 |
/* No reader status check, if it failed, what can you do ? :) */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
FreeChannel(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
} /* IFDHCloseChannel */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#if !defined(TWIN_SERIAL)
|
|
Packit |
9f0df5 |
static RESPONSECODE IFDHPolling(DWORD Lun, int timeout)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* log only if DEBUG_LEVEL_PERIODIC is set */
|
|
Packit |
9f0df5 |
if (LogLevel & DEBUG_LEVEL_PERIODIC)
|
|
Packit |
9f0df5 |
DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName, Lun, timeout);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return InterruptRead(reader_index, timeout);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* on an ICCD device the card is always inserted
|
|
Packit |
9f0df5 |
* so no card movement will ever happen: just do nothing */
|
|
Packit |
9f0df5 |
static RESPONSECODE IFDHSleep(DWORD Lun, int timeout)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName, Lun, timeout);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* just sleep for 5 seconds since the polling thread is NOT killable
|
|
Packit |
9f0df5 |
* so pcscd event thread must loop to exit cleanly
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Once the driver (libusb in fact) will support
|
|
Packit |
9f0df5 |
* TAG_IFD_POLLING_THREAD_KILLABLE then we could use a much longer delay
|
|
Packit |
9f0df5 |
* and be killed before pcscd exits
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
(void)usleep(timeout * 1000);
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static RESPONSECODE IFDHStopPolling(DWORD Lun)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO3("%s (lun: " DWORD_X ")",
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)InterruptStop(reader_index);
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag,
|
|
Packit |
9f0df5 |
PDWORD Length, PUCHAR Value)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function should get the slot/card capabilities for a
|
|
Packit |
9f0df5 |
* particular slot/card specified by Lun. Again, if you have only 1
|
|
Packit |
9f0df5 |
* card slot and don't mind loading a new driver for each reader then
|
|
Packit |
9f0df5 |
* ignore Lun.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Tag - the tag for the information requested example: TAG_IFD_ATR -
|
|
Packit |
9f0df5 |
* return the Atr and its size (required). these tags are defined in
|
|
Packit |
9f0df5 |
* ifdhandler.h
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Length - the length of the returned data Value - the value of the
|
|
Packit |
9f0df5 |
* data
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_SUCCESS IFD_ERROR_TAG
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
RESPONSECODE return_value = IFD_SUCCESS;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
switch (Tag)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
case TAG_IFD_ATR:
|
|
Packit |
9f0df5 |
case SCARD_ATTR_ATR_STRING:
|
|
Packit |
9f0df5 |
/* If Length is not zero, powerICC has been performed.
|
|
Packit |
9f0df5 |
* Otherwise, return NULL pointer
|
|
Packit |
9f0df5 |
* Buffer size is stored in *Length */
|
|
Packit |
9f0df5 |
if ((int)*Length >= CcidSlots[reader_index].nATRLength)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = CcidSlots[reader_index].nATRLength;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
memcpy(Value, CcidSlots[reader_index].pcATRBuffer, *Length);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case SCARD_ATTR_ICC_INTERFACE_STATUS:
|
|
Packit |
9f0df5 |
*Length = 1;
|
|
Packit |
9f0df5 |
if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
|
|
Packit |
9f0df5 |
/* nonzero if contact is active */
|
|
Packit |
9f0df5 |
*Value = 1;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
/* smart card electrical contact is not active */
|
|
Packit |
9f0df5 |
*Value = 0;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case SCARD_ATTR_ICC_PRESENCE:
|
|
Packit |
9f0df5 |
*Length = 1;
|
|
Packit |
9f0df5 |
/* Single byte indicating smart card presence:
|
|
Packit |
9f0df5 |
* 0 = not present
|
|
Packit |
9f0df5 |
* 1 = card present but not swallowed (applies only if
|
|
Packit |
9f0df5 |
* reader supports smart card swallowing)
|
|
Packit |
9f0df5 |
* 2 = card present (and swallowed if reader supports smart
|
|
Packit |
9f0df5 |
* card swallowing)
|
|
Packit |
9f0df5 |
* 4 = card confiscated. */
|
|
Packit |
9f0df5 |
if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
|
|
Packit |
9f0df5 |
/* Card present */
|
|
Packit |
9f0df5 |
*Value = 2;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
/* Not present */
|
|
Packit |
9f0df5 |
*Value = 0;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#ifdef HAVE_PTHREAD
|
|
Packit |
9f0df5 |
case TAG_IFD_SIMULTANEOUS_ACCESS:
|
|
Packit |
9f0df5 |
if (*Length >= 1)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = 1;
|
|
Packit |
9f0df5 |
*Value = CCID_DRIVER_MAX_READERS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case TAG_IFD_THREAD_SAFE:
|
|
Packit |
9f0df5 |
if (*Length >= 1)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = 1;
|
|
Packit |
9f0df5 |
#ifdef __APPLE__
|
|
Packit |
9f0df5 |
*Value = 0; /* Apple pcscd is bogus (rdar://problem/5697388) */
|
|
Packit |
9f0df5 |
#else
|
|
Packit |
9f0df5 |
*Value = 1; /* Can talk to multiple readers at the same time */
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case TAG_IFD_SLOTS_NUMBER:
|
|
Packit |
9f0df5 |
if (*Length >= 1)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = 1;
|
|
Packit |
9f0df5 |
*Value = 1 + get_ccid_descriptor(reader_index) -> bMaxSlotIndex;
|
|
Packit |
9f0df5 |
#ifdef USE_COMPOSITE_AS_MULTISLOT
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* On MacOS X or Linux+libusb we can simulate a
|
|
Packit |
9f0df5 |
* composite device with 2 CCID interfaces by a
|
|
Packit |
9f0df5 |
* multi-slot reader */
|
|
Packit |
9f0df5 |
int readerID = get_ccid_descriptor(reader_index) -> readerID;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* 2 CCID interfaces */
|
|
Packit |
9f0df5 |
if ((GEMALTOPROXDU == readerID)
|
|
Packit |
9f0df5 |
|| (GEMALTOPROXSU == readerID)
|
|
Packit |
9f0df5 |
|| (HID_OMNIKEY_5422 == readerID))
|
|
Packit |
9f0df5 |
*Value = 2;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* 3 CCID interfaces */
|
|
Packit |
9f0df5 |
if (FEITIANR502DUAL == readerID)
|
|
Packit |
9f0df5 |
*Value = 3;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
DEBUG_INFO2("Reader supports %d slot(s)", *Value);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case TAG_IFD_SLOT_THREAD_SAFE:
|
|
Packit |
9f0df5 |
if (*Length >= 1)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = 1;
|
|
Packit |
9f0df5 |
*Value = 0; /* Can NOT talk to multiple slots at the same time */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case SCARD_ATTR_VENDOR_IFD_VERSION:
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Vendor-supplied interface device version (DWORD in the form
|
|
Packit |
9f0df5 |
* 0xMMmmbbbb where MM = major version, mm = minor version, and
|
|
Packit |
9f0df5 |
* bbbb = build number). */
|
|
Packit |
9f0df5 |
*Length = 4;
|
|
Packit |
9f0df5 |
if (Value)
|
|
Packit |
9f0df5 |
*(uint32_t *)Value = IFD_bcdDevice << 16;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case SCARD_ATTR_VENDOR_NAME:
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
const char *sIFD_iManufacturer = get_ccid_descriptor(reader_index) -> sIFD_iManufacturer;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (sIFD_iManufacturer)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
strlcpy((char *)Value, sIFD_iManufacturer, *Length);
|
|
Packit |
9f0df5 |
*Length = strlen((char *)Value) +1;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* not supported */
|
|
Packit |
9f0df5 |
*Length = 0;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case SCARD_ATTR_MAXINPUT:
|
|
Packit |
9f0df5 |
*Length = sizeof(uint32_t);
|
|
Packit |
9f0df5 |
if (Value)
|
|
Packit |
9f0df5 |
*(uint32_t *)Value = get_ccid_descriptor(reader_index) -> dwMaxCCIDMessageLength -10;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#if !defined(TWIN_SERIAL)
|
|
Packit |
9f0df5 |
case TAG_IFD_POLLING_THREAD_WITH_TIMEOUT:
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_desc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* default value: not supported */
|
|
Packit |
9f0df5 |
*Length = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_desc = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* CCID and not ICCD */
|
|
Packit |
9f0df5 |
if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
|
|
Packit |
9f0df5 |
/* 3 end points */
|
|
Packit |
9f0df5 |
&& (3 == ccid_desc -> bNumEndpoints))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = sizeof(void *);
|
|
Packit |
9f0df5 |
if (Value)
|
|
Packit |
9f0df5 |
*(void **)Value = IFDHPolling;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
|
|
Packit |
9f0df5 |
|| (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = sizeof(void *);
|
|
Packit |
9f0df5 |
if (Value)
|
|
Packit |
9f0df5 |
*(void **)Value = IFDHSleep;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case TAG_IFD_POLLING_THREAD_KILLABLE:
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_desc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* default value: not supported */
|
|
Packit |
9f0df5 |
*Length = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_desc = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
|
|
Packit |
9f0df5 |
|| (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = 1; /* 1 char */
|
|
Packit |
9f0df5 |
if (Value)
|
|
Packit |
9f0df5 |
*Value = 1; /* TRUE */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case TAG_IFD_STOP_POLLING_THREAD:
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_desc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* default value: not supported */
|
|
Packit |
9f0df5 |
*Length = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_desc = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
/* CCID and not ICCD */
|
|
Packit |
9f0df5 |
if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
|
|
Packit |
9f0df5 |
/* 3 end points */
|
|
Packit |
9f0df5 |
&& (3 == ccid_desc -> bNumEndpoints))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
*Length = sizeof(void *);
|
|
Packit |
9f0df5 |
if (Value)
|
|
Packit |
9f0df5 |
*(void **)Value = IFDHStopPolling;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case SCARD_ATTR_VENDOR_IFD_SERIAL_NO:
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_desc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_desc = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
if (ccid_desc->sIFD_serial_number)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
strlcpy((char *)Value, ccid_desc->sIFD_serial_number, *Length);
|
|
Packit |
9f0df5 |
*Length = strlen((char *)Value)+1;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* not supported */
|
|
Packit |
9f0df5 |
*Length = 0;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
default:
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_TAG;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
} /* IFDHGetCapabilities */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
|
|
Packit |
9f0df5 |
/*@unused@*/ DWORD Length, /*@unused@*/ PUCHAR Value)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function should set the slot/card capabilities for a
|
|
Packit |
9f0df5 |
* particular slot/card specified by Lun. Again, if you have only 1
|
|
Packit |
9f0df5 |
* card slot and don't mind loading a new driver for each reader then
|
|
Packit |
9f0df5 |
* ignore Lun.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Tag - the tag for the information needing set
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Length - the length of the returned data Value - the value of the
|
|
Packit |
9f0df5 |
* data
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
|
|
Packit |
9f0df5 |
* IFD_ERROR_VALUE_READ_ONLY
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)Length;
|
|
Packit |
9f0df5 |
(void)Value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return IFD_NOT_SUPPORTED;
|
|
Packit |
9f0df5 |
} /* IFDHSetCapabilities */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
|
|
Packit |
9f0df5 |
UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function should set the PTS of a particular card/slot using
|
|
Packit |
9f0df5 |
* the three PTS parameters sent
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Protocol - SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
|
|
Packit |
9f0df5 |
* Flags - Logical OR of possible values:
|
|
Packit |
9f0df5 |
* IFD_NEGOTIATE_PTS1
|
|
Packit |
9f0df5 |
* IFD_NEGOTIATE_PTS2
|
|
Packit |
9f0df5 |
* IFD_NEGOTIATE_PTS3
|
|
Packit |
9f0df5 |
* to determine which PTS values to negotiate.
|
|
Packit |
9f0df5 |
* PTS1,PTS2,PTS3 - PTS Values.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
* IFD_SUCCESS
|
|
Packit |
9f0df5 |
* IFD_ERROR_PTS_FAILURE
|
|
Packit |
9f0df5 |
* IFD_COMMUNICATION_ERROR
|
|
Packit |
9f0df5 |
* IFD_PROTOCOL_NOT_SUPPORTED
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
BYTE pps[PPS_MAX_LENGTH];
|
|
Packit |
9f0df5 |
ATR_t atr;
|
|
Packit |
9f0df5 |
unsigned int len;
|
|
Packit |
9f0df5 |
int convention;
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
int atr_ret;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Set ccid desc params */
|
|
Packit |
9f0df5 |
CcidDesc *ccid_slot;
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_desc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO4("protocol T=" DWORD_D ", %s (lun: " DWORD_X ")",
|
|
Packit |
9f0df5 |
Protocol-SCARD_PROTOCOL_T0, CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Set to zero buffer */
|
|
Packit |
9f0df5 |
memset(pps, 0, sizeof(pps));
|
|
Packit |
9f0df5 |
memset(&atr, 0, sizeof(atr));
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Get ccid params */
|
|
Packit |
9f0df5 |
ccid_slot = get_ccid_slot(reader_index);
|
|
Packit |
9f0df5 |
ccid_desc = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Do not send CCID command SetParameters or PPS to the CCID
|
|
Packit |
9f0df5 |
* The CCID will do this himself */
|
|
Packit |
9f0df5 |
if (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_PROP)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
|
|
Packit |
9f0df5 |
goto end;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Get ATR of the card */
|
|
Packit |
9f0df5 |
atr_ret = ATR_InitFromArray(&atr, ccid_slot->pcATRBuffer,
|
|
Packit |
9f0df5 |
ccid_slot->nATRLength);
|
|
Packit |
9f0df5 |
if (ATR_MALFORMED == atr_ret)
|
|
Packit |
9f0df5 |
return IFD_PROTOCOL_NOT_SUPPORTED;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (SCARD_PROTOCOL_T0 == Protocol)
|
|
Packit |
9f0df5 |
pps[1] |= ATR_PROTOCOL_TYPE_T0;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
if (SCARD_PROTOCOL_T1 == Protocol)
|
|
Packit |
9f0df5 |
pps[1] |= ATR_PROTOCOL_TYPE_T1;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
return IFD_PROTOCOL_NOT_SUPPORTED;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TA2 present -> specific mode */
|
|
Packit |
9f0df5 |
if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
if (pps[1] != (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* wrong protocol */
|
|
Packit |
9f0df5 |
DEBUG_COMM3("Specific mode in T=%d and T=%d requested",
|
|
Packit |
9f0df5 |
atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F, pps[1]);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return IFD_PROTOCOL_NOT_SUPPORTED;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TCi (i>2) indicates CRC instead of LRC */
|
|
Packit |
9f0df5 |
if (SCARD_PROTOCOL_T1 == Protocol)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
t1_state_t *t1 = &(ccid_slot -> t1);
|
|
Packit |
9f0df5 |
int i;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TCi (i>2) present? */
|
|
Packit |
9f0df5 |
for (i=2; i
|
|
Packit |
9f0df5 |
if (atr.ib[i][ATR_INTERFACE_BYTE_TC].present)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
if (0 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM("Use LRC");
|
|
Packit |
9f0df5 |
(void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
if (1 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM("Use CRC");
|
|
Packit |
9f0df5 |
(void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_CRC, 0);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Wrong value for TCi: %d",
|
|
Packit |
9f0df5 |
atr.ib[i][ATR_INTERFACE_BYTE_TC].value);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* only the first TCi (i>2) must be used */
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* PTS1? */
|
|
Packit |
9f0df5 |
if (Flags & IFD_NEGOTIATE_PTS1)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* just use the value passed in argument */
|
|
Packit |
9f0df5 |
pps[1] |= 0x10; /* PTS1 presence */
|
|
Packit |
9f0df5 |
pps[2] = PTS1;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* TA1 present */
|
|
Packit |
9f0df5 |
if (atr.ib[0][ATR_INTERFACE_BYTE_TA].present)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int card_baudrate;
|
|
Packit |
9f0df5 |
unsigned int default_baudrate;
|
|
Packit |
9f0df5 |
double f, d;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* may happen with non ISO cards */
|
|
Packit |
9f0df5 |
if ((0 == f) || (0 == d))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* values for TA1=11 */
|
|
Packit |
9f0df5 |
f = 372;
|
|
Packit |
9f0df5 |
d = 1;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Baudrate = f x D/F */
|
|
Packit |
9f0df5 |
card_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
|
|
Packit |
9f0df5 |
* d / f);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
default_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
|
|
Packit |
9f0df5 |
* ATR_DEFAULT_D / ATR_DEFAULT_F);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* if the card does not try to lower the default speed */
|
|
Packit |
9f0df5 |
if ((card_baudrate > default_baudrate)
|
|
Packit |
9f0df5 |
/* and the reader is fast enough */
|
|
Packit |
9f0df5 |
&& (card_baudrate <= ccid_desc->dwMaxDataRate))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* the reader has no baud rates table */
|
|
Packit |
9f0df5 |
if ((NULL == ccid_desc->arrayOfSupportedDataRates)
|
|
Packit |
9f0df5 |
/* or explicitely support it */
|
|
Packit |
9f0df5 |
|| find_baud_rate(card_baudrate,
|
|
Packit |
9f0df5 |
ccid_desc->arrayOfSupportedDataRates))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pps[1] |= 0x10; /* PTS1 presence */
|
|
Packit |
9f0df5 |
pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Set speed to %d bauds", card_baudrate);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Reader does not support %d bauds",
|
|
Packit |
9f0df5 |
card_baudrate);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TA2 present -> specific mode: the card is supporting
|
|
Packit |
9f0df5 |
* only the baud rate specified in TA1 but reader does not
|
|
Packit |
9f0df5 |
* support this value. Reject the card. */
|
|
Packit |
9f0df5 |
if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* the card is too fast for the reader */
|
|
Packit |
9f0df5 |
if ((card_baudrate > ccid_desc->dwMaxDataRate +2)
|
|
Packit |
9f0df5 |
/* but TA1 <= 97 */
|
|
Packit |
9f0df5 |
&& (atr.ib[0][ATR_INTERFACE_BYTE_TA].value <= 0x97))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned char old_TA1;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
old_TA1 = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
|
|
Packit |
9f0df5 |
while (atr.ib[0][ATR_INTERFACE_BYTE_TA].value > 0x94)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* use a lower TA1 */
|
|
Packit |
9f0df5 |
atr.ib[0][ATR_INTERFACE_BYTE_TA].value--;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Baudrate = f x D/F */
|
|
Packit |
9f0df5 |
card_baudrate = (unsigned int) (1000 *
|
|
Packit |
9f0df5 |
ccid_desc->dwDefaultClock * d / f);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* the reader has a baud rate table */
|
|
Packit |
9f0df5 |
if ((ccid_desc->arrayOfSupportedDataRates
|
|
Packit |
9f0df5 |
/* and the baud rate is supported */
|
|
Packit |
9f0df5 |
&& find_baud_rate(card_baudrate,
|
|
Packit |
9f0df5 |
ccid_desc->arrayOfSupportedDataRates))
|
|
Packit |
9f0df5 |
/* or the reader has NO baud rate table */
|
|
Packit |
9f0df5 |
|| ((NULL == ccid_desc->arrayOfSupportedDataRates)
|
|
Packit |
9f0df5 |
/* and the baud rate is bellow the limit */
|
|
Packit |
9f0df5 |
&& (card_baudrate <= ccid_desc->dwMaxDataRate)))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pps[1] |= 0x10; /* PTS1 presence */
|
|
Packit |
9f0df5 |
pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Set adapted speed to %d bauds",
|
|
Packit |
9f0df5 |
card_baudrate);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* restore original TA1 value */
|
|
Packit |
9f0df5 |
atr.ib[0][ATR_INTERFACE_BYTE_TA].value = old_TA1;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* PTS2? */
|
|
Packit |
9f0df5 |
if (Flags & IFD_NEGOTIATE_PTS2)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pps[1] |= 0x20; /* PTS2 presence */
|
|
Packit |
9f0df5 |
pps[3] = PTS2;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* PTS3? */
|
|
Packit |
9f0df5 |
if (Flags & IFD_NEGOTIATE_PTS3)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pps[1] |= 0x40; /* PTS3 presence */
|
|
Packit |
9f0df5 |
pps[4] = PTS3;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Generate PPS */
|
|
Packit |
9f0df5 |
pps[0] = 0xFF;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Automatic PPS made by the ICC? */
|
|
Packit |
9f0df5 |
if ((! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_CUR))
|
|
Packit |
9f0df5 |
/* TA2 absent: negociable mode */
|
|
Packit |
9f0df5 |
&& (! atr.ib[1][ATR_INTERFACE_BYTE_TA].present))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int default_protocol;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ATR_GetDefaultProtocol(&atr, &default_protocol, NULL);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* if the requested protocol is not the default one
|
|
Packit |
9f0df5 |
* or a TA1/PPS1 is present */
|
|
Packit |
9f0df5 |
if (((pps[1] & 0x0F) != default_protocol) || (PPS_HAS_PPS1(pps)))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
#ifdef O2MICRO_OZ776_PATCH
|
|
Packit |
9f0df5 |
if ((OZ776 == ccid_desc->readerID)
|
|
Packit |
9f0df5 |
|| (OZ776_7772 == ccid_desc->readerID))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* convert from ATR_PROTOCOL_TYPE_T? to SCARD_PROTOCOL_T? */
|
|
Packit |
9f0df5 |
Protocol = default_protocol +
|
|
Packit |
9f0df5 |
(SCARD_PROTOCOL_T0 - ATR_PROTOCOL_TYPE_T0);
|
|
Packit |
9f0df5 |
DEBUG_INFO2("PPS not supported on O2Micro readers. Using T=" DWORD_D,
|
|
Packit |
9f0df5 |
Protocol - SCARD_PROTOCOL_T0);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
if (PPS_Exchange(reader_index, pps, &len, &pps[2]) != PPS_OK)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("PPS_Exchange Failed");
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return IFD_ERROR_PTS_FAILURE;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Now we must set the reader parameters */
|
|
Packit |
9f0df5 |
(void)ATR_GetConvention(&atr, &convention);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* specific mode and implicit parameters? (b5 of TA2) */
|
|
Packit |
9f0df5 |
if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present
|
|
Packit |
9f0df5 |
&& (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x10))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* T=1 */
|
|
Packit |
9f0df5 |
if (SCARD_PROTOCOL_T1 == Protocol)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
BYTE param[] = {
|
|
Packit |
9f0df5 |
0x11, /* Fi/Di */
|
|
Packit |
9f0df5 |
0x10, /* TCCKS */
|
|
Packit |
9f0df5 |
0x00, /* GuardTime */
|
|
Packit |
9f0df5 |
0x4D, /* BWI/CWI */
|
|
Packit |
9f0df5 |
0x00, /* ClockStop */
|
|
Packit |
9f0df5 |
0x20, /* IFSC */
|
|
Packit |
9f0df5 |
0x00 /* NADValue */
|
|
Packit |
9f0df5 |
};
|
|
Packit |
9f0df5 |
int i;
|
|
Packit |
9f0df5 |
t1_state_t *t1 = &(ccid_slot -> t1);
|
|
Packit |
9f0df5 |
RESPONSECODE ret;
|
|
Packit |
9f0df5 |
double f, d;
|
|
Packit |
9f0df5 |
int ifsc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TA1 is not default */
|
|
Packit |
9f0df5 |
if (PPS_HAS_PPS1(pps))
|
|
Packit |
9f0df5 |
param[0] = pps[2];
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* CRC checksum? */
|
|
Packit |
9f0df5 |
if (2 == t1->rc_bytes)
|
|
Packit |
9f0df5 |
param[1] |= 0x01;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* the CCID should ignore this bit */
|
|
Packit |
9f0df5 |
if (ATR_CONVENTION_INVERSE == convention)
|
|
Packit |
9f0df5 |
param[1] |= 0x02;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* get TC1 Extra guard time */
|
|
Packit |
9f0df5 |
if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
|
|
Packit |
9f0df5 |
param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TBi (i>2) present? BWI/CWI */
|
|
Packit |
9f0df5 |
for (i=2; i
|
|
Packit |
9f0df5 |
if (atr.ib[i][ATR_INTERFACE_BYTE_TB].present)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM3("BWI/CWI (TB%d) present: 0x%02X", i+1,
|
|
Packit |
9f0df5 |
atr.ib[i][ATR_INTERFACE_BYTE_TB].value);
|
|
Packit |
9f0df5 |
param[3] = atr.ib[i][ATR_INTERFACE_BYTE_TB].value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* Hack for OpenPGP card */
|
|
Packit |
9f0df5 |
unsigned char openpgp_atr[] = { 0x3B, 0xFA, 0x13,
|
|
Packit |
9f0df5 |
0x00, 0xFF, 0x81, 0x31, 0x80, 0x45, 0x00, 0x31,
|
|
Packit |
9f0df5 |
0xC1, 0x73, 0xC0, 0x01, 0x00, 0x00, 0x90, 0x00, 0xB1 };
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (0 == memcmp(ccid_slot->pcATRBuffer, openpgp_atr,
|
|
Packit |
9f0df5 |
ccid_slot->nATRLength))
|
|
Packit |
9f0df5 |
/* change BWI from 4 to 7 to increase BWT from
|
|
Packit |
9f0df5 |
* 1.4s to 11s and avoid a timeout during on
|
|
Packit |
9f0df5 |
* board key generation (bogus card) */
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
param[3] = 0x75;
|
|
Packit |
9f0df5 |
DEBUG_COMM2("OpenPGP hack, using 0x%02X", param[3]);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* only the first TBi (i>2) must be used */
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* compute communication timeout */
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
|
|
Packit |
9f0df5 |
ccid_desc->readTimeout = T1_card_timeout(f, d, param[2],
|
|
Packit |
9f0df5 |
(param[3] & 0xF0) >> 4 /* BWI */, param[3] & 0x0F /* CWI */,
|
|
Packit |
9f0df5 |
ccid_desc->dwDefaultClock);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ifsc = get_IFSC(&atr, &i);
|
|
Packit |
9f0df5 |
if (ifsc > 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
|
|
Packit |
9f0df5 |
param[5] = ifsc;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ret = SetParameters(reader_index, 1, sizeof(param), param);
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS != ret)
|
|
Packit |
9f0df5 |
return ret;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
/* T=0 */
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
BYTE param[] = {
|
|
Packit |
9f0df5 |
0x11, /* Fi/Di */
|
|
Packit |
9f0df5 |
0x00, /* TCCKS */
|
|
Packit |
9f0df5 |
0x00, /* GuardTime */
|
|
Packit |
9f0df5 |
0x0A, /* WaitingInteger */
|
|
Packit |
9f0df5 |
0x00 /* ClockStop */
|
|
Packit |
9f0df5 |
};
|
|
Packit |
9f0df5 |
RESPONSECODE ret;
|
|
Packit |
9f0df5 |
double f, d;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TA1 is not default */
|
|
Packit |
9f0df5 |
if (PPS_HAS_PPS1(pps))
|
|
Packit |
9f0df5 |
param[0] = pps[2];
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (ATR_CONVENTION_INVERSE == convention)
|
|
Packit |
9f0df5 |
param[1] |= 0x02;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* get TC1 Extra guard time */
|
|
Packit |
9f0df5 |
if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
|
|
Packit |
9f0df5 |
param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* TC2 WWT */
|
|
Packit |
9f0df5 |
if (atr.ib[1][ATR_INTERFACE_BYTE_TC].present)
|
|
Packit |
9f0df5 |
param[3] = atr.ib[1][ATR_INTERFACE_BYTE_TC].value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* compute communication timeout */
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
|
|
Packit |
9f0df5 |
(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_desc->readTimeout = T0_card_timeout(f, d, param[2] /* TC1 */,
|
|
Packit |
9f0df5 |
param[3] /* TC2 */, ccid_desc->dwDefaultClock);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Communication timeout: %d ms", ccid_desc->readTimeout);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ret = SetParameters(reader_index, 0, sizeof(param), param);
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS != ret)
|
|
Packit |
9f0df5 |
return ret;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* set IFSC & IFSD in T=1 */
|
|
Packit |
9f0df5 |
if (SCARD_PROTOCOL_T1 == Protocol)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
t1_state_t *t1 = &(ccid_slot -> t1);
|
|
Packit |
9f0df5 |
int i, ifsc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ifsc = get_IFSC(&atr, &i);
|
|
Packit |
9f0df5 |
if (ifsc > 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
|
|
Packit |
9f0df5 |
(void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSC, ifsc);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* IFSD not negociated by the reader? */
|
|
Packit |
9f0df5 |
if (! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_IFSD))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Negotiate IFSD at %d", ccid_desc -> dwMaxIFSD);
|
|
Packit |
9f0df5 |
if (t1_negotiate_ifsd(t1, 0, ccid_desc -> dwMaxIFSD) < 0)
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
(void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSD, ccid_desc -> dwMaxIFSD);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM3("T=1: IFSC=%d, IFSD=%d", t1->ifsc, t1->ifsd);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
end:
|
|
Packit |
9f0df5 |
/* store used protocol for use by the secure commands (verify/change PIN) */
|
|
Packit |
9f0df5 |
ccid_desc->cardProtocol = Protocol;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
} /* IFDHSetProtocolParameters */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
|
|
Packit |
9f0df5 |
PUCHAR Atr, PDWORD AtrLength)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function controls the power and reset signals of the smartcard
|
|
Packit |
9f0df5 |
* reader at the particular reader/slot specified by Lun.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Action - Action to be taken on the card.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_POWER_UP - Power and reset the card if not done so (store the
|
|
Packit |
9f0df5 |
* ATR and return it and its length).
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_POWER_DOWN - Power down the card if not done already
|
|
Packit |
9f0df5 |
* (Atr/AtrLength should be zero'd)
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_RESET - Perform a quick reset on the card. If the card is not
|
|
Packit |
9f0df5 |
* powered power up the card. (Store and return the Atr/Length)
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Atr - Answer to Reset of the card. The driver is responsible for
|
|
Packit |
9f0df5 |
* caching this value in case IFDHGetCapabilities is called requesting
|
|
Packit |
9f0df5 |
* the ATR and its length. This should not exceed MAX_ATR_SIZE.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* AtrLength - Length of the Atr. This should not exceed
|
|
Packit |
9f0df5 |
* MAX_ATR_SIZE.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Notes:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Memory cards without an ATR should return IFD_SUCCESS on reset but
|
|
Packit |
9f0df5 |
* the Atr should be zero'd and the length should be zero
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Reset errors should return zero for the AtrLength and return
|
|
Packit |
9f0df5 |
* IFD_ERROR_POWER_ACTION.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
|
|
Packit |
9f0df5 |
* IFD_NOT_SUPPORTED
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
unsigned int nlength;
|
|
Packit |
9f0df5 |
RESPONSECODE return_value = IFD_SUCCESS;
|
|
Packit |
9f0df5 |
unsigned char pcbuffer[10+MAX_ATR_SIZE];
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
#ifndef NO_LOG
|
|
Packit |
9f0df5 |
const char *actions[] = { "PowerUp", "PowerDown", "Reset" };
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
unsigned int oldReadTimeout;
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_descriptor;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* By default, assume it won't work :) */
|
|
Packit |
9f0df5 |
*AtrLength = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO4("action: %s, %s (lun: " DWORD_X ")",
|
|
Packit |
9f0df5 |
actions[Action-IFD_POWER_UP], CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
switch (Action)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
case IFD_POWER_DOWN:
|
|
Packit |
9f0df5 |
/* Clear ATR buffer */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].nATRLength = 0;
|
|
Packit |
9f0df5 |
*CcidSlots[reader_index].pcATRBuffer = '\0';
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Memorise the request */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PDWN;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* send the command */
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS != CmdPowerOff(reader_index))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("PowerDown failed");
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_POWER_ACTION;
|
|
Packit |
9f0df5 |
goto end;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* clear T=1 context */
|
|
Packit |
9f0df5 |
t1_release(&(get_ccid_slot(reader_index) -> t1));
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case IFD_POWER_UP:
|
|
Packit |
9f0df5 |
case IFD_RESET:
|
|
Packit |
9f0df5 |
/* save the current read timeout computed from card capabilities */
|
|
Packit |
9f0df5 |
ccid_descriptor = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
oldReadTimeout = ccid_descriptor->readTimeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* The German eID card is bogus and need to be powered off
|
|
Packit |
9f0df5 |
* before a power on */
|
|
Packit |
9f0df5 |
if (KOBIL_IDTOKEN == ccid_descriptor -> readerID)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* send the command */
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS != CmdPowerOff(reader_index))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("PowerDown failed");
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_POWER_ACTION;
|
|
Packit |
9f0df5 |
goto end;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* use a very long timeout since the card can use up to
|
|
Packit |
9f0df5 |
* (9600+12)*33 ETU in total
|
|
Packit |
9f0df5 |
* 12 ETU per byte
|
|
Packit |
9f0df5 |
* 9600 ETU max between each byte
|
|
Packit |
9f0df5 |
* 33 bytes max for ATR
|
|
Packit |
9f0df5 |
* 1 ETU = 372 cycles during ATR
|
|
Packit |
9f0df5 |
* with a 4 MHz clock => 29 seconds
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
ccid_descriptor->readTimeout = 60*1000;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
nlength = sizeof(pcbuffer);
|
|
Packit |
9f0df5 |
return_value = CmdPowerOn(reader_index, &nlength, pcbuffer,
|
|
Packit |
9f0df5 |
PowerOnVoltage);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* set back the old timeout */
|
|
Packit |
9f0df5 |
ccid_descriptor->readTimeout = oldReadTimeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (return_value != IFD_SUCCESS)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* used by GemCore SIM PRO: no card is present */
|
|
Packit |
9f0df5 |
if (GEMCORESIMPRO == ccid_descriptor -> readerID)
|
|
Packit |
9f0df5 |
get_ccid_descriptor(reader_index)->dwSlotStatus
|
|
Packit |
9f0df5 |
= IFD_ICC_NOT_PRESENT;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("PowerUp failed");
|
|
Packit |
9f0df5 |
return_value = IFD_ERROR_POWER_ACTION;
|
|
Packit |
9f0df5 |
goto end;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Power up successful, set state variable to memorise it */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PUP;
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags &= ~MASK_POWERFLAGS_PDWN;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Reset is returned, even if TCK is wrong */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].nATRLength = *AtrLength =
|
|
Packit |
9f0df5 |
(nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
|
|
Packit |
9f0df5 |
memcpy(Atr, pcbuffer, *AtrLength);
|
|
Packit |
9f0df5 |
memcpy(CcidSlots[reader_index].pcATRBuffer, pcbuffer, *AtrLength);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* initialise T=1 context */
|
|
Packit |
9f0df5 |
(void)t1_init(&(get_ccid_slot(reader_index) -> t1), reader_index);
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
default:
|
|
Packit |
9f0df5 |
DEBUG_CRITICAL("Action not supported");
|
|
Packit |
9f0df5 |
return_value = IFD_NOT_SUPPORTED;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
end:
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
} /* IFDHPowerICC */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
|
|
Packit |
9f0df5 |
PUCHAR TxBuffer, DWORD TxLength,
|
|
Packit |
9f0df5 |
PUCHAR RxBuffer, PDWORD RxLength, /*@unused@*/ PSCARD_IO_HEADER RecvPci)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function performs an APDU exchange with the card/slot
|
|
Packit |
9f0df5 |
* specified by Lun. The driver is responsible for performing any
|
|
Packit |
9f0df5 |
* protocol specific exchanges such as T=0/1 ... differences. Calling
|
|
Packit |
9f0df5 |
* this function will abstract all protocol differences.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* SendPci Protocol - 0, 1, .... 14 Length - Not used.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
|
|
Packit |
9f0df5 |
* 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
|
|
Packit |
9f0df5 |
* example (0x61 0x14) RxLength - Length of the received APDU. This
|
|
Packit |
9f0df5 |
* function will be passed the size of the buffer of RxBuffer and this
|
|
Packit |
9f0df5 |
* function is responsible for setting this to the length of the
|
|
Packit |
9f0df5 |
* received APDU. This should be ZERO on all errors. The resource
|
|
Packit |
9f0df5 |
* manager will take responsibility of zeroing out any temporary APDU
|
|
Packit |
9f0df5 |
* buffers for security reasons.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* RecvPci Protocol - 0, 1, .... 14 Length - Not used.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Notes: The driver is responsible for knowing what type of card it
|
|
Packit |
9f0df5 |
* has. If the current slot/card contains a memory card then this
|
|
Packit |
9f0df5 |
* command should ignore the Protocol and use the MCT style commands
|
|
Packit |
9f0df5 |
* for support for these style cards and transmit them appropriately.
|
|
Packit |
9f0df5 |
* If your reader does not support memory cards or you don't want to
|
|
Packit |
9f0df5 |
* then ignore this.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* RxLength should be set to zero on error.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
|
|
Packit |
9f0df5 |
* IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
RESPONSECODE return_value;
|
|
Packit |
9f0df5 |
unsigned int rx_length;
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
int old_read_timeout;
|
|
Packit |
9f0df5 |
int restore_timeout = FALSE;
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_descriptor;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)RecvPci;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_descriptor = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
|
|
Packit |
9f0df5 |
Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* special APDU for the Kobil IDToken (CLASS = 0xFF) */
|
|
Packit |
9f0df5 |
if (KOBIL_IDTOKEN == ccid_descriptor -> readerID)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
char manufacturer[] = {0xFF, 0x9A, 0x01, 0x01, 0x00};
|
|
Packit |
9f0df5 |
char product_name[] = {0xFF, 0x9A, 0x01, 0x03, 0x00};
|
|
Packit |
9f0df5 |
char firmware_version[] = {0xFF, 0x9A, 0x01, 0x06, 0x00};
|
|
Packit |
9f0df5 |
char driver_version[] = {0xFF, 0x9A, 0x01, 0x07, 0x00};
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((sizeof manufacturer == TxLength)
|
|
Packit |
9f0df5 |
&& (memcmp(TxBuffer, manufacturer, sizeof manufacturer) == 0))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("IDToken: Manufacturer command");
|
|
Packit |
9f0df5 |
memcpy(RxBuffer, "KOBIL systems\220\0", 15);
|
|
Packit |
9f0df5 |
*RxLength = 15;
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((sizeof product_name == TxLength)
|
|
Packit |
9f0df5 |
&& (memcmp(TxBuffer, product_name, sizeof product_name) == 0))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("IDToken: Product name command");
|
|
Packit |
9f0df5 |
memcpy(RxBuffer, "IDToken\220\0", 9);
|
|
Packit |
9f0df5 |
*RxLength = 9;
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((sizeof firmware_version == TxLength)
|
|
Packit |
9f0df5 |
&& (memcmp(TxBuffer, firmware_version, sizeof firmware_version) == 0))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int IFD_bcdDevice = ccid_descriptor -> IFD_bcdDevice;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO1("IDToken: Firmware version command");
|
|
Packit |
9f0df5 |
*RxLength = sprintf((char *)RxBuffer, "%X.%02X",
|
|
Packit |
9f0df5 |
IFD_bcdDevice >> 8, IFD_bcdDevice & 0xFF);
|
|
Packit |
9f0df5 |
RxBuffer[(*RxLength)++] = 0x90;
|
|
Packit |
9f0df5 |
RxBuffer[(*RxLength)++] = 0x00;
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((sizeof driver_version == TxLength)
|
|
Packit |
9f0df5 |
&& (memcmp(TxBuffer, driver_version, sizeof driver_version) == 0))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("IDToken: Driver version command");
|
|
Packit |
9f0df5 |
#define DRIVER_VERSION "2012.2.7\220\0"
|
|
Packit |
9f0df5 |
memcpy(RxBuffer, DRIVER_VERSION, sizeof DRIVER_VERSION -1);
|
|
Packit |
9f0df5 |
*RxLength = sizeof DRIVER_VERSION -1;
|
|
Packit |
9f0df5 |
return IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Pseudo-APDU as defined in PC/SC v2 part 10 supplement document
|
|
Packit |
9f0df5 |
* CLA=0xFF, INS=0xC2, P1=0x01 */
|
|
Packit |
9f0df5 |
if (0 == memcmp(TxBuffer, "\xFF\xC2\x01", 3))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* Yes, use the same timeout as for SCardControl() */
|
|
Packit |
9f0df5 |
restore_timeout = TRUE;
|
|
Packit |
9f0df5 |
old_read_timeout = ccid_descriptor -> readTimeout;
|
|
Packit |
9f0df5 |
ccid_descriptor -> readTimeout = 90 * 1000; /* 90 seconds */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
rx_length = *RxLength;
|
|
Packit |
9f0df5 |
return_value = CmdXfrBlock(reader_index, TxLength, TxBuffer, &rx_length,
|
|
Packit |
9f0df5 |
RxBuffer, SendPci.Protocol);
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS == return_value)
|
|
Packit |
9f0df5 |
*RxLength = rx_length;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
*RxLength = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* restore timeout */
|
|
Packit |
9f0df5 |
if (restore_timeout)
|
|
Packit |
9f0df5 |
ccid_descriptor -> readTimeout = old_read_timeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
} /* IFDHTransmitToICC */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode,
|
|
Packit |
9f0df5 |
PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength,
|
|
Packit |
9f0df5 |
PDWORD pdwBytesReturned)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function performs a data exchange with the reader (not the
|
|
Packit |
9f0df5 |
* card) specified by Lun. Here XXXX will only be used. It is
|
|
Packit |
9f0df5 |
* responsible for abstracting functionality such as PIN pads,
|
|
Packit |
9f0df5 |
* biometrics, LCD panels, etc. You should follow the MCT, CTBCS
|
|
Packit |
9f0df5 |
* specifications for a list of accepted commands to implement.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
|
|
Packit |
9f0df5 |
* - Receive data RxLength - Length of the received data. This
|
|
Packit |
9f0df5 |
* function will be passed the length of the buffer RxBuffer and it
|
|
Packit |
9f0df5 |
* must set this to the length of the received data.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Notes: RxLength should be zero on error.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
RESPONSECODE return_value = IFD_ERROR_NOT_SUPPORTED;
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_descriptor;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
reader_index = LunToReaderIndex(Lun);
|
|
Packit |
9f0df5 |
if ((-1 == reader_index) || (NULL == pdwBytesReturned))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_descriptor = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO4("ControlCode: 0x" DWORD_X ", %s (lun: " DWORD_X ")",
|
|
Packit |
9f0df5 |
dwControlCode, CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
DEBUG_INFO_XXD("Control TxBuffer: ", TxBuffer, TxLength);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Set the return length to 0 to avoid problems */
|
|
Packit |
9f0df5 |
*pdwBytesReturned = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE == dwControlCode)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int allowed = (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED);
|
|
Packit |
9f0df5 |
int readerID = ccid_descriptor -> readerID;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (VENDOR_GEMALTO == GET_VENDOR(readerID))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned char switch_interface[] = { 0x52, 0xF8, 0x04, 0x01, 0x00 };
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* get firmware version escape command */
|
|
Packit |
9f0df5 |
if ((1 == TxLength) && (0x02 == TxBuffer[0]))
|
|
Packit |
9f0df5 |
allowed = TRUE;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* switch interface escape command on the GemProx DU
|
|
Packit |
9f0df5 |
* the next byte in the command is the interface:
|
|
Packit |
9f0df5 |
* 0x01 switch to contactless interface
|
|
Packit |
9f0df5 |
* 0x02 switch to contact interface
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
if ((GEMALTOPROXDU == readerID)
|
|
Packit |
9f0df5 |
&& (6 == TxLength)
|
|
Packit |
9f0df5 |
&& (0 == memcmp(TxBuffer, switch_interface, sizeof(switch_interface))))
|
|
Packit |
9f0df5 |
allowed = TRUE;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (!allowed)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("ifd exchange (Escape command) not allowed");
|
|
Packit |
9f0df5 |
return_value = IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int iBytesReturned;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
iBytesReturned = RxLength;
|
|
Packit |
9f0df5 |
/* 30 seconds timeout for long commands */
|
|
Packit |
9f0df5 |
return_value = CmdEscape(reader_index, TxBuffer, TxLength,
|
|
Packit |
9f0df5 |
RxBuffer, &iBytesReturned, 30*1000);
|
|
Packit |
9f0df5 |
*pdwBytesReturned = iBytesReturned;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Implement the PC/SC v2.02.07 Part 10 IOCTL mechanism */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Query for features */
|
|
Packit |
9f0df5 |
/* 0x313520 is the Windows value for SCARD_CTL_CODE(3400)
|
|
Packit |
9f0df5 |
* This hack is needed for RDP applications */
|
|
Packit |
9f0df5 |
if ((CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode)
|
|
Packit |
9f0df5 |
|| (0x313520 == dwControlCode))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int iBytesReturned = 0;
|
|
Packit |
9f0df5 |
PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)RxBuffer;
|
|
Packit |
9f0df5 |
int readerID = ccid_descriptor -> readerID;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* we need room for up to six records */
|
|
Packit |
9f0df5 |
if (RxLength < 6 * sizeof(PCSC_TLV_STRUCTURE))
|
|
Packit |
9f0df5 |
return IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* We can only support direct verify and/or modify currently */
|
|
Packit |
9f0df5 |
if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_VERIFY)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT;
|
|
Packit |
9f0df5 |
pcsc_tlv -> length = 0x04; /* always 0x04 */
|
|
Packit |
9f0df5 |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
pcsc_tlv++;
|
|
Packit |
9f0df5 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_MODIFY)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT;
|
|
Packit |
9f0df5 |
pcsc_tlv -> length = 0x04; /* always 0x04 */
|
|
Packit |
9f0df5 |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
pcsc_tlv++;
|
|
Packit |
9f0df5 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Provide IFD_PIN_PROPERTIES only for pinpad readers */
|
|
Packit |
9f0df5 |
if (ccid_descriptor -> bPINSupport)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES;
|
|
Packit |
9f0df5 |
pcsc_tlv -> length = 0x04; /* always 0x04 */
|
|
Packit |
9f0df5 |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_IFD_PIN_PROPERTIES);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
pcsc_tlv++;
|
|
Packit |
9f0df5 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((KOBIL_TRIBANK == readerID)
|
|
Packit |
9f0df5 |
|| (KOBIL_MIDENTITY_VISUAL == readerID))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pcsc_tlv -> tag = FEATURE_MCT_READER_DIRECT;
|
|
Packit |
9f0df5 |
pcsc_tlv -> length = 0x04; /* always 0x04 */
|
|
Packit |
9f0df5 |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_MCT_READER_DIRECT);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
pcsc_tlv++;
|
|
Packit |
9f0df5 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
pcsc_tlv -> tag = FEATURE_GET_TLV_PROPERTIES;
|
|
Packit |
9f0df5 |
pcsc_tlv -> length = 0x04; /* always 0x04 */
|
|
Packit |
9f0df5 |
pcsc_tlv -> value = htonl(IOCTL_FEATURE_GET_TLV_PROPERTIES);
|
|
Packit |
9f0df5 |
pcsc_tlv++;
|
|
Packit |
9f0df5 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE */
|
|
Packit |
9f0df5 |
if (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
pcsc_tlv -> tag = FEATURE_CCID_ESC_COMMAND;
|
|
Packit |
9f0df5 |
pcsc_tlv -> length = 0x04; /* always 0x04 */
|
|
Packit |
9f0df5 |
pcsc_tlv -> value = htonl(IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
pcsc_tlv++;
|
|
Packit |
9f0df5 |
iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
*pdwBytesReturned = iBytesReturned;
|
|
Packit |
9f0df5 |
return_value = IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Get PIN handling capabilities */
|
|
Packit |
9f0df5 |
if (IOCTL_FEATURE_IFD_PIN_PROPERTIES == dwControlCode)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)RxBuffer;
|
|
Packit |
9f0df5 |
int validation;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (RxLength < sizeof(PIN_PROPERTIES_STRUCTURE))
|
|
Packit |
9f0df5 |
return IFD_ERROR_INSUFFICIENT_BUFFER;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Only give the LCD size for now */
|
|
Packit |
9f0df5 |
caps -> wLcdLayout = ccid_descriptor -> wLcdLayout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Hardcoded special reader cases */
|
|
Packit |
9f0df5 |
switch (ccid_descriptor->readerID)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
case GEMPCPINPAD:
|
|
Packit |
9f0df5 |
case VEGAALPHA:
|
|
Packit |
9f0df5 |
case CHERRYST2000:
|
|
Packit |
9f0df5 |
validation = 0x02; /* Validation key pressed */
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
default:
|
|
Packit |
9f0df5 |
validation = 0x07; /* Default */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Gemalto readers providing firmware features */
|
|
Packit |
9f0df5 |
if (ccid_descriptor -> gemalto_firmware_features)
|
|
Packit |
9f0df5 |
validation = ccid_descriptor -> gemalto_firmware_features -> bEntryValidationCondition;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
caps -> bEntryValidationCondition = validation;
|
|
Packit |
9f0df5 |
caps -> bTimeOut2 = 0x00; /* We do not distinguish bTimeOut from TimeOut2 */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
*pdwBytesReturned = sizeof(*caps);
|
|
Packit |
9f0df5 |
return_value = IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Reader features */
|
|
Packit |
9f0df5 |
if (IOCTL_FEATURE_GET_TLV_PROPERTIES == dwControlCode)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int p = 0;
|
|
Packit |
9f0df5 |
int tmp;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* wLcdLayout */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdLayout; /* tag */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 2; /* length */
|
|
Packit |
9f0df5 |
tmp = ccid_descriptor -> wLcdLayout;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = (tmp >> 8) & 0xFF;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* only if the reader has a display */
|
|
Packit |
9f0df5 |
if (ccid_descriptor -> wLcdLayout)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* wLcdMaxCharacters */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxCharacters; /* tag */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 2; /* length */
|
|
Packit |
9f0df5 |
tmp = ccid_descriptor -> wLcdLayout & 0xFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = (tmp >> 8) & 0xFF;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* wLcdMaxLines */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxLines; /* tag */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 2; /* length */
|
|
Packit |
9f0df5 |
tmp = ccid_descriptor -> wLcdLayout >> 8;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = (tmp >> 8) & 0xFF;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bTimeOut2 */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bTimeOut2;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
/* IFD does not distinguish bTimeOut from bTimeOut2 */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 0x00;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* sFirmwareID */
|
|
Packit |
9f0df5 |
if (VENDOR_GEMALTO == GET_VENDOR(ccid_descriptor -> readerID))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned char firmware[256];
|
|
Packit |
9f0df5 |
const unsigned char cmd[] = { 0x02 };
|
|
Packit |
9f0df5 |
RESPONSECODE ret;
|
|
Packit |
9f0df5 |
unsigned int len;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
len = sizeof(firmware);
|
|
Packit |
9f0df5 |
ret = CmdEscape(reader_index, cmd, sizeof(cmd), firmware, &len, 0);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS == ret)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_sFirmwareID;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = len;
|
|
Packit |
9f0df5 |
memcpy(&RxBuffer[p], firmware, len);
|
|
Packit |
9f0df5 |
p += len;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Gemalto PC Pinpad V1 */
|
|
Packit |
9f0df5 |
if (((GEMPCPINPAD == ccid_descriptor -> readerID)
|
|
Packit |
9f0df5 |
&& (0x0100 == ccid_descriptor -> IFD_bcdDevice))
|
|
Packit |
9f0df5 |
/* Covadis Véga-Alpha */
|
|
Packit |
9f0df5 |
|| (VEGAALPHA == ccid_descriptor->readerID))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* bMinPINSize */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 4; /* min PIN size */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bMaxPINSize */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 8; /* max PIN size */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bEntryValidationCondition */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 0x02; /* validation key pressed */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Cherry GmbH SmartTerminal ST-2xxx */
|
|
Packit |
9f0df5 |
if (CHERRYST2000 == ccid_descriptor -> readerID)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* bMinPINSize */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 0; /* min PIN size */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bMaxPINSize */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 25; /* max PIN size */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bEntryValidationCondition */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 0x02; /* validation key pressed */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Gemalto readers providing firmware features */
|
|
Packit |
9f0df5 |
if (ccid_descriptor -> gemalto_firmware_features)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
struct GEMALTO_FIRMWARE_FEATURES *features = ccid_descriptor -> gemalto_firmware_features;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bMinPINSize */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = features -> MinimumPINSize; /* min PIN size */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bMaxPINSize */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = features -> MaximumPINSize; /* max PIN size */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bEntryValidationCondition */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = features -> bEntryValidationCondition; /* validation key pressed */
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* bPPDUSupport */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bPPDUSupport;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 1; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] =
|
|
Packit |
9f0df5 |
(DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED) ? 1 : 0;
|
|
Packit |
9f0df5 |
/* bit0: PPDU is supported over SCardControl using
|
|
Packit |
9f0df5 |
* FEATURE_CCID_ESC_COMMAND */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* wIdVendor */
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int idVendor = ccid_descriptor -> readerID >> 16;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdVendor;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 2; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = idVendor & 0xFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = idVendor >> 8;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* wIdProduct */
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int idProduct = ccid_descriptor -> readerID & 0xFFFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdProduct;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 2; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = idProduct & 0xFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = idProduct >> 8;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* dwMaxAPDUDataSize */
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int MaxAPDUDataSize = 0; /* short APDU only by default */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* reader is TPDU or extended APDU */
|
|
Packit |
9f0df5 |
if ((ccid_descriptor -> dwFeatures & CCID_CLASS_EXTENDED_APDU)
|
|
Packit |
9f0df5 |
|| (ccid_descriptor -> dwFeatures & CCID_CLASS_TPDU))
|
|
Packit |
9f0df5 |
MaxAPDUDataSize = 0x10000;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
RxBuffer[p++] = PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = 4; /* length */
|
|
Packit |
9f0df5 |
RxBuffer[p++] = MaxAPDUDataSize & 0xFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = (MaxAPDUDataSize >> 8) & 0xFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = (MaxAPDUDataSize >> 16) & 0xFF;
|
|
Packit |
9f0df5 |
RxBuffer[p++] = (MaxAPDUDataSize >> 24) & 0xFF;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
*pdwBytesReturned = p;
|
|
Packit |
9f0df5 |
return_value = IFD_SUCCESS;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Verify a PIN, plain CCID */
|
|
Packit |
9f0df5 |
if (IOCTL_FEATURE_VERIFY_PIN_DIRECT == dwControlCode)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int iBytesReturned;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
iBytesReturned = RxLength;
|
|
Packit |
9f0df5 |
return_value = SecurePINVerify(reader_index, TxBuffer, TxLength,
|
|
Packit |
9f0df5 |
RxBuffer, &iBytesReturned);
|
|
Packit |
9f0df5 |
*pdwBytesReturned = iBytesReturned;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Modify a PIN, plain CCID */
|
|
Packit |
9f0df5 |
if (IOCTL_FEATURE_MODIFY_PIN_DIRECT == dwControlCode)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int iBytesReturned;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
iBytesReturned = RxLength;
|
|
Packit |
9f0df5 |
return_value = SecurePINModify(reader_index, TxBuffer, TxLength,
|
|
Packit |
9f0df5 |
RxBuffer, &iBytesReturned);
|
|
Packit |
9f0df5 |
*pdwBytesReturned = iBytesReturned;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* MCT: Multifunctional Card Terminal */
|
|
Packit |
9f0df5 |
if (IOCTL_FEATURE_MCT_READER_DIRECT == dwControlCode)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
if ( (TxBuffer[0] != 0x20) /* CLA */
|
|
Packit |
9f0df5 |
|| ((TxBuffer[1] & 0xF0) != 0x70) /* INS */
|
|
Packit |
9f0df5 |
/* valid INS are
|
|
Packit |
9f0df5 |
* 0x70: SECODER INFO
|
|
Packit |
9f0df5 |
* 0x71: SECODER SELECT APPLICATION
|
|
Packit |
9f0df5 |
* 0x72: SECODER APPLICATION ACTIVE
|
|
Packit |
9f0df5 |
* 0x73: SECODER DATA CONFIRMATION
|
|
Packit |
9f0df5 |
* 0x74: SECODER PROCESS AUTHENTICATION TOKEN */
|
|
Packit |
9f0df5 |
|| ((TxBuffer[1] & 0x0F) > 4)
|
|
Packit |
9f0df5 |
|| (TxBuffer[2] != 0x00) /* P1 */
|
|
Packit |
9f0df5 |
|| (TxBuffer[3] != 0x00) /* P2 */
|
|
Packit |
9f0df5 |
|| (TxBuffer[4] != 0x00) /* Lind */
|
|
Packit |
9f0df5 |
)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("MCT Command refused by driver");
|
|
Packit |
9f0df5 |
return_value = IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int iBytesReturned;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* we just transmit the buffer as a CCID Escape command */
|
|
Packit |
9f0df5 |
iBytesReturned = RxLength;
|
|
Packit |
9f0df5 |
return_value = CmdEscape(reader_index, TxBuffer, TxLength,
|
|
Packit |
9f0df5 |
RxBuffer, &iBytesReturned, 0);
|
|
Packit |
9f0df5 |
*pdwBytesReturned = iBytesReturned;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (IFD_SUCCESS != return_value)
|
|
Packit |
9f0df5 |
*pdwBytesReturned = 0;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO_XXD("Control RxBuffer: ", RxBuffer, *pdwBytesReturned);
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
} /* IFDHControl */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
EXTERNAL RESPONSECODE IFDHICCPresence(DWORD Lun)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
* This function returns the status of the card inserted in the
|
|
Packit |
9f0df5 |
* reader/slot specified by Lun. It will return either:
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
|
|
Packit |
9f0df5 |
* IFD_COMMUNICATION_ERROR
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
|
|
Packit |
9f0df5 |
RESPONSECODE return_value = IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
int oldLogLevel;
|
|
Packit |
9f0df5 |
int reader_index;
|
|
Packit |
9f0df5 |
_ccid_descriptor *ccid_descriptor;
|
|
Packit |
9f0df5 |
unsigned int oldReadTimeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (-1 == (reader_index = LunToReaderIndex(Lun)))
|
|
Packit |
9f0df5 |
return IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_PERIODIC3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, Lun);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ccid_descriptor = get_ccid_descriptor(reader_index);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if ((GEMCORESIMPRO == ccid_descriptor->readerID)
|
|
Packit |
9f0df5 |
&& (ccid_descriptor->IFD_bcdDevice < 0x0200))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* GemCore SIM Pro firmware 2.00 and up features
|
|
Packit |
9f0df5 |
* a full independant second slot */
|
|
Packit |
9f0df5 |
return_value = ccid_descriptor->dwSlotStatus;
|
|
Packit |
9f0df5 |
goto end;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* save the current read timeout computed from card capabilities */
|
|
Packit |
9f0df5 |
oldReadTimeout = ccid_descriptor->readTimeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* use default timeout since the reader may not be present anymore */
|
|
Packit |
9f0df5 |
ccid_descriptor->readTimeout = DEFAULT_COM_READ_TIMEOUT;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
|
|
Packit |
9f0df5 |
oldLogLevel = LogLevel;
|
|
Packit |
9f0df5 |
if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
|
|
Packit |
9f0df5 |
LogLevel &= ~DEBUG_LEVEL_COMM;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return_value = CmdGetSlotStatus(reader_index, pcbuffer);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* set back the old timeout */
|
|
Packit |
9f0df5 |
ccid_descriptor->readTimeout = oldReadTimeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* set back the old LogLevel */
|
|
Packit |
9f0df5 |
LogLevel = oldLogLevel;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (return_value != IFD_SUCCESS)
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return_value = IFD_COMMUNICATION_ERROR;
|
|
Packit |
9f0df5 |
switch (pcbuffer[7] & CCID_ICC_STATUS_MASK) /* bStatus */
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
case CCID_ICC_PRESENT_ACTIVE:
|
|
Packit |
9f0df5 |
return_value = IFD_ICC_PRESENT;
|
|
Packit |
9f0df5 |
/* use default slot */
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case CCID_ICC_PRESENT_INACTIVE:
|
|
Packit |
9f0df5 |
if ((CcidSlots[reader_index].bPowerFlags == POWERFLAGS_RAZ)
|
|
Packit |
9f0df5 |
|| (CcidSlots[reader_index].bPowerFlags & MASK_POWERFLAGS_PDWN))
|
|
Packit |
9f0df5 |
/* the card was previously absent */
|
|
Packit |
9f0df5 |
return_value = IFD_ICC_PRESENT;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* the card was previously present but has been
|
|
Packit |
9f0df5 |
* removed and inserted between two consecutive
|
|
Packit |
9f0df5 |
* IFDHICCPresence() calls */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
|
|
Packit |
9f0df5 |
return_value = IFD_ICC_NOT_PRESENT;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case CCID_ICC_ABSENT:
|
|
Packit |
9f0df5 |
/* Reset ATR buffer */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].nATRLength = 0;
|
|
Packit |
9f0df5 |
*CcidSlots[reader_index].pcATRBuffer = '\0';
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Reset PowerFlags */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return_value = IFD_ICC_NOT_PRESENT;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#if 0
|
|
Packit |
9f0df5 |
/* SCR331-DI contactless reader */
|
|
Packit |
9f0df5 |
if (((SCR331DI == ccid_descriptor->readerID)
|
|
Packit |
9f0df5 |
|| (SDI010 == ccid_descriptor->readerID)
|
|
Packit |
9f0df5 |
|| (SCR331DINTTCOM == ccid_descriptor->readerID))
|
|
Packit |
9f0df5 |
&& (ccid_descriptor->bCurrentSlotIndex > 0))
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned char cmd[] = { 0x11 };
|
|
Packit |
9f0df5 |
/* command: 11 ??
|
|
Packit |
9f0df5 |
* response: 00 11 01 ?? no card
|
|
Packit |
9f0df5 |
* 01 04 00 ?? card present */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
unsigned char res[10];
|
|
Packit |
9f0df5 |
unsigned int length_res = sizeof(res);
|
|
Packit |
9f0df5 |
RESPONSECODE ret;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
|
|
Packit |
9f0df5 |
oldLogLevel = LogLevel;
|
|
Packit |
9f0df5 |
if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
|
|
Packit |
9f0df5 |
LogLevel &= ~DEBUG_LEVEL_COMM;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* set back the old LogLevel */
|
|
Packit |
9f0df5 |
LogLevel = oldLogLevel;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (ret != IFD_SUCCESS)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
DEBUG_INFO1("CmdEscape failed");
|
|
Packit |
9f0df5 |
/* simulate a card absent */
|
|
Packit |
9f0df5 |
res[0] = 0;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (0x01 == res[0])
|
|
Packit |
9f0df5 |
return_value = IFD_ICC_PRESENT;
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* Reset ATR buffer */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].nATRLength = 0;
|
|
Packit |
9f0df5 |
*CcidSlots[reader_index].pcATRBuffer = '\0';
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Reset PowerFlags */
|
|
Packit |
9f0df5 |
CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return_value = IFD_ICC_NOT_PRESENT;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
#endif
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
end:
|
|
Packit |
9f0df5 |
DEBUG_PERIODIC2("Card %s",
|
|
Packit |
9f0df5 |
IFD_ICC_PRESENT == return_value ? "present" : "absent");
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return return_value;
|
|
Packit |
9f0df5 |
} /* IFDHICCPresence */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
CcidDesc *get_ccid_slot(unsigned int reader_index)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
return &CcidSlots[reader_index];
|
|
Packit |
9f0df5 |
} /* get_ccid_slot */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
void init_driver(void)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
char infofile[FILENAME_MAX];
|
|
Packit |
9f0df5 |
char *e;
|
|
Packit |
9f0df5 |
int rv;
|
|
Packit |
9f0df5 |
list_t plist, *values;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_INFO1("Driver version: " VERSION);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Info.plist full patch filename */
|
|
Packit |
9f0df5 |
(void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
|
|
Packit |
9f0df5 |
PCSCLITE_HP_DROPDIR, BUNDLE);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
rv = bundleParse(infofile, &plist);
|
|
Packit |
9f0df5 |
if (0 == rv)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* Log level */
|
|
Packit |
9f0df5 |
rv = LTPBundleFindValueWithKey(&plist, "ifdLogLevel", &values);
|
|
Packit |
9f0df5 |
if (0 == rv)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* convert from hex or dec or octal */
|
|
Packit |
9f0df5 |
LogLevel = strtoul(list_get_at(values, 0), NULL, 0);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* print the log level used */
|
|
Packit |
9f0df5 |
DEBUG_INFO2("LogLevel: 0x%.4X", LogLevel);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Driver options */
|
|
Packit |
9f0df5 |
rv = LTPBundleFindValueWithKey(&plist, "ifdDriverOptions", &values);
|
|
Packit |
9f0df5 |
if (0 == rv)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* convert from hex or dec or octal */
|
|
Packit |
9f0df5 |
DriverOptions = strtoul(list_get_at(values, 0), NULL, 0);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* print the log level used */
|
|
Packit |
9f0df5 |
DEBUG_INFO2("DriverOptions: 0x%.4X", DriverOptions);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
bundleRelease(&plist);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
e = getenv("LIBCCID_ifdLogLevel");
|
|
Packit |
9f0df5 |
if (e)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* convert from hex or dec or octal */
|
|
Packit |
9f0df5 |
LogLevel = strtoul(e, NULL, 0);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* print the log level used */
|
|
Packit |
9f0df5 |
DEBUG_INFO2("LogLevel from LIBCCID_ifdLogLevel: 0x%.4X", LogLevel);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* get the voltage parameter */
|
|
Packit |
9f0df5 |
switch ((DriverOptions >> 4) & 0x03)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
case 0:
|
|
Packit |
9f0df5 |
PowerOnVoltage = VOLTAGE_5V;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case 1:
|
|
Packit |
9f0df5 |
PowerOnVoltage = VOLTAGE_3V;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case 2:
|
|
Packit |
9f0df5 |
PowerOnVoltage = VOLTAGE_1_8V;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
case 3:
|
|
Packit |
9f0df5 |
PowerOnVoltage = VOLTAGE_AUTO;
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* initialise the Lun to reader_index mapping */
|
|
Packit |
9f0df5 |
InitReaderIndex();
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DebugInitialized = TRUE;
|
|
Packit |
9f0df5 |
} /* init_driver */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static char find_baud_rate(unsigned int baudrate, unsigned int *list)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int i;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Card baud rate: %d", baudrate);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Does the reader support the announced smart card data speed? */
|
|
Packit |
9f0df5 |
for (i=0;; i++)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* end of array marker */
|
|
Packit |
9f0df5 |
if (0 == list[i])
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
DEBUG_COMM2("Reader can do: %d", list[i]);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* We must take into account that the card_baudrate integral value
|
|
Packit |
9f0df5 |
* is an approximative result, computed from the d/f float result.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
if ((baudrate < list[i] + 2) && (baudrate > list[i] - 2))
|
|
Packit |
9f0df5 |
return TRUE;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return FALSE;
|
|
Packit |
9f0df5 |
} /* find_baud_rate */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
|
|
Packit |
9f0df5 |
int clock_frequency)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
unsigned int timeout = DEFAULT_COM_READ_TIMEOUT;
|
|
Packit |
9f0df5 |
double EGT, WWT;
|
|
Packit |
9f0df5 |
unsigned int t;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Timeout applied on ISO_IN or ISO_OUT card exchange
|
|
Packit |
9f0df5 |
* we choose the maximum computed value.
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* ISO_IN timeout is the sum of:
|
|
Packit |
9f0df5 |
* Terminal: Smart card:
|
|
Packit |
9f0df5 |
* 5 bytes header cmd ->
|
|
Packit |
9f0df5 |
* <- Procedure byte
|
|
Packit |
9f0df5 |
* 256 data bytes ->
|
|
Packit |
9f0df5 |
* <- SW1-SW2
|
|
Packit |
9f0df5 |
* = 261 EGT + 3 WWT + 3 WWT
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* ISO_OUT Timeout is the sum of:
|
|
Packit |
9f0df5 |
* Terminal: Smart card:
|
|
Packit |
9f0df5 |
* 5 bytes header cmd ->
|
|
Packit |
9f0df5 |
* <- Procedure byte + 256 data bytes + SW1-SW2
|
|
Packit |
9f0df5 |
* = 5 EGT + 1 WWT + 259 WWT
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* clock_frequency is in kHz so the times are in milliseconds and not
|
|
Packit |
9f0df5 |
* in seconds */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* may happen with non ISO cards */
|
|
Packit |
9f0df5 |
if ((0 == f) || (0 == d) || (0 == clock_frequency))
|
|
Packit |
9f0df5 |
return 60 * 1000; /* 60 seconds */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* EGT */
|
|
Packit |
9f0df5 |
/* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
|
|
Packit |
9f0df5 |
EGT = 12 * f / d / clock_frequency + (f / d) * TC1 / clock_frequency;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* card WWT */
|
|
Packit |
9f0df5 |
/* see ch. 8.2 Character level, page 15 of ISO 7816-3 */
|
|
Packit |
9f0df5 |
WWT = 960 * TC2 * f / clock_frequency;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* ISO in */
|
|
Packit |
9f0df5 |
t = 261 * EGT + (3 + 3) * WWT;
|
|
Packit |
9f0df5 |
if (timeout < t)
|
|
Packit |
9f0df5 |
timeout = t;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* ISO out */
|
|
Packit |
9f0df5 |
t = 5 * EGT + (1 + 259) * WWT;
|
|
Packit |
9f0df5 |
if (timeout < t)
|
|
Packit |
9f0df5 |
timeout = t;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return timeout;
|
|
Packit |
9f0df5 |
} /* T0_card_timeout */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static unsigned int T1_card_timeout(double f, double d, int TC1,
|
|
Packit |
9f0df5 |
int BWI, int CWI, int clock_frequency)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
double EGT, BWT, CWT, etu;
|
|
Packit |
9f0df5 |
unsigned int timeout;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* Timeout applied on ISO in + ISO out card exchange
|
|
Packit |
9f0df5 |
*
|
|
Packit |
9f0df5 |
* Timeout is the sum of:
|
|
Packit |
9f0df5 |
* - ISO in delay between leading edge of the first character sent by the
|
|
Packit |
9f0df5 |
* interface device and the last one (NAD PCB LN APDU CKS) = 260 EGT,
|
|
Packit |
9f0df5 |
* - delay between ISO in and ISO out = BWT,
|
|
Packit |
9f0df5 |
* - ISO out delay between leading edge of the first character sent by the
|
|
Packit |
9f0df5 |
* card and the last one (NAD PCB LN DATAS CKS) = 260 CWT.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* clock_frequency is in kHz so the times are in milliseconds and not
|
|
Packit |
9f0df5 |
* in seconds */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* may happen with non ISO cards */
|
|
Packit |
9f0df5 |
if ((0 == f) || (0 == d) || (0 == clock_frequency))
|
|
Packit |
9f0df5 |
return 60 * 1000; /* 60 seconds */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* see ch. 6.5.2 Transmission factors F and D, page 12 of ISO 7816-3 */
|
|
Packit |
9f0df5 |
etu = f / d / clock_frequency;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* EGT */
|
|
Packit |
9f0df5 |
/* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
|
|
Packit |
9f0df5 |
EGT = 12 * etu + (f / d) * TC1 / clock_frequency;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* card BWT */
|
|
Packit |
9f0df5 |
/* see ch. 9.5.3.2 Block Waiting Time, page 20 of ISO 7816-3 */
|
|
Packit |
9f0df5 |
BWT = 11 * etu + (1<
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* card CWT */
|
|
Packit |
9f0df5 |
/* see ch. 9.5.3.1 Caracter Waiting Time, page 20 of ISO 7816-3 */
|
|
Packit |
9f0df5 |
CWT = (11 + (1<
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
timeout = 260*EGT + BWT + 260*CWT;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* This is the card/reader timeout. Add 1 second for the libusb
|
|
Packit |
9f0df5 |
* timeout so we get the error from the reader. */
|
|
Packit |
9f0df5 |
timeout += 1000;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return timeout;
|
|
Packit |
9f0df5 |
} /* T1_card_timeout */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static int get_IFSC(ATR_t *atr, int *idx)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int i, ifsc, protocol = -1;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* default return values */
|
|
Packit |
9f0df5 |
ifsc = -1;
|
|
Packit |
9f0df5 |
*idx = -1;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
for (i=0; i
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* TAi (i>2) present and protocol=1 => IFSC */
|
|
Packit |
9f0df5 |
if (i >= 2 && protocol == 1
|
|
Packit |
9f0df5 |
&& atr->ib[i][ATR_INTERFACE_BYTE_TA].present)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
ifsc = atr->ib[i][ATR_INTERFACE_BYTE_TA].value;
|
|
Packit |
9f0df5 |
*idx = i+1;
|
|
Packit |
9f0df5 |
/* only the first TAi (i>2) must be used */
|
|
Packit |
9f0df5 |
break;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* protocol T=? */
|
|
Packit |
9f0df5 |
if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present)
|
|
Packit |
9f0df5 |
protocol = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (ifsc > 254)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
/* 0xFF is not a valid value for IFSC */
|
|
Packit |
9f0df5 |
DEBUG_INFO2("Non ISO IFSC: 0x%X", ifsc);
|
|
Packit |
9f0df5 |
ifsc = 254;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return ifsc;
|
|
Packit |
9f0df5 |
} /* get_IFSC */
|
|
Packit |
9f0df5 |
|