oscam-2.26.01-11942-802-wit.../csctapi/ifd_pcsc.c

391 lines
12 KiB
C

#include "../globals.h"
#ifdef CARDREADER_PCSC
#include "atr.h"
#include "../oscam-string.h"
#if defined(__CYGWIN__)
#define __reserved
#define __nullnullterminated
#include <specstrings.h>
#include <WinSCard.h>
#endif
#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#include <PCSC/pcsclite.h>
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <PCSC/reader.h>
#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include "pcsclite.h"
#include "winscard.h"
#include "wintypes.h"
#include "reader.h"
#endif
#ifndef ERR_INVALID
#define ERR_INVALID -1
#endif
#if defined(__CYGWIN__)
#undef OK
#undef ERROR
#undef LOBYTE
#undef HIBYTE
#endif
#define OK 0
#define ERROR 1
struct pcsc_data
{
bool pcsc_has_card;
char pcsc_name[128];
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
DWORD dwActiveProtocol;
};
static int32_t pcsc_init(struct s_reader *pcsc_reader)
{
ULONG rv;
DWORD dwReaders = 0;
LPSTR mszReaders = NULL;
char *ptr, **readers = NULL;
char *device = pcsc_reader->device;
int32_t nbReaders;
int32_t reader_nb;
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC establish context for PCSC pcsc_reader %s", device);
SCARDCONTEXT hContext;
memset(&hContext, 0, sizeof(hContext));
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
if(rv == SCARD_S_SUCCESS)
{
if(!cs_malloc(&pcsc_reader->crdr_data, sizeof(struct pcsc_data)))
{ return ERROR; }
struct pcsc_data *crdr_data = pcsc_reader->crdr_data;
crdr_data->hContext = hContext;
// here we need to list the pcsc readers and get the name from there,
// the pcsc_reader->device should contain the pcsc_reader number
// and after the actual device name is copied in crdr_data->pcsc_name .
rv = SCardListReaders(crdr_data->hContext, NULL, NULL, &dwReaders);
if(rv != SCARD_S_SUCCESS)
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC failed listing readers [1] : (%lx)", (unsigned long)rv);
return ERROR;
}
if(!cs_malloc(&mszReaders, dwReaders))
{ return ERROR; }
rv = SCardListReaders(crdr_data->hContext, NULL, mszReaders, &dwReaders);
if(rv != SCARD_S_SUCCESS)
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC failed listing readers [2]: (%lx)", (unsigned long)rv);
NULLFREE(mszReaders);
return ERROR;
}
/* Extract readers from the null separated string and get the total
* number of readers
*/
nbReaders = 0;
ptr = mszReaders;
while(*ptr != '\0')
{
ptr += cs_strlen(ptr) + 1;
nbReaders++;
}
if(nbReaders == 0)
{
rdr_log(pcsc_reader, "PCSC : no pcsc_reader found");
NULLFREE(mszReaders);
return ERROR;
}
if(!cs_malloc(&readers, nbReaders * sizeof(char *)))
{
NULLFREE(mszReaders);
return ERROR;
}
char* device_line;
char* device_first;
char* device_second;
device_line = strdup((const char *)&pcsc_reader->device);
device_first = strsep(&device_line, ":");
device_second = strsep(&device_line, ":");
reader_nb = atoi(device_first);
/* fill the readers table */
nbReaders = 0;
ptr = mszReaders;
while(*ptr != '\0')
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC pcsc_reader %d: %s", nbReaders, ptr);
readers[nbReaders] = ptr;
if ((reader_nb == -1) && (device_second != NULL) && strstr(ptr,device_second)){
reader_nb = nbReaders;
}
ptr += cs_strlen(ptr) + 1;
nbReaders++;
}
if(reader_nb < 0 || reader_nb >= nbReaders)
{
rdr_log(pcsc_reader, "Wrong pcsc_reader index: %d", reader_nb);
NULLFREE(mszReaders);
NULLFREE(readers);
NULLFREE(device_line);
return ERROR;
}
if (readers)
{
snprintf(crdr_data->pcsc_name, sizeof(crdr_data->pcsc_name), "%s", readers[reader_nb]);
NULLFREE(readers);
}
NULLFREE(mszReaders);
NULLFREE(device_line);
}
else
{
rdr_log(pcsc_reader, "PCSC failed establish context (%lx)", (unsigned long)rv);
return ERROR;
}
return OK;
}
static int32_t pcsc_do_api(struct s_reader *pcsc_reader, const uint8_t *buf, uint8_t *cta_res, uint16_t *cta_lr, int32_t l)
{
LONG rv;
DWORD dwSendLength, dwRecvLength;
*cta_lr = 0;
if(!l)
{
rdr_log(pcsc_reader, "ERROR: Data length to be send to the pcsc_reader is %d", l);
return ERROR;
}
char tmp[l * 3];
dwRecvLength = CTA_RES_LEN;
struct pcsc_data *crdr_data = pcsc_reader->crdr_data;
if(pcsc_reader->resetalways)
{
SCardReconnect(crdr_data->hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &crdr_data->dwActiveProtocol);
}
if(crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0)
{
// explanantion as to why we do the test on buf[4] :
// Issuing a command without exchanging data :
//To issue a command to the card that does not involve the exchange of data (either sent or received), the send and receive buffers must be formatted as follows.
//The pbSendBuffer buffer must contain the CLA, INS, P1, and P2 values for the T=0 operation. The P3 value is not sent. (This is to differentiate the header from the case where 256 bytes are expected to be returned.)
//The cbSendLength parameter must be set to four, the size of the T=0 header information (CLA, INS, P1, and P2).
//The pbRecvBuffer will receive the SW1 and SW2 status codes from the operation.
//The pcbRecvLength should be at least two and will be set to two upon return.
if(buf[4])
{ dwSendLength = l; }
else
{ dwSendLength = l - 1; }
rdr_log_dbg(pcsc_reader, D_DEVICE, "sending %lu bytes to PCSC : %s", (unsigned long)dwSendLength, cs_hexdump(1, buf, l, tmp, sizeof(tmp)));
rv = SCardTransmit(crdr_data->hCard, SCARD_PCI_T0, (LPCBYTE) buf, dwSendLength, NULL, (LPBYTE) cta_res, (LPDWORD) &dwRecvLength);
*cta_lr = dwRecvLength;
}
else if(crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T1)
{
dwSendLength = l;
rdr_log_dbg(pcsc_reader, D_DEVICE, "sending %lu bytes to PCSC : %s", (unsigned long)dwSendLength, cs_hexdump(1, buf, l, tmp, sizeof(tmp)));
rv = SCardTransmit(crdr_data->hCard, SCARD_PCI_T1, (LPCBYTE) buf, dwSendLength, NULL, (LPBYTE) cta_res, (LPDWORD) &dwRecvLength);
*cta_lr = dwRecvLength;
}
else
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC invalid protocol (T=%lu)", (unsigned long)crdr_data->dwActiveProtocol);
return ERROR;
}
rdr_log_dbg(pcsc_reader, D_DEVICE, "received %d bytes from PCSC with rv=%lx : %s", *cta_lr, (unsigned long)rv, cs_hexdump(1, cta_res, *cta_lr, tmp, sizeof(tmp)));
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC doapi (%lx ) (T=%d), %d", (unsigned long)rv, (crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1), *cta_lr);
if(rv == SCARD_S_SUCCESS)
{
return OK;
}
else
{
return ERROR;
}
}
static int32_t pcsc_activate_card(struct s_reader *pcsc_reader, uint8_t *atr, uint16_t *atr_size)
{
struct pcsc_data *crdr_data = pcsc_reader->crdr_data;
LONG rv;
DWORD dwState, dwAtrLen, dwReaderLen;
unsigned char pbAtr[ATR_MAX_SIZE];
char tmp[sizeof(pbAtr) * 3 + 1];
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC initializing card in (%s)", crdr_data->pcsc_name);
dwAtrLen = sizeof(pbAtr);
dwReaderLen = 0;
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC resetting card in (%s) with handle %" PRIuPTR, crdr_data->pcsc_name, (uintptr_t)crdr_data->hCard);
rv = SCardReconnect(crdr_data->hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &crdr_data->dwActiveProtocol);
if(rv != SCARD_S_SUCCESS)
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "ERROR: PCSC failed to reset card (%lx)", (unsigned long)rv);
return ERROR;
}
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC resetting done on card in (%s)", crdr_data->pcsc_name);
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC Protocol (T=%d)", (crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC getting ATR for card in (%s)", crdr_data->pcsc_name);
rv = SCardStatus(crdr_data->hCard, NULL, &dwReaderLen, &dwState, &crdr_data->dwActiveProtocol, pbAtr, &dwAtrLen);
if(rv == SCARD_S_SUCCESS)
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC Protocol (T=%d)", (crdr_data->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
memcpy(atr, pbAtr, dwAtrLen);
*atr_size = dwAtrLen;
rdr_log(pcsc_reader, "ATR: %s", cs_hexdump(1, (uint8_t *)pbAtr, dwAtrLen, tmp, sizeof(tmp)));
memcpy(pcsc_reader->card_atr, pbAtr, dwAtrLen);
pcsc_reader->card_atr_length = dwAtrLen;
return OK;
}
else
{
rdr_log_dbg(pcsc_reader, D_DEVICE, "ERROR: PCSC failed to get ATR for card (%lx)", (unsigned long)rv);
}
return ERROR;
}
static int32_t pcsc_activate(struct s_reader *reader, struct s_ATR *atr)
{
unsigned char atrarr[ATR_MAX_SIZE];
uint16_t atr_size = 0;
if(pcsc_activate_card(reader, atrarr, &atr_size) == OK)
{
if(ATR_InitFromArray(atr, atrarr, atr_size) != ERROR) // ATR is OK or softfail malformed
{ return OK; }
else
{ return ERROR; }
}
else
{ return ERROR; }
}
static int32_t pcsc_check_card_inserted(struct s_reader *pcsc_reader)
{
struct pcsc_data *crdr_data = pcsc_reader->crdr_data;
DWORD dwState, dwAtrLen, dwReaderLen;
unsigned char pbAtr[64];
SCARDHANDLE rv;
dwAtrLen = sizeof(pbAtr);
rv = 0;
dwState = 0;
dwReaderLen = 0;
// Do we have a card ?
if(!crdr_data->pcsc_has_card && !crdr_data->hCard)
{
// try connecting to the card
rv = SCardConnect(crdr_data->hContext, crdr_data->pcsc_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &crdr_data->hCard, &crdr_data->dwActiveProtocol);
if(rv == (SCARDHANDLE)SCARD_E_NO_SMARTCARD)
{
// no card in pcsc_reader
crdr_data->pcsc_has_card = 0;
if(crdr_data->hCard)
{
SCardDisconnect(crdr_data->hCard, SCARD_RESET_CARD);
crdr_data->hCard = 0;
}
// rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", crdr_data->pcsc_name, dwState, (unsigned long)rv );
return OK;
}
else if(rv == (SCARDHANDLE)SCARD_W_UNRESPONSIVE_CARD)
{
// there is a problem with the card in the pcsc_reader
crdr_data->pcsc_has_card = 0;
crdr_data->hCard = 0;
rdr_log(pcsc_reader, "PCSC card in %s is unresponsive. Eject and re-insert please.", crdr_data->pcsc_name);
return ERROR;
}
else if(rv == SCARD_S_SUCCESS)
{
// we have a card
crdr_data->pcsc_has_card = 1;
rdr_log(pcsc_reader, "PCSC was opened with handle: %" PRIuPTR, (uintptr_t)crdr_data->hCard);
}
else
{
// if we get here we have a bigger problem -> display status and debug
// rdr_log_dbg(pcsc_reader, D_DEVICE, "PCSC pcsc_reader %s status [dwstate=%lx rv=(%lx)]", crdr_data->pcsc_name, dwState, (unsigned long)rv );
return ERROR;
}
}
// if we get there the card is ready, check its status
rv = SCardStatus(crdr_data->hCard, NULL, &dwReaderLen, &dwState, &crdr_data->dwActiveProtocol, pbAtr, &dwAtrLen);
if(rv == SCARD_S_SUCCESS && (dwState & (SCARD_PRESENT | SCARD_NEGOTIABLE | SCARD_POWERED)))
{
return OK;
}
else
{
SCardDisconnect(crdr_data->hCard, SCARD_RESET_CARD);
crdr_data->hCard = 0;
crdr_data->pcsc_has_card = 0;
}
return ERROR;
}
static int32_t pcsc_get_status(struct s_reader *reader, int32_t *in)
{
struct pcsc_data *crdr_data = reader->crdr_data;
int32_t ret = pcsc_check_card_inserted(reader);
*in = crdr_data->pcsc_has_card;
return ret;
}
static int32_t pcsc_close(struct s_reader *pcsc_reader)
{
struct pcsc_data *crdr_data = pcsc_reader->crdr_data;
rdr_log_dbg(pcsc_reader, D_IFD, "PCSC : Closing device %s", pcsc_reader->device);
SCardDisconnect(crdr_data->hCard, SCARD_LEAVE_CARD);
SCardReleaseContext(crdr_data->hContext);
return OK;
}
const struct s_cardreader cardreader_pcsc =
{
.desc = "pcsc",
.typ = R_PCSC,
.skip_extra_atr_parsing = 1,
.skip_t1_command_retries = 1,
.skip_setting_ifsc = 1,
.reader_init = pcsc_init,
.get_status = pcsc_get_status,
.activate = pcsc_activate,
.card_write = pcsc_do_api,
.close = pcsc_close,
};
#endif