From 4cf124d6950d107c5eaceac70028de1897bc4c22 Mon Sep 17 00:00:00 2001 From: leslie Date: Sun, 8 Mar 2009 22:12:23 +0800 Subject: [PATCH] smartcards: add support for CCID smartcards via pcscd --- Makefile | 5 ++ examples/cardslot.conf.example | 14 ++++ smartcard.c | 144 +++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) diff --git a/Makefile b/Makefile index 5a410f2..3cd15d6 100644 --- a/Makefile +++ b/Makefile @@ -115,6 +115,11 @@ ifdef DEFAULT_PORT $(error DEFAULT_PORT support was removed, use cardslot.conf) endif +ifdef WITH_PCSC + DEFINES += -DWITH_PCSC + LIBS += -lpcsclite +endif + # max number of CAIDs per slot MAXCAID := $(shell sed -ne '/define MAXCASYSTEMIDS/ s/^.[a-zA-Z ]*\([0-9]*\).*$$/\1/p' $(VDRDIR)/ci.c) ifneq ($(strip $(MAXCAID)),) diff --git a/examples/cardslot.conf.example b/examples/cardslot.conf.example index 163b3aa..7de2e63 100644 --- a/examples/cardslot.conf.example +++ b/examples/cardslot.conf.example @@ -27,6 +27,20 @@ serial:/dev/ttyS1:1:0:3579545 srplus:/dev/ttyS0 srplus:/dev/ttyS1:6000000 +; cardslot talking to PCSCd using CCID protocol for communication +; +; ccid:dev +; +; dev - serial device e.g. /dev/ttyS0 +; +; For using this cardslot type, you must have installed pcsd-lite and ccid +; driver package. Before compiling you should add something like this to your +; Make.config file: +; WITH_PCSC = 1 +; INCLUDES += /usr/include/PCSC +; +ccid:/dev/usb0 + ; emulated smartcard on dummy port. For testing/debugging purpose only! ; The emulation code has to be enabled with the CARD_EMU define im smartcard.c ; diff --git a/smartcard.c b/smartcard.c index e5ac24a..5f1369a 100644 --- a/smartcard.c +++ b/smartcard.c @@ -1059,6 +1059,150 @@ bool cSmartCardSlotSRPlus::SRConfig(int F, float D, int fs, int N, int T, int in return true; } +// -- cSmartCardSlotCCID ------------------------------------------------------- + +#ifdef WITH_PCSC +#include + +class cSmartCardSlotCCID : public cSmartCardSlot { +private: + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + DWORD dwActiveProtocol, dwProtocol; + DWORD dwState, dwReaderLen; + bool needsReOpen; + // + int Transmit(const unsigned char *request, int requestlen, unsigned char *answer, int answerlen); +protected: + virtual bool DeviceOpen(const char *cfg); + virtual void DeviceClose(void); + virtual bool DeviceSetMode(int mode, int baud); + virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0) { return -1; } + virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0) { return -1; } + virtual void DeviceToggleReset(void) {} + virtual bool DevicePTS(void) { return false; } + virtual bool DeviceIsInserted(void); + // + virtual bool Reset(void); +public: + virtual bool IsoRead(const unsigned char *cmd, unsigned char *data); + virtual bool IsoWrite(const unsigned char *cmd, const unsigned char *data); + virtual int RawRead(unsigned char *data, int len, int to=0) { return -1; } + virtual int RawWrite(const unsigned char *data, int len) { return -1; } + }; + +static cSmartCardSlotLinkReg __scs_ccid("ccid"); + +bool cSmartCardSlotCCID::DeviceOpen(const char *cfg) +{ + if(sscanf(cfg,"%255[^:]",devName)==1) { + LONG rv=SCardEstablishContext(SCARD_SCOPE_SYSTEM,NULL,NULL,&hContext); + PRINTF(L_CORE_SC,"%s: establish Context: %ld:%s",devName,rv,pcsc_stringify_error(rv)); + DWORD protocol=SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1; + rv=SCardConnect(hContext,devName,SCARD_SHARE_SHARED,protocol,&hCard,&dwActiveProtocol); + dwProtocol=dwActiveProtocol; + PRINTF(L_CORE_SC,"%s: connect: %ld:%s",devName,rv,pcsc_stringify_error(rv)); + needsReOpen=false; + return true; + } + else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'ccid'"); + return false; +} + +void cSmartCardSlotCCID::DeviceClose(void) +{ + SCardDisconnect(hCard,SCARD_RESET_CARD); + SCardReleaseContext(hContext); +} + +bool cSmartCardSlotCCID::DeviceSetMode(int mode, int baud) +{ + currMode=mode; + return true; +} + +bool cSmartCardSlotCCID::DeviceIsInserted(void) +{ + BYTE pbAtr[MAX_ATR_SIZE]; + DWORD dwAtrLen=sizeof(pbAtr); + LONG rv=SCardStatus(hCard,NULL,&dwReaderLen,&dwState,&dwProtocol,pbAtr,&dwAtrLen); + if(rv==SCARD_S_SUCCESS && (dwState&SCARD_NEGOTIABLE)) return true; + needsReOpen=true; + return false; +} + +bool cSmartCardSlotCCID::Reset(void) +{ + PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",slotnum,serModes[DeviceCurrentMode()]); + if(needsReOpen) { DeviceClose(); DeviceOpen(0); } + LONG rv=SCardReconnect(hCard,SCARD_SHARE_EXCLUSIVE,dwProtocol,SCARD_RESET_CARD,&dwActiveProtocol); + if(rv!=SCARD_S_SUCCESS) { + PRINTF(L_CORE_SC,"%d: reset failed: %lx:%sn",slotnum,rv,pcsc_stringify_error(rv)); + return false; + } + DWORD dwAtrLen=sizeof(atr.atr); + rv=SCardStatus(hCard,NULL,&dwReaderLen,&dwState,&dwProtocol,atr.atr,&dwAtrLen); + if(rv==SCARD_S_SUCCESS) { + atr.atrLen=dwAtrLen; + LDUMP(L_CORE_SC,atr.atr,dwAtrLen,"%d: <- ATR len=%ld:",slotnum,dwAtrLen); + return true; + } + return false; +} + +int cSmartCardSlotCCID::Transmit(const unsigned char *request, int requestlen, unsigned char *answer, int answerlen) +{ + SCARD_IO_REQUEST pioRecvPci, pioSendPci; + switch (dwProtocol) { + case SCARD_PROTOCOL_T0: + case SCARD_PROTOCOL_T1: + pioSendPci.dwProtocol=dwProtocol; + pioSendPci.cbPciLength=sizeof(pioSendPci); + pioRecvPci.dwProtocol=dwProtocol; + pioRecvPci.cbPciLength=sizeof(pioRecvPci); + break; + default: + PRINTF(L_CORE_SC,"%d: protocol failure: %ld",slotnum,dwProtocol); + return 0; + } + DWORD answlen=answerlen; + DWORD rv=SCardTransmit(hCard,&pioSendPci,(LPCBYTE)request,(DWORD)requestlen,&pioRecvPci,(LPBYTE)answer,&answlen); + if(rv!=SCARD_S_SUCCESS) { + PRINTF(L_CORE_SC, "%d: transmit failed: %0lx:%s\n",slotnum,rv,pcsc_stringify_error(rv)); + return -1; + } + return answlen; +} + +bool cSmartCardSlotCCID::IsoRead(const unsigned char *cmd, unsigned char *data) +{ + LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum); + int restlen=Transmit(cmd,CMD_LEN,data,MAX_LEN); + if(restlen<2) return Test(false); + sb[0]=data[restlen-2]; + sb[1]=data[restlen-1]; + LDUMP(L_CORE_SC,sb,2,"%d: <- SB: ",slotnum); + LDUMP(L_CORE_SC,data,restlen-2,"%d: <- DATA:",slotnum); + return true; +} + +bool cSmartCardSlotCCID::IsoWrite(const unsigned char *cmd, const unsigned char *data) +{ + LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum); + LDUMP(L_CORE_SC,data,cmd[LEN_IDX],"%d: -> DATA:",slotnum); + unsigned char sendbuf[MAX_LEN+CMD_LEN], recvbuf[MAX_LEN]; + memcpy(sendbuf,cmd,CMD_LEN); + memcpy(sendbuf+CMD_LEN,data,sendbuf[LEN_IDX]); + int restlen=Transmit(sendbuf,CMD_LEN+sendbuf[LEN_IDX],recvbuf,MAX_LEN); + if(restlen<2) return Test(false); + sb[0]=recvbuf[restlen-2]; + sb[1]=recvbuf[restlen-1]; + LDUMP(L_CORE_SC,sb,2,"%d: <- SB: ",slotnum); + return true; +} + +#endif //WITH_PCSC + // -- cSmartCardSlotEmuGeneric ------------------------------------------------- #ifdef CARD_EMU -- 2.39.5