From: leslie Date: Thu, 5 Mar 2009 04:16:27 +0000 (+0800) Subject: smartcards: virtualise cardreader code X-Git-Tag: 0.9.2~59 X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=36192df42b32af15493952bf792c6440cdb880e8;p=sasc-ng.git smartcards: virtualise cardreader code --- diff --git a/examples/cardslot.conf.example b/examples/cardslot.conf.example index b5d471b..b3d2fcf 100644 --- a/examples/cardslot.conf.example +++ b/examples/cardslot.conf.example @@ -11,3 +11,11 @@ ; serial:/dev/ttyS0:0:0 serial:/dev/ttyS1:1:0:3579545 + +; 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 +; +emuseca: +emucrypto: +emuirdeto:acs383 +emuirdeto:acs384 diff --git a/sc.c b/sc.c index c7c92c0..a3f61f4 100644 --- a/sc.c +++ b/sc.c @@ -78,7 +78,7 @@ #endif // SC API version number for loading shared libraries -#define SCAPIVERS 21 +#define SCAPIVERS 22 static cPlugin *ScPlugin; static cOpts *ScOpts, *LogOpts; @@ -1011,17 +1011,12 @@ bool cScSetup::Ignore(unsigned short caid) bool cSoftCAM::Load(const char *cfgdir) { if(!Feature.KeyFile()) keys.Disable(); - if(!Feature.SmartCard()) { - carddatas.Disable(); - smartcards.Disable(); - } + if(!Feature.SmartCard()) smartcards.Disable(); cStructLoaders::Load(false); if(Feature.KeyFile() && keys.Count()<1) PRINTF(L_GEN_ERROR,"no keys loaded for softcam!"); if(!cSystems::Init(cfgdir)) return false; srand(time(0)); - if(Feature.SmartCard()) - smartcards.LaunchWatcher(); return true; } @@ -1030,7 +1025,6 @@ void cSoftCAM::Shutdown(void) cStructLoaders::Save(true); cSystems::Clean(); smartcards.Shutdown(); - carddatas.SafeClear(); keys.SafeClear(); } diff --git a/smartcard.c b/smartcard.c index ef1bc51..45418db 100644 --- a/smartcard.c +++ b/smartcard.c @@ -36,92 +36,659 @@ #include "log-core.h" #define ISO_FREQ 3571200 // Hz +#define ISO_BAUD 9600 -//#define SER_EMU // use serial emulation (select one of the following) -//#define EMU_SECA // fake Seca card -//#define EMU_IRD // fake Irdeto/Beta card -//#define EMU_IRD_384 // fake ACS 384, if undefined ACS 383 -//#define EMU_CRYPTO // fake Cryptoworks card +//#define CARD_EMU // include smartcard emulation code //#define NO_PTS_PROTO // disable PTS protocol (baudrate changes) -struct BaudRates { - int real; - speed_t apival; - }; +// -- cSmartCardSlot ----------------------------------------------------------- -static const struct BaudRates BaudRateTab[] = { - { 9600, B9600 }, - { 19200, B19200 }, - { 38400, B38400 }, - { 57600, B57600 }, - { 115200, B115200 }, - { 230400, B230400 } +class cSmartCardSlot : private cThread, public cStructItem { +private: + cSmartCard *card; + int usecount, cardid; + bool firstRun, needsReset, dead, ready; + cMutex mutex; + cCondVar cond; + // + void SetCard(cSmartCard *c, int cid=0); + bool CardReset(void); +protected: + virtual bool DeviceOpen(const char *cfg)=0; + virtual void DeviceClose(void) {} + virtual bool DeviceSetMode(int mode, int baud)=0; + virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0)=0; + virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0)=0; + virtual void DeviceToggleReset(void)=0; + virtual bool DevicePTS(void)=0; + virtual bool DeviceIsInserted(void)=0; + virtual int DeviceCurrentMode(void)=0; + // + virtual void Action(void); + // possibly virtual + bool Reset(void); + // + int Procedure(unsigned char ins, int restLen); + int Read(unsigned char *data, int len, int to=0); + int Write(const unsigned char *data, int len); + bool Test(bool res); + void Invert(unsigned char *data, int n); + bool ParseAtr(void); + // + int slotnum, clock; + struct Atr atr; + bool localecho; +public: + cSmartCardSlot(void); + virtual ~cSmartCardSlot(); + bool Setup(int num, const char *cfg); + void TriggerReset(void) { needsReset=true; } + bool HaveCard(int id); + cSmartCard *LockCard(int id); + void ReleaseCard(cSmartCard *sc); + void GetCardIdStr(char *str, int len); + bool GetCardInfoStr(char *str, int len); + int SlotNum(void) { return slotnum; } + // possibly virtual + bool IsoRead(const unsigned char *cmd, unsigned char *data); + bool IsoWrite(const unsigned char *cmd, const unsigned char *data); + int RawRead(unsigned char *data, int len, int to=0); + int RawWrite(const unsigned char *data, int len); }; -// -- cSerial ------------------------------------------------------------------ +static const char *serModes[] = { 0,"8e2","8o2","8n2" }; + +cSmartCardSlot::cSmartCardSlot(void) +{ + card=0; usecount=0; slotnum=-1; clock=ISO_FREQ; + firstRun=true; needsReset=false; dead=false; ready=false; localecho=true; +} + +cSmartCardSlot::~cSmartCardSlot() +{ + Cancel(3); + SetCard(0); + DeviceClose(); +} + +bool cSmartCardSlot::Setup(int num, const char *cfg) +{ + slotnum=num; + SetDescription("CardSlot %d watcher",slotnum); + if(DeviceOpen(cfg)) { + firstRun=true; + Start(); + return true; + } + return false; +} + +bool cSmartCardSlot::HaveCard(int id) +{ + cMutexLock lock(&mutex); + while(Running() && firstRun) cond.Wait(mutex); + return ready && card && cardid==id; +} + +cSmartCard *cSmartCardSlot::LockCard(int id) +{ + mutex.Lock(); + while(Running() && firstRun) cond.Wait(mutex); + if(ready && card && cardid==id) { + usecount++; + mutex.Unlock(); + card->Lock(); + if(DeviceIsInserted() && card->CardUp() && !needsReset) return card; + // if failed, unlock the card and decrement UseCount + card->Unlock(); + mutex.Lock(); + usecount--; + cond.Broadcast(); + } + mutex.Unlock(); + return 0; +} + +void cSmartCardSlot::ReleaseCard(cSmartCard *sc) +{ + if(card==sc) { + card->Unlock(); + mutex.Lock(); + usecount--; + cond.Broadcast(); + mutex.Unlock(); + } +} + +void cSmartCardSlot::GetCardIdStr(char *str, int len) +{ + mutex.Lock(); + if(ready && card && !card->GetCardIdStr(str,len)) { + for(cSmartCardLink *scl=smartcards.First(); scl; smartcards.Next(scl)) { + if(scl->Id()==cardid) { + strn0cpy(str,scl->Name(),len); + break; + } + } + } + mutex.Unlock(); +} + +bool cSmartCardSlot::GetCardInfoStr(char *str, int len) +{ + mutex.Lock(); + bool res=false; + if(ready && card) res=card->GetCardInfoStr(str,len); + mutex.Unlock(); + return res; +} + +void cSmartCardSlot::SetCard(cSmartCard *c, int cid) +{ + mutex.Lock(); + while(usecount) cond.Wait(mutex); + if(card!=c) delete card; + card=c; cardid=cid; ready=(card!=0); needsReset=dead=false; + mutex.Unlock(); +} + +void cSmartCardSlot::Action(void) +{ + while(Running()) { + if(card) { + card->Lock(); + if(!DeviceIsInserted()) { + card->Unlock(); + PRINTF(L_CORE_SC,"%d: card removed (usecount=%d)",slotnum,usecount); + SetCard(0); + } + else if(needsReset) { + PRINTF(L_CORE_SC,"%d: card reset requested",slotnum); + int mode=DeviceCurrentMode()&SM_MASK; + if(!DeviceSetMode(mode,ISO_BAUD) + || !CardReset() + || !card->Setup(this,mode,&atr)) { + card->Unlock(); + PRINTF(L_CORE_SC,"%d: card re-init failed",slotnum); + SetCard(0); dead=true; + } + } + if(card) card->Unlock(); + } + else if(DeviceIsInserted()) { + if(!dead) { + PRINTF(L_CORE_SC,"%d: new card inserted",slotnum); + for(int mode=SM_NONE+1 ; modeName()); + card=scl->Create(); + if(card && card->Setup(this,mode,&atr)) { + SetCard(card,scl->Id()); + goto done; // ugly, any better solution? + } + delete card; card=0; + } + PRINTF(L_CORE_SC,"%d: no card handler found",slotnum); + } + else PRINTF(L_CORE_SC,"%d: reset/atr error",slotnum); + } + else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slotnum,serModes[mode]); + } + dead=true; + PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slotnum); + } + } + else { + if(dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slotnum); + dead=false; + } +done: + if(firstRun) { + mutex.Lock(); + cond.Broadcast(); + firstRun=false; + mutex.Unlock(); + } + cCondWait::SleepMs(300); + } +} + +bool cSmartCardSlot::Reset(void) +{ + PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",slotnum,serModes[DeviceCurrentMode()]); + DeviceToggleReset(); + cCondWait::SleepMs(100); + DeviceToggleReset(); + int r=DeviceRead(atr.atr,-MAX_ATR_LEN,800,2000); + atr.atrLen=r; + if(r>0) LDUMP(L_CORE_SC,atr.atr,r,"%d: <- ATR len=%d:",slotnum,r); + return r>=2; +} + +bool cSmartCardSlot::CardReset(void) +{ + if(!Reset() || !ParseAtr()) return false; + if((atr.F!=372 || atr.D!=1.0) && !DevicePTS()) { + // reset card again and continue without PTS + if(!Reset() || !ParseAtr()) return false; + } + return true; +} + +void cSmartCardSlot::Invert(unsigned char *data, int n) +{ + static const unsigned char swaptab[] = { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 }; + for(int i=n-1; i>=0; i--) + data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4]; +} + +int cSmartCardSlot::Read(unsigned char *data, int len, int to) +{ + int r=DeviceRead(data,len,card->cfg->serTO,to); + if(atr.convention==SM_INDIRECT && r>0) Invert(data,r); + return r; +} + +int cSmartCardSlot::Write(const unsigned char *data, int len) +{ + unsigned char *tmp=AUTOMEM(len); + if(atr.convention==SM_INDIRECT) { + memcpy(tmp,data,len); + Invert(tmp,len); + data=tmp; + } + int r=DeviceWrite(data,len,card->cfg->serDL); + if(r>0 && localecho) { + unsigned char *buff=AUTOMEM(r); + int rr=DeviceRead(buff,r,card->cfg->serTO); + if(rr<0) r=rr; + } + return r; +} + +int cSmartCardSlot::Procedure(unsigned char ins, int restLen) +{ + int r; + unsigned char buff; + LBSTARTF(L_CORE_SC); + LBPUT("%d: <- PROC: ",slotnum); + do { + do { + if(Read(&buff,1,card->cfg->workTO)<=0) return -1; + LBPUT("%02x ",buff); + } while(buff==0x60); + + if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2 + card->sb[0]=buff; + if(Read(&buff,1)<=0) return -1; + LBPUT("%02x",buff); + card->sb[1]=buff; + return 0; + } + else { + if((buff&0xFE)==(ins&0xFE)) r=restLen; + else if((~buff&0xFE)==(ins&0xFE)) r=1; + else { + LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins); + return -1; + } + if(r>restLen) { + LBPUT("data overrun r=%d restLen=%d",r,restLen); + return -1; + } + } + } while(r==0); + LBEND(); + return r; +} + +bool cSmartCardSlot::Test(bool res) +{ + if(!res) { + TriggerReset(); + PRINTF(L_CORE_SC,"%d: reset triggered",slotnum); + } + return res; +} + +bool cSmartCardSlot::IsoRead(const unsigned char *cmd, unsigned char *data) +{ + LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum); + if(Write(cmd,CMD_LEN)<0) return Test(false); + int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256; + int len=0; + while(1) { + int r=Procedure(cmd[INS_IDX],tr-len); + if(r<=0) return Test(r==0); + if(Read(data+len,r)<0) return Test(false); + LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",slotnum); + len+=r; + } +} + +bool cSmartCardSlot::IsoWrite(const unsigned char *cmd, const unsigned char *data) +{ + LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum); + if(Write(cmd,CMD_LEN)<0) return Test(false); + int len=0; + while(1) { + int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len); + if(r<=0) return Test(r==0); + if(Write(data+len,r)<0) return Test(false); + LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",slotnum); + len+=r; + } +} + +int cSmartCardSlot::RawRead(unsigned char *data, int len, int to) +{ + int r=Read(data,len,to); + if(r<0) Test(false); + return r; +} + +int cSmartCardSlot::RawWrite(const unsigned char *data, int len) +{ + int r=Write(data,len); + if(r<0) Test(false); + return r; +} + +#define NEED(x) { if(len+(x)>atr.atrLen) { LBPUT("SHORT ATR"); return false; } } + +bool cSmartCardSlot::ParseAtr(void) +{ + // default values + atr.histLen=0; atr.T=0; atr.F=372; atr.D=1.0; atr.N=0; atr.WI=10; + atr.BWI=4; atr.CWI=0; atr.Tspec=-1; + + static const int Ftable[16] = { + 372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0 + }; + static const float Dtable[16] = { + 0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0, + 0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625 + }; + + const unsigned char *rawatr=atr.atr; + if(rawatr[0]==0x03) { + PRINTF(L_CORE_SC,"%d: indirect convention detected",slotnum); + Invert(atr.atr,atr.atrLen); + atr.convention=SM_INDIRECT; + } + else if(rawatr[0]==0x3B) { + PRINTF(L_CORE_SC,"%d: direct convention detected",slotnum); + atr.convention=SM_DIRECT; + } + else { + PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",slotnum,rawatr[0]); + return false; + } -class cSerial { + // TS TO + atr.histLen=rawatr[1]&0x0F; + int Y=rawatr[1]&0xF0, i=1, len=2; + LBSTARTF(L_CORE_SC); + LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",slotnum,rawatr[0],atr.histLen,i,Y); + do { + if(Y&0x10) { // TAi + NEED(1); + LBPUT("TA%d=%02x ",i,rawatr[len]); + if(i==1) { + atr.TA1=rawatr[len]; + atr.F=Ftable[(rawatr[len]>>4)&0x0F]; + atr.D=Dtable[ rawatr[len] &0x0F]; + LBPUT("F=%d D=%f ",atr.F,atr.D); + } + else if(i==2) { + atr.Tspec=rawatr[len]&0x0F; + LBPUT("Tspec=%d ",atr.Tspec); + } + else if(i==3) { + LBPUT("IFSC=%d ",rawatr[len]); + } + len++; + } + if(Y&0x20) { // TBi + NEED(1); + LBPUT("TB%d=%02x ",i,rawatr[len]); + if(i==3) { + atr.BWI=(rawatr[len]>>4)&0x0F; + atr.CWI=rawatr[len]&0x0F; + LBPUT("BWI=%d CWI=%d ",atr.BWI,atr.CWI); + } + len++; + } + if(Y&0x40) { // TCi + NEED(1); + LBPUT("TC%d=%02x ",i,rawatr[len]); + if(i==1) { + atr.N=rawatr[len]; + LBPUT("N=%d ",atr.N); + } + else if(i==2) { + atr.WI=rawatr[len]; + LBPUT("WI=%d ",atr.WI); + } + else if(i==3) { + LBPUT("CHK=%s ",rawatr[len]&1 ? "CRC16":"LRC"); + } + len++; + } + if(Y&0x80) { // TDi + NEED(1); + LBPUT("TD%d=%02x ",i,rawatr[len]); + if(i==1) { + atr.T=rawatr[len]&0x0F; + LBPUT("T=%d ",atr.T); + } + else { + LBPUT("Tn=%d ",rawatr[len]&0x0F); + } + Y=rawatr[len]&0xF0; + len++; + } + else Y=0; + i++; + LBPUT("Y%d=%02x ",i,Y); + } while(Y); + NEED(atr.histLen); + LBEND(); + + LBSTART(L_CORE_SC); + LBPUT("%d: historical:",slotnum); + for(int i=0; ilen) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",slotnum,atr.atrLen,len); + atr.wwt=960*atr.WI*atr.F/(clock/1000); + atr.bwt=(int)(960*(float)(1< { +friend class cSmartCardSlotLink; private: - char *devName; - int fd; - int currMode, statInv; - bool invRST; + static cSmartCardSlotLink *first; // - speed_t FindBaud(int baud); -#ifdef SER_EMU - unsigned char devBuff[1024], nextSW[SB_LEN]; - int buffCount, dataLen, record; - bool cmdStart, rts, dsr, flag; - int remTime; -#endif + static void Register(cSmartCardSlotLink *scl); +protected: + virtual bool ParseLinePlain(const char *line); public: - cSerial(const char *DevName, bool invCD, bool InvRST); - ~cSerial(); - bool Open(void); - bool SetMode(int mode, int baud=9600); - int CurrentMode(void) const { return currMode; } - void Flush(void); - int Read(unsigned char *mem, int len, int timeout, int initialTimeout=0); - int Write(const unsigned char *mem, int len, int delay=0); - void ToggleRTS(void); - bool CheckCAR(void); - void Close(void); - const char *DeviceName(void) const { return devName; } + cSmartCardSlots(void); + cSmartCardSlot *GetSlot(int num); + cSmartCardSlot *FirstSlot(void); + void Release(void); }; -cSerial::cSerial(const char *DevName, bool invCD, bool InvRST) +cSmartCardSlotLink *cSmartCardSlots::first=0; + +static cSmartCardSlots cardslots; + +// -- cSmartCardSlotLink ------------------------------------------------------- + +class cSmartCardSlotLink { +public: + cSmartCardSlotLink *next; + const char *name; +public: + cSmartCardSlotLink(const char *Name); + virtual ~cSmartCardSlotLink() {} + virtual cSmartCardSlot *Create(void)=0; + }; + +template class cSmartCardSlotLinkReg : public cSmartCardSlotLink { +public: + cSmartCardSlotLinkReg(const char *Name):cSmartCardSlotLink(Name) {} + virtual cSmartCardSlot *Create(void) { return new LL; } + }; + +cSmartCardSlotLink::cSmartCardSlotLink(const char *Name) +{ + name=Name; + cSmartCardSlots::Register(this); +} + +// -- cSmartCardSlots ---------------------------------------------------------- + +cSmartCardSlots::cSmartCardSlots(void) +:cStructListPlain("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE) +{} + +void cSmartCardSlots::Register(cSmartCardSlotLink *scl) { - devName=strdup(DevName); - statInv=invCD ? TIOCM_CAR:0; - invRST=InvRST; - fd=-1; currMode=SM_NONE; + PRINTF(L_CORE_DYN,"registering cardslot type %s",scl->name); + scl->next=first; + first=scl; } -cSerial::~cSerial() +cSmartCardSlot *cSmartCardSlots::GetSlot(int num) { - Close(); - free(devName); + ListLock(false); + for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) + if(slot->SlotNum()==num) return slot; + return 0; } -#ifndef SER_EMU +cSmartCardSlot *cSmartCardSlots::FirstSlot(void) +{ + ListLock(false); + return First(); +} -bool cSerial::Open(void) +void cSmartCardSlots::Release(void) { - PRINTF(L_CORE_SERIAL,"%s: open serial port",devName); - fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY); - if(fd>=0) { - PRINTF(L_CORE_SERIAL,"%s: set DTR/RTS",devName); - unsigned int modembits; - modembits=TIOCM_DTR; CHECK(ioctl(fd, TIOCMBIS, &modembits)); - modembits=TIOCM_RTS; CHECK(ioctl(fd, invRST?TIOCMBIS:TIOCMBIC, &modembits)); - PRINTF(L_CORE_SERIAL,"%s: init done",devName); - return true; + ListUnlock(); +} + +bool cSmartCardSlots::ParseLinePlain(const char *line) +{ + char type[32]; + int num; + if(sscanf(line,"%31[^:]:%n",type,&num)==1) { + for(cSmartCardSlotLink *scs=first; scs; scs=scs->next) { + if(!strcasecmp(type,scs->name)) { + cSmartCardSlot *slot=scs->Create(); + if(slot) { + if(slot->Setup(Count(),&line[num])) { + Add(slot); + return true; + } + delete slot; + } + else PRINTF(L_GEN_ERROR,"failed to create cardslot"); + return false; + } + } + PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type); + } + return false; +} + +// -- cSmartCardSlotSerial ----------------------------------------------------- + +class cSmartCardSlotSerial : public cSmartCardSlot { +private: + char devName[256]; + int fd; + int currMode, statInv, invRST; + // + void Flush(void); + speed_t FindBaud(int baud); +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); + virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0); + virtual void DeviceToggleReset(void); + virtual bool DevicePTS(void); + virtual bool DeviceIsInserted(void); + virtual int DeviceCurrentMode(void) { return currMode; } +public: + cSmartCardSlotSerial(void); + }; + +static cSmartCardSlotLinkReg __scs_serial("serial"); + +cSmartCardSlotSerial::cSmartCardSlotSerial(void) +{ + fd=-1; statInv=0; invRST=false; currMode=SM_NONE; +} + +bool cSmartCardSlotSerial::DeviceOpen(const char *cfg) +{ + int invCD=0; + if(sscanf(cfg,"%255[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) { + statInv=invCD ? TIOCM_CAR:0; + PRINTF(L_CORE_SERIAL,"%s: open serial port",devName); + fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY); + if(fd>=0) { + PRINTF(L_CORE_SERIAL,"%s: set DTR/RTS",devName); + unsigned int modembits; + modembits=TIOCM_DTR; CHECK(ioctl(fd, TIOCMBIS, &modembits)); + modembits=TIOCM_RTS; CHECK(ioctl(fd, invRST?TIOCMBIS:TIOCMBIC, &modembits)); + PRINTF(L_CORE_SERIAL,"%s: init done",devName); + PRINTF(L_CORE_LOAD,"cardslot: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)", + devName,slotnum,invCD?"inverse":"normal",invRST?"inverse":"normal",clock); + return true; + } + else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno)); } - else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno)); + else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'serial'"); return false; } -void cSerial::Close(void) +void cSmartCardSlotSerial::DeviceClose(void) { if(fd>=0) { PRINTF(L_CORE_SERIAL,"%s: shutting down",devName); @@ -133,8 +700,18 @@ void cSerial::Close(void) } } -speed_t cSerial::FindBaud(int baud) +void cSmartCardSlotSerial::Flush(void) { + if(fd>=0) CHECK(tcflush(fd,TCIOFLUSH)); +} + +speed_t cSmartCardSlotSerial::FindBaud(int baud) +{ + static const struct BaudRates { int real; speed_t apival; } BaudRateTab[] = { + { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 }, + { 57600, B57600 }, { 115200, B115200 }, { 230400, B230400 } + }; + for(int i=0; i<(int)(sizeof(BaudRateTab)/sizeof(struct BaudRates)); i++) { int b=BaudRateTab[i].real; int d=((b-baud)*10000)/b; @@ -147,13 +724,13 @@ speed_t cSerial::FindBaud(int baud) return B0; } -bool cSerial::SetMode(int mode, int baud) +bool cSmartCardSlotSerial::DeviceSetMode(int mode, int baud) { if(fd>=0) { speed_t bconst=FindBaud(baud); bool custom=false; if(bconst==B0) { custom=true; bconst=B38400; } - + struct termios tio; memset(&tio,0,sizeof(tio)); LBSTARTF(L_CORE_SERIAL); @@ -165,7 +742,7 @@ bool cSerial::SetMode(int mode, int baud) cfsetispeed(&tio,bconst); cfsetospeed(&tio,bconst); switch(mode&SM_MASK) { - case SM_8E2: + case SM_8E2: LBPUT("8e%d",(mode&SM_1SB)?1:2); tio.c_cflag |= PARENB; break; case SM_8N2: @@ -211,13 +788,7 @@ bool cSerial::SetMode(int mode, int baud) return false; } -void cSerial::Flush(void) -{ - if(fd>=0) - CHECK(tcflush(fd,TCIOFLUSH)); -} - -int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout) +int cSmartCardSlotSerial::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout) { PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d:%d",devName,len,timeout,initialTimeout); bool incomplete=false; @@ -254,7 +825,7 @@ int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout) return n; } -int cSerial::Write(const unsigned char *mem, int len, int delay) +int cSmartCardSlotSerial::DeviceWrite(const unsigned char *mem, int len, int delay) { PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay); HEXDUMP(L_CORE_SERIAL,mem,len,"%s: write data",devName); @@ -286,7 +857,7 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) return n; } -void cSerial::ToggleRTS(void) +void cSmartCardSlotSerial::DeviceToggleReset(void) { int mask=0; if(ioctl(fd,TIOCMGET,&mask)<0) { LOG_ERROR; return; } @@ -296,7 +867,56 @@ void cSerial::ToggleRTS(void) Flush(); } -bool cSerial::CheckCAR(void) +bool cSmartCardSlotSerial::DevicePTS(void) +{ + int baud=(int)((float)clock*atr.D/atr.F); + PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",slotnum,baud); + + if(atr.Tspec<0) { + PRINTF(L_CORE_SC,"%d: negotiable mode",slotnum); +#ifdef NO_PTS_PROTO + PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",slotnum); + return true; +#else + unsigned char req[4], conf[16]; + req[0]=0xFF; + req[1]=0x10 | atr.T; + req[2]=atr.TA1; + req[3]=XorSum(req,3); + LDUMP(L_CORE_SC,req,4,"%d: PTS request:",slotnum); + if(DeviceWrite(req,4)!=4) { + PRINTF(L_CORE_SC,"%d: PTS request, write failed",slotnum); + return false; + } + if(DeviceRead(conf,4,100,100)!=4) { + PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",slotnum); + return false; + } + int n=DeviceRead(conf,-16,200,1000); + if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",slotnum); + if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) { + PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",slotnum); + return false; + } + if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) { + PRINTF(L_CORE_SC,"%d: PTS not confirmed",slotnum); + return false; + } +#endif // NO_PTS_PROTO + } + else + PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",slotnum,atr.Tspec); + + int mode=DeviceCurrentMode(); + if(atr.N==255) mode|=SM_1SB; + if(!DeviceSetMode(mode,baud)) { + PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",slotnum,baud); + return false; + } + return true; +} + +bool cSmartCardSlotSerial::DeviceIsInserted(void) { int status=0; if(ioctl(fd,TIOCMGET,&status)<0) { LOG_ERROR; return false; } @@ -311,54 +931,73 @@ bool cSerial::CheckCAR(void) return !(status & TIOCM_CAR); } -#else //SER_EMU +#ifdef CARD_EMU + +// -- cSmartCardSlotEmuGeneric ------------------------------------------------- + +#define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); } +#define PUSHB(b) { devBuff[buffCount++]=(b); } + +class cSmartCardSlotEmuGeneric : public cSmartCardSlot { +private: + int currMode; +protected: + char devName[256]; + unsigned char devBuff[1024], nextSW[SB_LEN]; + int buffCount, dataLen, record; + bool cmdStart, rts, dsr, flag; + time_t remTime; + // + 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); + virtual void DeviceToggleReset(void); + virtual bool DevicePTS(void); + virtual bool DeviceIsInserted(void); + virtual int DeviceCurrentMode(void) { return currMode; } + // + virtual void EmuPushAtr(void)=0; + void Flush(void); +public: + cSmartCardSlotEmuGeneric(void); + }; -// -// emulator for a serial phoenix interface -// (activate in smartcard.h) -// +cSmartCardSlotEmuGeneric::cSmartCardSlotEmuGeneric(void) +{ + currMode=SM_NONE; +} -bool cSerial::Open(void) +bool cSmartCardSlotEmuGeneric::DeviceOpen(const char *cfg) { - PRINTF(L_CORE_SERIAL,"serial: open serial port %s (emulator)",devName); - PRINTF(L_CORE_SERIAL,"serial: init done"); - fd=1; buffCount=0; cmdStart=true; rts=false; flag=false; + PRINTF(L_CORE_SERIAL,"%s: open serial port (emulator)",devName); + PRINTF(L_CORE_SERIAL,"%s: init done",devName); + buffCount=0; cmdStart=true; rts=false; flag=false; remTime=time(0); dsr=true; + PRINTF(L_CORE_LOAD,"cardslot: added emulated port %s as port %d",devName,slotnum); return true; } -void cSerial::Close(void) +void cSmartCardSlotEmuGeneric::DeviceClose(void) { - if(fd>=0) { - PRINTF(L_CORE_SERIAL,"serial: shutting down ... "); - fd=-1; - PRINTF(L_CORE_SERIAL,"done"); - } + PRINTF(L_CORE_SERIAL,"%s: shutting down",devName); } -speed_t cSerial::FindBaud(int baud) +void cSmartCardSlotEmuGeneric::Flush(void) { - return B0; + buffCount=0; } -bool cSerial::SetMode(int mode, int baud) +bool cSmartCardSlotEmuGeneric::DeviceSetMode(int mode, int baud) { currMode=mode; Flush(); return true; } -void cSerial::Flush(void) -{ - buffCount=0; -} - -#define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); } -#define PUSHB(b) { devBuff[buffCount++]=(b); } - -int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout) +int cSmartCardSlotEmuGeneric::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout) { - PRINTF(L_CORE_SERIAL,"serial: read len=%d timeout=%d",len,timeout); + PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d",devName,len,timeout); if(len<0) { len=-len; if(buffCount=remTime+30) { + dsr=!dsr; + remTime=time(0); + } +#endif + return dsr; +} + +// -- cSmartCardSlotEmuSeca ---------------------------------------------------- + +class cSmartCardSlotEmuSeca : public cSmartCardSlotEmuGeneric { +protected: + virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0); + virtual void EmuPushAtr(void); +public: + cSmartCardSlotEmuSeca(void); + }; + +static cSmartCardSlotLinkReg __scs_emuseca("emuseca"); + +cSmartCardSlotEmuSeca::cSmartCardSlotEmuSeca(void) +{ + strcpy(devName,"emuseca"); +} + +int cSmartCardSlotEmuSeca::DeviceWrite(const unsigned char *mem, int len, int delay) { - PRINTF(L_CORE_SERIAL,"serial: write len=%d delay=%d",len,delay); + PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay); Flush(); cCondWait::SleepMs(300); PUSH(mem,len); // echo back -#if defined(EMU_SECA) + //--- if(cmdStart && len==CMD_LEN) { // new INS PUSHB(mem[INS_IDX]); // ACK byte cmdStart=false; @@ -418,7 +1100,41 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) cmdStart=true; } } -#elif defined(EMU_CRYPTO) + //--- + return len; +} + +void cSmartCardSlotEmuSeca::EmuPushAtr(void) +{ + static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00, + 0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 }; + PUSH(atr,sizeof(atr)); +} + +// -- cSmartCardSlotEmuCrypto -------------------------------------------------- + +class cSmartCardSlotEmuCrypto : public cSmartCardSlotEmuGeneric { +protected: + virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0); + virtual void EmuPushAtr(void); +public: + cSmartCardSlotEmuCrypto(void); + }; + +static cSmartCardSlotLinkReg __scs_emucrypto("emucrypto"); + +cSmartCardSlotEmuCrypto::cSmartCardSlotEmuCrypto(void) +{ + strcpy(devName,"emucrypto"); +} + +int cSmartCardSlotEmuCrypto::DeviceWrite(const unsigned char *mem, int len, int delay) +{ + PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay); + Flush(); + cCondWait::SleepMs(300); + PUSH(mem,len); // echo back + //--- if(cmdStart && len==CMD_LEN) { // new INS cmdStart=false; dataLen=mem[LEN_IDX]; @@ -429,7 +1145,7 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) switch(mem[0]*256+mem[1]) { case 0xa4a4: switch(mem[5]*256+mem[6]) { - case 0x2f01: + case 0x2f01: case 0x0f00: case 0x0f20: //case 0x0f40: @@ -500,30 +1216,20 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) 0x92,0x20,0x00 // ... }; memcpy(data,resp,sizeof(resp)); - } + } break; case 0x80: dataLen=0x07; - data[0]=0x80; - data[1]=0x05; - data[2]=0x5c; - data[3]=0x0c; - data[4]=0x00; - data[5]=0xec; - data[6]=0x0a; + data[0]=0x80; data[1]=0x05; data[2]=0x5c; data[3]=0x0c; + data[4]=0x00; data[5]=0xec; data[6]=0x0a; break; case 0xD1: dataLen=0x04; - data[0]=0xd1; - data[1]=0x02; - data[2]=0x0d; - data[3]=0x22; + data[0]=0xd1; data[1]=0x02; data[2]=0x0d; data[3]=0x22; break; case 0x9F: dataLen=0x03; - data[0]=0x9f; - data[1]=0x01; - data[2]=0x88; + data[0]=0x9f; data[1]=0x01; data[2]=0x88; break; case 0x9E: { @@ -551,10 +1257,7 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) if(mem[2]==0) { dataLen=0x0C; memset(data,0,0x0c); - data[0]=0xDF; - data[1]=0x0A; - data[4]=0xDF; - data[5]=0x88; + data[0]=0xDF; data[1]=0x0A; data[4]=0xDF; data[5]=0x88; } else { dataLen=0; @@ -567,20 +1270,13 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) case 0xa4c0: readcmd=true; if(mem[4]==0x1c) { - data[0]=0xdb; - data[1]=0x10; + data[0]=0xdb; data[1]=0x10; memset(&data[2],0x45,16); - data[18]=0xdf; - data[19]=0x08; - data[20]=0x50; - data[23]=0x80; + data[18]=0xdf; data[19]=0x08; data[20]=0x50; data[23]=0x80; } else if(mem[4]==0x11) { memset(data,0,0x11); - data[0]=0xdf; - data[1]=0x0f; - data[6]=0x3f; - data[7]=0x6a; + data[0]=0xdf; data[1]=0x0f; data[6]=0x3f; data[7]=0x6a; } else if(mem[4]==0x42) { static const unsigned char resp[0x42] = { @@ -610,54 +1306,109 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) cmdStart=true; } } -#elif defined(EMU_IRD) + //--- + return len; +} + +void cSmartCardSlotEmuCrypto::EmuPushAtr(void) +{ + static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00, + 0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 }; + PUSH(atr,sizeof(atr)); +} + +// -- cSmartCardSlotEmuIrdeto -------------------------------------------------- + +class cSmartCardSlotEmuIrdeto : public cSmartCardSlotEmuGeneric { +private: + bool acs384; +protected: + virtual bool DeviceOpen(const char *cfg); + virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0); + virtual void EmuPushAtr(void); +public: + cSmartCardSlotEmuIrdeto(void); + }; + +static cSmartCardSlotLinkReg __scs_emuirdeto("emuirdeto"); + +cSmartCardSlotEmuIrdeto::cSmartCardSlotEmuIrdeto(void) +{ + strcpy(devName,"emuirdeto"); + acs384=false; +} + +bool cSmartCardSlotEmuIrdeto::DeviceOpen(const char *cfg) +{ + char acs[32]; + if(sscanf(cfg,"%31[^:]",acs)>=0) { + if(!strcasecmp(acs,"acs384")) acs384=true; + else if(!strcasecmp(acs,"acs383")) acs384=false; + else { + PRINTF(L_GEN_ERROR,"unknown ACS type"); + return false; + } + return cSmartCardSlotEmuGeneric::DeviceOpen(0); + } + else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",devName); + return false; +} + +int cSmartCardSlotEmuIrdeto::DeviceWrite(const unsigned char *mem, int len, int delay) +{ + PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay); + Flush(); + cCondWait::SleepMs(300); + PUSH(mem,len); // echo back + //--- static const struct Resp { unsigned int cmd; + int acs; unsigned char data[MAX_LEN]; } resp[] = { -#ifdef EMU_IRD_384 - { 0x01020203, + { 0x01020203,0x384, {0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x84,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} }, - { 0x01020E02, + { 0x01020E02,0x384, {0x01,0x02,0x00,0x00,0x0e,0x02,0x00,0x40,0xa9,0x6d,0x73,0x97,0x9e,0xfc,0x9b,0x8e,0x5b,0x8c,0xfa,0xb2,0x0c,0xb2,0x57,0x0f,0xb2,0xf7,0x29,0x4e,0xa2,0xcb,0xbd,0x5b,0x52,0x74,0xb1,0x2a,0xb7,0xc5,0xd9,0x62,0x6d,0x37,0x6d,0x9d,0xa3,0xe9,0x61,0xbb,0x1b,0x2b,0x56,0xb7,0x86,0x0c,0xe6,0xb1,0x07,0x6f,0xe0,0xf8,0x8a,0xd3,0x05,0x83,0xf6,0x53,0x0e,0xd2,0x72,0xd5,0xc1,0x50} }, - { 0x01020E03, + { 0x01020E03,0x384, {0x01,0x02,0x00,0x00,0x0e,0x03,0x00,0x40,0xb6,0xde,0xa8,0xce,0x86,0x1c,0x42,0x72,0xa8,0x16,0x4b,0xf9,0xce,0x33,0xb5,0x43,0xd0,0x50,0xe6,0xa7,0xf1,0xcb,0x55,0x25,0x97,0x13,0xee,0x62,0x98,0xe7,0x17,0x50,0xeb,0x3b,0x59,0x10,0x0a,0xb6,0x2e,0x93,0x61,0x71,0x3c,0xe6,0xe2,0x2c,0x1e,0x7d,0xbd,0x6a,0x49,0xbb,0x04,0x5b,0xdf,0x2f,0xb7,0xa7,0x93,0xe0,0x3d,0x40,0x4e,0xd1} }, -#else - { 0x01020203, + // + { 0x01020203,0x383, {0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x83,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} }, - { 0x01020E02, + { 0x01020E02,0x383, {0x01,0x02,0x00,0x00,0x0E,0x02,0x00,0x40,0x65,0xEF,0xD0,0xA7,0xF3,0x80,0x48,0x0E,0xC1,0x4B,0x41,0x6C,0xDB,0x68,0x47,0xE4,0x23,0xAD,0x96,0x12,0x07,0x58,0x58,0x29,0xE9,0x14,0x27,0x7F,0x7D,0xF8,0xC2,0x65,0x76,0x4D,0x75,0x04,0x7C,0x9B,0xAA,0x99,0x58,0xEA,0xE2,0x43,0xB5,0x03,0x05,0xD6,0x62,0x99,0xF5,0x18,0x16,0x4E,0xCF,0x49,0x11,0xBD,0xF3,0xEE,0xC3,0xCD,0x90,0x3B} }, - { 0x01020E03, + { 0x01020E03,0x383, {0x01,0x02,0x00,0x00,0x0E,0x03,0x00,0x40,0x9B,0x06,0xB5,0x0A,0x98,0xC6,0x2E,0x1D,0x71,0xA1,0xE8,0x84,0xAE,0x98,0x57,0xE9,0xE6,0xC2,0x97,0x46,0x25,0x7A,0x2B,0xA1,0xD5,0x33,0x18,0xDE,0x16,0xC1,0xAB,0x22,0x2C,0xC2,0x11,0x24,0x81,0x11,0xA8,0x39,0xE3,0xB1,0xDB,0x33,0x1A,0x93,0x31,0xB0,0x61,0xD8,0xDE,0x92,0x1F,0x29,0x20,0xD0,0x9E,0x0F,0x6A,0xF0,0x7C,0xBA,0xCD,0xCC} }, -#endif - { 0x01020003, + // + { 0x01020003,0x0, {0x01,0x02,0x00,0x00,0x00,0x03,0x00,0x14,0x37,0x30,0x31,0x32,0x30,0x36,0x39,0x33,0x34,0x37,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, - { 0x01020103, + { 0x01020103,0x0, {0x01,0x02,0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x17,0x00,0x00,0x01,0x00,0x17,0x00,0x00,0x01,0x04,0x00,0xF3,0x86,0x01,0x1A} }, - { 0x01021100, + { 0x01021100,0x0, {0x01,0x02,0x58,0x00,0x11,0x00,0x00,0x00} }, - { 0x01020903, + { 0x01020903,0x0, {0x01,0x02,0x55,0x00,0x09,0x03,0x00,0x00} }, - { 0x01020303, + { 0x01020303,0x0, {0x01,0x02,0x00,0x00,0x03,0x03,0x02,0x18,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }, - { 0x01020400, + { 0x01020400,0x0, {0x01,0x02,0x54,0x00,0x04,0x00,0x00,0x00} }, - { 0x01050000, + { 0x01050000,0x0, {0x01,0x05,0x9D,0x00,0x38,0x00,0x02,0x16,0x00,0x01,0x00,0x13,0xFF,0xFF,0x22,0x88,0xBF,0x02,0x70,0xFA,0x5F,0x80,0xFD,0x1E,0xD4,0xD6,0xF0,0xF1,0x81,0xB3} }, - { 0x01010000, + { 0x01010000,0x0, {0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xFF} }, - { 0x00000000, // don't delete this one + { 0x00000000,0x0, // don't delete this one {} } }; const unsigned int cmd=(mem[0]<<24) + (mem[1]<<16) + (mem[2]<<8) + mem[3]; const struct Resp *r=&resp[0]; + int acs=acs384 ? 0x384:0x383; while(1) { if(!r->cmd) { static const unsigned char fail[] = { 0x01,0x99,0x6f }; PUSH(fail,sizeof(fail)); break; } - if(cmd==r->cmd) { + if(cmd==r->cmd && (!r->acs || r->acs==acs)) { const int len=r->data[7]+9-1; int cs=0x3f; for(int i=0 ; idata[i]; @@ -667,50 +1418,21 @@ int cSerial::Write(const unsigned char *mem, int len, int delay) } r++; } -#else -#error No serial emulation mode selected -#endif + //--- return len; } -void cSerial::ToggleRTS(void) -{ - rts=!rts; - if(!rts) { -#if defined(EMU_SECA) - static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00, - 0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 }; -#elif defined(EMU_IRD) - static const unsigned char atr[] = { 0x3B,0x9F,0x21,0x0E, -#ifdef EMU_IRD_384 - 0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d }; -#else - 0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 }; -#endif -#elif defined(EMU_CRYPTO) - static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00, - 0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 }; -#else -#error No serial emulation mode selected -#endif - PUSH(atr,sizeof(atr)); - PRINTF(L_CORE_SERIAL,"serial: toggle RTS, now off"); - } - else { PRINTF(L_CORE_SERIAL,"serial: toggle RTS, now on"); } -} - -bool cSerial::CheckCAR(void) +void cSmartCardSlotEmuIrdeto::EmuPushAtr(void) { -#if 0 - if(time(0)>=remTime+30) { - dsr=!dsr; - remTime=time(0); - } -#endif - return dsr; + static const unsigned char atr384[] = { 0x3B,0x9F,0x21,0x0E, + 0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d }; + static const unsigned char atr383[] = { 0x3B,0x9F,0x21,0x0E, + 0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 }; + if(acs384) PUSH(atr384,sizeof(atr384)) + else PUSH(atr383,sizeof(atr383)) } -#endif //SER_EMU +#endif // CARD_EMU // -- cInfoStr ----------------------------------------------------------------- @@ -749,384 +1471,123 @@ void cInfoStr::Finish() // -- cSmartCardData ----------------------------------------------------------- -cSmartCardData::cSmartCardData(int Ident) -{ - ident=Ident; -} - -// -- cSmartCardDatas ---------------------------------------------------------- - -cSmartCardDatas carddatas; - -cSmartCardDatas::cSmartCardDatas(void) -:cStructList("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE) -{} - -cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param) -{ - ListLock(false); - cSmartCardData *cd; - for(cd=First(); cd; cd=Next(cd)) - if(cd->Ident()==param->Ident() && cd->Matches(param)) break; - ListUnlock(); - return cd; -} - -cStructItem *cSmartCardDatas::ParseLine(char *line) -{ - char *r=index(line,':'); - if(r) - for(cSmartCardLink *scl=cSmartCards::first; scl; scl=scl->next) - if(!strncasecmp(scl->name,line,r-line)) { - cSmartCardData *scd=scl->CreateData(); - if(scd && scd->Parse(r+1)) return scd; - delete scd; - break; - } - return 0; -} - -// -- cSmartCardSlot ----------------------------------------------------------- - -cSmartCardSlot::cSmartCardSlot(int num) -{ - Serial=0; Card=0; - CardId=0; UseCount=0; Dead=false; - SlotNum=num; - Clock=ISO_FREQ; -} - -cSmartCardSlot::~cSmartCardSlot() -{ - delete Card; - delete Serial; -} - -// -- cSmartCard --------------------------------------------------------------- - -static const int Ftable[16] = { - 372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0 - }; - -static const float Dtable[16] = { - 0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0, - 0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625 - }; - -cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg) -{ - msg=Msg; - ser=0; atr=0; idStr[0]=0; cardUp=false; needsReset=true; - NewCardConfig(Cfg); -} - -void cSmartCard::NewCardConfig(const struct CardConfig *Cfg) -{ - cfg=Cfg; -} - -bool cSmartCard::GetCardIdStr(char *str, int len) -{ - strn0cpy(str,idStr,len); - return (str[0]!=0); -} - -bool cSmartCard::GetCardInfoStr(char *str, int len) -{ - return infoStr.Get(str,len); -} - -bool cSmartCard::Setup(cSerial *Ser, const struct Atr *Atr, int Id) -{ - ser=Ser; atr=Atr; id=Id; - if(cfg->SerMode==(ser->CurrentMode()&SM_MASK) && Init()) { - cardUp=true; needsReset=false; - return true; - } - return false; -} - -#define NEED(x) { \ - if(len+(x)>Atr->atrLen) { \ - LBPUT("SHORT ATR"); \ - return false; \ - } \ - } - -bool cSmartCard::ParseAtr(struct Atr *Atr, int id, int clock) -{ - // default values - Atr->histLen=0; Atr->T=0; Atr->F=372; Atr->D=1.0; Atr->N=0; Atr->WI=10; - Atr->BWI=4; Atr->CWI=0; Atr->Tspec=-1; - - const unsigned char *atr=Atr->atr; - if(atr[0]==0x03) { - PRINTF(L_CORE_SC,"%d: indirect convention detected",id); - cSmartCard::Invert(Atr->atr,Atr->atrLen); - Atr->convention=SM_INDIRECT; - } - else if(atr[0]==0x3B) { - PRINTF(L_CORE_SC,"%d: direct convention detected",id); - Atr->convention=SM_DIRECT; - } - else { - PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",id,atr[0]); - return false; - } - - // TS TO - Atr->histLen=atr[1]&0x0F; - int Y=atr[1]&0xF0, i=1, len=2; - LBSTARTF(L_CORE_SC); - LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",id,atr[0],Atr->histLen,i,Y); - do { - if(Y&0x10) { // TAi - NEED(1); - LBPUT("TA%d=%02x ",i,atr[len]); - if(i==1) { - Atr->TA1=atr[len]; - Atr->F=Ftable[(atr[len]>>4)&0x0F]; - Atr->D=Dtable[ atr[len] &0x0F]; - LBPUT("F=%d D=%f ",Atr->F,Atr->D); - } - else if(i==2) { - Atr->Tspec=atr[len]&0x0F; - LBPUT("Tspec=%d ",Atr->Tspec); - } - else if(i==3) { - LBPUT("IFSC=%d ",atr[len]); - } - len++; - } - if(Y&0x20) { // TBi - NEED(1); - LBPUT("TB%d=%02x ",i,atr[len]); - if(i==3) { - Atr->BWI=(atr[len]>>4)&0x0F; - Atr->CWI=atr[len]&0x0F; - LBPUT("BWI=%d CWI=%d ",Atr->BWI,Atr->CWI); - } - len++; - } - if(Y&0x40) { // TCi - NEED(1); - LBPUT("TC%d=%02x ",i,atr[len]); - if(i==1) { - Atr->N=atr[len]; - LBPUT("N=%d ",Atr->N); - } - else if(i==2) { - Atr->WI=atr[len]; - LBPUT("WI=%d ",Atr->WI); - } - else if(i==3) { - LBPUT("CHK=%s ",atr[len]&1 ? "CRC16":"LRC"); - } - len++; - } - if(Y&0x80) { // TDi - NEED(1); - LBPUT("TD%d=%02x ",i,atr[len]); - if(i==1) { - Atr->T=atr[len]&0x0F; - LBPUT("T=%d ",Atr->T); - } - else { - LBPUT("Tn=%d ",atr[len]&0x0F); - } - Y=atr[len]&0xF0; - len++; - } - else Y=0; - i++; - LBPUT("Y%d=%02x ",i,Y); - } while(Y); - NEED(Atr->histLen); - LBEND(); - - LBSTART(L_CORE_SC); - LBPUT("%d: historical:",id); - for(int i=0 ; ihistLen ; i++) LBPUT(" %02x",atr[len+i]); - LBFLUSH(); - LBPUT("%d: historical: '",id); - for(int i=0 ; ihistLen ; i++) LBPUT("%c",isprint(atr[len+i]) ? atr[len+i] : '.'); - LBEND(); +cSmartCardData::cSmartCardData(int Ident) +{ + ident=Ident; +} - memcpy(Atr->hist,&atr[len],Atr->histLen); - len+=Atr->histLen; +// -- cSmartCardDatas ---------------------------------------------------------- - // TCK - if(Atr->T!=0 && len+1<=Atr->atrLen) { - len++; - unsigned char cs=XorSum(atr+1,len-1); - // according to the ISO the initial TS byte isn't checksumed, but - // some cards do so. In this case the checksum is equal TS. - if(cs==0) PRINTF(L_CORE_SC,"%d: atr checksum ok",id); - else if(cs==atr[0]) PRINTF(L_CORE_SC,"iso: %d: atr checksum is TS (not ISO compliant)",id); - else { - PRINTF(L_CORE_SC,"%d: atr checksum FAILED (cs:%02x)",id,cs); - return false; - } - } - else PRINTF(L_CORE_SC,"%d: atr checksum not given/not required",id); +class cSmartCardDatas : public cStructList { +protected: + virtual cStructItem *ParseLine(char *line); +public: + cSmartCardDatas(void); + cSmartCardData *Find(cSmartCardData *param); + }; - if(Atr->atrLen>len) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",id,Atr->atrLen,len); - Atr->wwt=960*Atr->WI*Atr->F/(clock/1000); - Atr->bwt=(int)(960*(float)(1<BWI)*372/(clock/1000)); - PRINTF(L_CORE_SC,"%d: indicated wwt(T0)=%d ms, bwt(T1)=%d ms (at %.4f MHz)",id,Atr->wwt,Atr->bwt,(float)clock/1000000); - return true; +static cSmartCardDatas carddatas; + +cSmartCardDatas::cSmartCardDatas(void) +:cStructList("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE) +{} + +cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param) +{ + ListLock(false); + cSmartCardData *cd; + for(cd=First(); cd; cd=Next(cd)) + if(cd->Ident()==param->Ident() && cd->Matches(param)) break; + ListUnlock(); + return cd; } -void cSmartCard::Invert(unsigned char *data, int n) +cStructItem *cSmartCardDatas::ParseLine(char *line) { - static const unsigned char swaptab[] = { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 }; - for(int i=n-1; i>=0; i--) - data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4]; + char *r=index(line,':'); + if(r) + for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl)) + if(!strncasecmp(scl->Name(),line,r-line)) { + cSmartCardData *scd=scl->CreateData(); + if(scd && scd->Parse(r+1)) return scd; + delete scd; + break; + } + return 0; } -int cSmartCard::SerRead(unsigned char *data, int len, int to) +// -- cSmartCard --------------------------------------------------------------- + +cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg) { - if(atr->T==1 || atr->T==14) { - int r=Read(data,len,to); - if(r<0) Test(false); - return r; - } - else { - PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",id,atr->T); - return -1; - } + msg=Msg; + slot=0; atr=0; idStr[0]=0; cardUp=false; + NewCardConfig(Cfg); } -int cSmartCard::SerWrite(const unsigned char *data, int len) +void cSmartCard::NewCardConfig(const struct CardConfig *Cfg) { - if(atr->T==1 || atr->T==14) { - int r=Write(data,len); - if(r<0) Test(false); - return r; - } - else { - PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",id,atr->T); - return -1; - } + cfg=Cfg; } -int cSmartCard::Read(unsigned char *data, int len, int to) +bool cSmartCard::GetCardIdStr(char *str, int len) { - int r=ser->Read(data,len,cfg->serTO,to); - if(atr->convention==SM_INDIRECT && r>0) Invert(data,r); - return r; + strn0cpy(str,idStr,len); + return (str[0]!=0); +} + +bool cSmartCard::GetCardInfoStr(char *str, int len) +{ + return infoStr.Get(str,len); } -int cSmartCard::Write(const unsigned char *data, int len) +bool cSmartCard::Setup(cSmartCardSlot *Slot, int sermode, const struct Atr *Atr) { - unsigned char *tmp=AUTOMEM(len); - if(atr->convention==SM_INDIRECT) { - memcpy(tmp,data,len); - Invert(tmp,len); - data=tmp; - } - int r=ser->Write(data,len,cfg->serDL); - if(r>0) { - unsigned char *buff=AUTOMEM(r); - int rr=ser->Read(buff,r,cfg->serTO); - if(rr<0) r=rr; - } - return r; + slot=Slot; atr=Atr; slotnum=slot->SlotNum(); + cardUp=false; + if(cfg->SerMode==sermode && Init()) cardUp=true; + return cardUp; } -int cSmartCard::Procedure(unsigned char ins, int restLen) +int cSmartCard::SerRead(unsigned char *data, int len, int to) { - int r; - unsigned char buff; - LBSTARTF(L_CORE_SC); - LBPUT("%d: <- PROC: ",id); - do { - do { - if(Read(&buff,1,cfg->workTO)<=0) return -1; - LBPUT("%02x ",buff); - } while(buff==0x60); + if(atr->T==1 || atr->T==14) return slot->RawRead(data,len,to); + PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T); + return -1; +} - if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2 - sb[0]=buff; - if(Read(&buff,1)<=0) return -1; - LBPUT("%02x",buff); - sb[1]=buff; - return 0; - } - else { - if((buff&0xFE)==(ins&0xFE)) r=restLen; - else if((~buff&0xFE)==(ins&0xFE)) r=1; - else { - LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins); - return -1; - } - if(r>restLen) { - LBPUT("data overrun r=%d restLen=%d",r,restLen); - return -1; - } - } - } while(r==0); - LBEND(); - return r; +int cSmartCard::SerWrite(const unsigned char *data, int len) +{ + if(atr->T==1 || atr->T==14) return slot->RawWrite(data,len); + PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T); + return -1; } bool cSmartCard::IsoRead(const unsigned char *cmd, unsigned char *data) { - if(atr->T==0) { // only for ISO complaint cards - LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",id); - if(Write(cmd,CMD_LEN)<0) return Test(false); - int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256; - int len=0; - while(1) { - int r=Procedure(cmd[INS_IDX],tr-len); - if(r<=0) return Test(r==0); - if(Read(data+len,r)<0) return Test(false); - LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",id); - len+=r; - } - } - else PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",id,atr->T); + if(atr->T==0) return slot->IsoRead(cmd,data); + PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",slotnum,atr->T); return false; } bool cSmartCard::IsoWrite(const unsigned char *cmd, const unsigned char *data) { - if(atr->T==0) { // only for ISO complaint cards - LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",id); - if(Write(cmd,CMD_LEN)<0) return Test(false); - int len=0; - while(1) { - int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len); - if(r<=0) return Test(r==0); - if(Write(data+len,r)<0) return Test(false); - LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",id); - len+=r; - } - } - else PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",id,atr->T); + if(atr->T==0) return slot->IsoWrite(cmd,data); + PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",slotnum,atr->T); return false; } -bool cSmartCard::Test(bool res) -{ - if(!res) { - TriggerReset(); - PRINTF(L_CORE_SC,"%d: reset triggered",id); - } - return res; -} - bool cSmartCard::Status(void) { const struct StatusMsg *m=msg; while(m->sb[0]!=0xFF) { if(sb[0]==m->sb[0] && (m->sb[1]==0xFF || sb[1]==m->sb[1])) { - if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",id,m->message,sb[0],sb[1]); + if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",slotnum,m->message,sb[0],sb[1]); return m->retval; } m++; } - PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",id,sb[0],sb[1]); + PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",slotnum,sb[0],sb[1]); return false; } @@ -1154,15 +1615,6 @@ cSmartCardLink *cSmartCards::first=0; cSmartCards smartcards; -static const char *serModes[] = { 0,"8e2","8o2","8n2" }; - -cSmartCards::cSmartCards(void) -:cThread("SmartcardWatcher") -,cStructListPlain("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE) -{ - firstRun=true; -} - void cSmartCards::Register(cSmartCardLink *scl) { PRINTF(L_CORE_DYN,"registering %s smartcard (id %x)",scl->name,scl->id); @@ -1170,329 +1622,71 @@ void cSmartCards::Register(cSmartCardLink *scl) first=scl; } -void cSmartCards::LaunchWatcher(void) -{ - firstRun=true; - if(Count()>0) Start(); - else { - firstRun=false; - PRINTF(L_GEN_WARN,"no smartcard slot defined!"); - } -} - void cSmartCards::Shutdown(void) { - PreLoad(); + carddatas.SafeClear(); + cardslots.SafeClear(); } -void cSmartCards::PreLoad(void) +void cSmartCards::Disable(void) { - Cancel(3); - mutex.Lock(); - Clear(); Modified(false); - mutex.Unlock(); + carddatas.Disable(); + cardslots.Disable(); } -bool cSmartCards::ParseLinePlain(const char *line) +cSmartCardData *cSmartCards::FindCardData(cSmartCardData *param) { - char type[32]; - int num; - if(sscanf(line,"%31[^:]:%n",type,&num)==1) { - if(!strcasecmp(type,"serial")) { - int invCD=0, invRST=0, clock=0; - char devName[64]; - if(sscanf(&line[num],"%63[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) { - cSmartCardSlot *slot=new cSmartCardSlot(Count()); - if(slot) { - cSerial *ser=new cSerial(devName,invCD,invRST); - if(ser && ser->Open()) { - slot->Serial=ser; - if(clock>0) slot->Clock=clock; - Add(slot); - PRINTF(L_CORE_LOAD,"smartcards: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)", - devName,slot->SlotNum,invCD?"inverse":"normal",invRST?"inverse":"normal",slot->Clock); - return true; - } - else PRINTF(L_GEN_ERROR,"failed to open serial port %s",devName); - delete ser; - delete slot; - } - else PRINTF(L_GEN_ERROR,"failed to create cardslot"); - } - else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",type); - } - else PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type); - } - return false; + return carddatas.Find(param); } - bool cSmartCards::HaveCard(int id) { - cMutexLock lock(&mutex); - while(Running() && firstRun) cond.Wait(mutex); - for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) - if(slot->CardId==id) return true; - return false; + bool res=false; + for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot)) + if(slot->HaveCard(id)) { res=true; break; } + cardslots.Release(); + return res; } cSmartCard *cSmartCards::LockCard(int id) { - mutex.Lock(); - while(Running() && firstRun) cond.Wait(mutex); - for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) { - if(slot->CardId==id) { - slot->UseCount++; - mutex.Unlock(); - cSmartCard *sc=slot->Card; - sc->Lock(); - if(CardInserted(slot->Serial) && sc->CardUp() && !sc->NeedsReset()) - return sc; - // if failed, unlock the card and decrement UseCount - sc->Unlock(); - mutex.Lock(); - slot->UseCount--; - cond.Broadcast(); - break; - } - } - mutex.Unlock(); - return 0; + cSmartCard *sc=0; + for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot)) + if((sc=slot->LockCard(id))) break; + cardslots.Release(); + return sc; } void cSmartCards::ReleaseCard(cSmartCard *sc) { - sc->Unlock(); - mutex.Lock(); - for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) { - if(slot->Card==sc) { - slot->UseCount--; - cond.Broadcast(); - mutex.Unlock(); - return; - } - } - mutex.Unlock(); - PRINTF(L_GEN_DEBUG,"internal: can't find port in cSmartCards::ReleaseCard()"); -} - -bool cSmartCards::CardInserted(cSerial *ser) -{ - return ser->CheckCAR(); -} - -bool cSmartCards::CardReset(cSmartCardSlot *port) -{ - if(Reset(port)<2 || !cSmartCard::ParseAtr(&port->Atr,port->SlotNum,port->Clock)) - return false; - if(!DoPTS(port)) { - // reset card again and continue without PTS - if(Reset(port)<2 || !cSmartCard::ParseAtr(&port->Atr,port->SlotNum,port->Clock)) - return false; - } - return true; -} - -int cSmartCards::Reset(cSmartCardSlot *port) -{ - cSerial *ser=port->Serial; - PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",port->SlotNum,serModes[ser->CurrentMode()]); - ser->ToggleRTS(); - cCondWait::SleepMs(100); - ser->ToggleRTS(); - int r=ser->Read(port->Atr.atr,-MAX_ATR_LEN,800,2000); - port->Atr.atrLen=r; - if(r>0) LDUMP(L_CORE_SC,port->Atr.atr,r,"%d: <- ATR len=%d:",port->SlotNum,r); - return r; -} - -bool cSmartCards::DoPTS(cSmartCardSlot *port) -{ - const struct Atr *atr=&port->Atr; - if(atr->F!=372 || atr->D!=1.0) { // PTS required - cSerial *ser=port->Serial; - const int id=port->SlotNum; - int baud=(int)((float)port->Clock*atr->D/atr->F); - PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",id,baud); - - if(atr->Tspec<0) { - PRINTF(L_CORE_SC,"%d: negotiable mode",id); -#ifdef NO_PTS_PROTO - PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",id); - return true; -#else - unsigned char req[4], conf[16]; - req[0]=0xFF; - req[1]=0x10 | atr->T; - req[2]=atr->TA1; - req[3]=XorSum(req,3); - LDUMP(L_CORE_SC,req,4,"%d: PTS request:",id); - if(ser->Write(req,4)!=4) { - PRINTF(L_CORE_SC,"%d: PTS request, write failed",id); - return false; - } - if(ser->Read(conf,4,100,100)!=4) { - PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",id); - return false; - } - int n=ser->Read(conf,-16,200,1000); - if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",id); - if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) { - PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",id); - return false; - } - if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) { - PRINTF(L_CORE_SC,"%d: PTS not confirmed",id); - return false; - } -#endif // NO_PTS_PROTO - } - else - PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",id,atr->Tspec); - - int mode=ser->CurrentMode(); - if(atr->N==255) mode|=SM_1SB; - if(!ser->SetMode(mode,baud)) { - PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",id,baud); - return false; - } - } - return true; -} - -void cSmartCards::SetPort(cSmartCardSlot *port, cSmartCard *sc, int id, bool dead) -{ - mutex.Lock(); - while(port->UseCount) cond.Wait(mutex); - delete port->Card; - port->Card=sc; - port->CardId=id; - port->Dead=dead; - port->UseCount=0; - mutex.Unlock(); -} - -void cSmartCards::Action(void) -{ - while(Running()) { - for(cSmartCardSlot *slot=First(); slot;) { - cSerial *ser=slot->Serial; - if(ser) { - if(slot->Card) { - cSmartCard *sc=slot->Card; - sc->Lock(); - if(!CardInserted(ser)) { - sc->Unlock(); sc=0; - PRINTF(L_CORE_SC,"%d: card removed (UseCount=%d)",slot->SlotNum,slot->UseCount); - SetPort(slot,0,0,false); - } - else if(sc->NeedsReset()) { - PRINTF(L_CORE_SC,"%d: card reset requested",slot->SlotNum); - if(!ser->SetMode(ser->CurrentMode()&SM_MASK) - || !CardReset(slot) - || !sc->Setup(ser,&slot->Atr,slot->SlotNum)) { - sc->Unlock(); sc=0; - PRINTF(L_CORE_SC,"%d: card re-init failed",slot->SlotNum); - SetPort(slot,0,0,true); - } - } - if(sc) sc->Unlock(); - } - else if(CardInserted(ser)) { - if(!slot->Dead) { - PRINTF(L_CORE_SC,"%d: new card inserted",slot->SlotNum); - for(int mode=SM_NONE+1 ; modeSetMode(mode)) { - if(CardReset(slot)) { - cSmartCardLink *scl=first; - while(scl) { - PRINTF(L_CORE_SC,"%d: checking for %s card",slot->SlotNum,scl->name); - cSmartCard *sc=scl->Create(); - if(sc && sc->Setup(ser,&slot->Atr,slot->SlotNum)) { - SetPort(slot,sc,scl->id,false); - goto next; // ugly, any better solution? - } - delete sc; - scl=scl->next; - } - PRINTF(L_CORE_SC,"%d: no card handler found",slot->SlotNum); - } - else PRINTF(L_CORE_SC,"%d: reset/atr error",slot->SlotNum); - } - else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slot->SlotNum,serModes[mode]); - } - slot->Dead=true; - PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slot->SlotNum); - } - } - else { - if(slot->Dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slot->SlotNum); - slot->Dead=false; - } - } -next: slot=Next(slot); - } - if(firstRun) { - mutex.Lock(); - cond.Broadcast(); - firstRun=false; - mutex.Unlock(); - } - cCondWait::SleepMs(300); - } -} - -cSmartCardSlot *cSmartCards::GetSlot(int num) -{ - for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) - if(slot->SlotNum==num) return slot; - return 0; + for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot)) + slot->ReleaseCard(sc); + cardslots.Release(); } bool cSmartCards::ListCard(int num, char *str, int len) { - cSmartCardSlot *slot=GetSlot(num); - if(!slot) return false; + cSmartCardSlot *slot=cardslots.GetSlot(num); str[0]=0; - mutex.Lock(); - cSmartCard *sc=slot->Card; - if(sc) { - if(!sc->GetCardIdStr(str,len)) { - cSmartCardLink *scl=first; - while(scl) { - if(scl->id==slot->CardId) { - strn0cpy(str,scl->name,len); - break; - } - scl=scl->next; - } - } - } - mutex.Unlock(); - return true; + bool res=false; + if(slot) { slot->GetCardIdStr(str,len); res=true; } + cardslots.Release(); + return res; } bool cSmartCards::CardInfo(int num, char *str, int len) { + cSmartCardSlot *slot=cardslots.GetSlot(num); + str[0]=0; bool res=false; - cSmartCardSlot *slot=GetSlot(num); - if(slot) { - str[0]=0; - mutex.Lock(); - cSmartCard *sc=slot->Card; - if(sc) res=sc->GetCardInfoStr(str,len); - mutex.Unlock(); - } + if(slot) res=slot->GetCardInfoStr(str,len); + cardslots.Release(); return res; } void cSmartCards::CardReset(int num) { - cSmartCardSlot *slot=GetSlot(num); - if(slot) { - mutex.Lock(); - cSmartCard *sc=slot->Card; - if(sc) sc->TriggerReset(); - mutex.Unlock(); - } + cSmartCardSlot *slot=cardslots.GetSlot(num); + if(slot) slot->TriggerReset(); + cardslots.Release(); } diff --git a/smartcard.h b/smartcard.h index 63c1ed9..eac4ae1 100644 --- a/smartcard.h +++ b/smartcard.h @@ -40,8 +40,8 @@ // ---------------------------------------------------------------- -class cSerial; class cSmartCards; +class cSmartCardSlot; // ---------------------------------------------------------------- @@ -74,18 +74,6 @@ public: // ---------------------------------------------------------------- -class cSmartCardDatas : public cStructList { -protected: - virtual cStructItem *ParseLine(char *line); -public: - cSmartCardDatas(void); - cSmartCardData *Find(cSmartCardData *param); - }; - -extern cSmartCardDatas carddatas; - -// ---------------------------------------------------------------- - #define SM_NONE 0 #define SM_8E2 1 #define SM_8O2 2 @@ -118,18 +106,14 @@ struct Atr { unsigned char hist[MAX_HIST]; }; -class cSmartCard : protected cMutex { -friend class cSmartCards; +class cSmartCard : public cMutex { +friend class cSmartCardSlot; private: - cSerial *ser; + cSmartCardSlot *slot; + int slotnum; const struct CardConfig *cfg; const struct StatusMsg *msg; - bool cardUp, needsReset; - int id; - // - int Procedure(unsigned char ins, int restLen); - int Read(unsigned char *data, int len, int to=0); - int Write(const unsigned char *data, int len); + bool cardUp; protected: const struct Atr *atr; unsigned char sb[SB_LEN]; @@ -141,11 +125,8 @@ protected: bool IsoRead(const unsigned char *cmd, unsigned char *data); bool IsoWrite(const unsigned char *cmd, const unsigned char *data); bool Status(void); - bool Test(bool res); void NewCardConfig(const struct CardConfig *Cfg); int CheckSctLen(const unsigned char *data, int off); - void TriggerReset(void) { needsReset=true; } - static void Invert(unsigned char *data, int n); public: cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg); virtual ~cSmartCard() {}; @@ -154,37 +135,24 @@ public: virtual bool Update(int pid, int caid, const unsigned char *data) { return false; } virtual bool CanHandle(unsigned short CaId) { return true; } // - bool Setup(cSerial *Ser, const struct Atr *Atr, int Id); - static bool ParseAtr(struct Atr *atr, int id, int clock); + bool Setup(cSmartCardSlot *Slot, int sermode, const struct Atr *Atr); bool CardUp(void) { return cardUp; } - bool NeedsReset(void) { return needsReset; } bool GetCardIdStr(char *str, int len); bool GetCardInfoStr(char *str, int len); }; // ---------------------------------------------------------------- -class cSmartCardSlot : public cStructItem { -public: - cSmartCardSlot(int num); - ~cSmartCardSlot(); - // - cSerial *Serial; - bool Dead; - cSmartCard *Card; - int CardId, UseCount, SlotNum, Clock; - struct Atr Atr; - }; - -// ---------------------------------------------------------------- - class cSmartCardLink { -public: +friend class cSmartCards; +private: cSmartCardLink *next; const char *name; int id; public: cSmartCardLink(const char *Name, int Id); + const char *Name(void) { return name; } + int Id(void) { return id; } virtual ~cSmartCardLink() {} virtual cSmartCard *Create(void)=0; virtual cSmartCardData *CreateData(void) { return 0; } @@ -192,35 +160,23 @@ public: // ---------------------------------------------------------------- -class cSmartCards : private cThread, public cStructListPlain { +class cSmartCards { friend class cSmartCardLink; -friend class cSmartCardDatas; private: static cSmartCardLink *first; - cMutex mutex; - cCondVar cond; - bool firstRun; // static void Register(cSmartCardLink *scl); - bool CardInserted(cSerial *ser); - bool CardReset(cSmartCardSlot *port); - int Reset(cSmartCardSlot *port); - bool DoPTS(cSmartCardSlot *port); - void SetPort(cSmartCardSlot *port, cSmartCard *sc, int id, bool dead); - cSmartCardSlot *GetSlot(int num); -protected: - virtual void Action(void); - virtual void PreLoad(void); - virtual bool ParseLinePlain(const char *line); public: - cSmartCards(void); void Shutdown(void); + void Disable(void); + static cSmartCardLink *First(void) { return first; } + static cSmartCardLink *Next(cSmartCardLink *scl) { return scl->next; } // to be called ONLY from a system class! + cSmartCardData *FindCardData(cSmartCardData *param); bool HaveCard(int id); cSmartCard *LockCard(int id); void ReleaseCard(cSmartCard *sc); // to be called ONLY from frontend thread! - void LaunchWatcher(void); bool ListCard(int num, char *str, int len); bool CardInfo(int num, char *str, int len); void CardReset(int num); diff --git a/systems/sc-cryptoworks/sc-cryptoworks.c b/systems/sc-cryptoworks/sc-cryptoworks.c index af38f16..9f16889 100644 --- a/systems/sc-cryptoworks/sc-cryptoworks.c +++ b/systems/sc-cryptoworks/sc-cryptoworks.c @@ -304,7 +304,7 @@ bool cSmartCardCryptoworks::Init(void) if(ReadRecord(buff,0x9E)>=66) { HEXDUMP(L_SC_EXTRA,&buff[2],64,"card ISK"); cSmartCardDataCryptoworks cd(dtIPK,Caid); - cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)carddatas.Find(&cd); + cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)smartcards.FindCardData(&cd); if(entry) { PRINTF(L_SC_EXTRA,"got IPK from smartcard.conf"); if(rsa.RSA(&buff[2],&buff[2],64,exp,entry->key,false)>0) { @@ -322,7 +322,7 @@ bool cSmartCardCryptoworks::Init(void) } if(!ucpkValid) { cSmartCardDataCryptoworks cd(dtUCPK,serial); - cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)carddatas.Find(&cd); + cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)smartcards.FindCardData(&cd); if(entry) { BN_copy(ucpk,entry->key); ucpkValid=true; @@ -418,7 +418,7 @@ bool cSmartCardCryptoworks::Init(void) } if(!pinOK) { cSmartCardDataCryptoworks cd(dtPIN,serial); - cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)carddatas.Find(&cd); + cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)smartcards.FindCardData(&cd); if(entry) { memcpy(&buff[2],entry->pin,4); pinOK=true; diff --git a/systems/sc-irdeto/sc-irdeto.c b/systems/sc-irdeto/sc-irdeto.c index 628b90d..2a316f5 100644 --- a/systems/sc-irdeto/sc-irdeto.c +++ b/systems/sc-irdeto/sc-irdeto.c @@ -462,10 +462,10 @@ bool cSmartCardIrdeto::Init(void) cSmartCardDataIrdeto *entry=0; if(!doPlain) { cSmartCardDataIrdeto cd(ACS,caId); - if(!(entry=(cSmartCardDataIrdeto *)carddatas.Find(&cd))) { + if(!(entry=(cSmartCardDataIrdeto *)smartcards.FindCardData(&cd))) { PRINTF(L_GEN_WARN,"didn't find Irdeto card specific certificate, falling back to default"); cSmartCardDataIrdeto cd(-1,-1); - if(!(entry=(cSmartCardDataIrdeto *)carddatas.Find(&cd))) { + if(!(entry=(cSmartCardDataIrdeto *)smartcards.FindCardData(&cd))) { PRINTF(L_GEN_WARN,"didn't find default Irdeto certificate, please add one"); if(ACS!=0x0384) return false; PRINTF(L_GEN_WARN,"trying pre-coded ACS 384 challenge. This mode is DEPRECATED. There ARE valid certificates for these cards available!"); diff --git a/systems/sc-nagra/sc-nagra.c b/systems/sc-nagra/sc-nagra.c index ec16d09..e0feeac 100644 --- a/systems/sc-nagra/sc-nagra.c +++ b/systems/sc-nagra/sc-nagra.c @@ -385,7 +385,7 @@ bool cSmartCardNagra::Init(void) bool sessOk=false; if(buff[5]!=0 && irdProvId==((buff[10]*256)|buff[11])) { // prepare DT08 data cSmartCardDataNagra cd(irdProvId,true); - if(!(entry=(cSmartCardDataNagra *)carddatas.Find(&cd))) { + if(!(entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd))) { PRINTF(L_GEN_WARN,"didn't find smartcard Nagra IRD modulus"); } else { @@ -395,7 +395,7 @@ bool cSmartCardNagra::Init(void) } else { cSmartCardDataNagra cd(irdProvId); - if(!(entry=(cSmartCardDataNagra *)carddatas.Find(&cd))) { + if(!(entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd))) { PRINTF(L_GEN_WARN,"didn't find smartcard Nagra CAM modulus"); } else { diff --git a/systems/sc-videoguard2/sc-videoguard2.c b/systems/sc-videoguard2/sc-videoguard2.c index c0bbd29..3080e88 100644 --- a/systems/sc-videoguard2/sc-videoguard2.c +++ b/systems/sc-videoguard2/sc-videoguard2.c @@ -566,7 +566,7 @@ bool cSmartCardVideoGuard2::Init(void) } if(!boxidOK) { cSmartCardDataVideoGuard2 cd(dtBoxId); - cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)carddatas.Find(&cd); + cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd); if(entry) { memcpy(&boxID,entry->boxid,sizeof(boxID)); boxidOK=true; @@ -603,7 +603,7 @@ bool cSmartCardVideoGuard2::Init(void) PRINTF(L_SC_INIT,"cardtype: %c%c.%d boxID %s caid %04x cardID %s",atr->hist[10],atr->hist[11],atr->hist[12],HexStr(str,boxID,4),CAID,HexStr(str2,cardID,4)); cSmartCardDataVideoGuard2 cd(dtSeed); - cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)carddatas.Find(&cd); + cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd); if(!entry) { PRINTF(L_SC_ERROR,"no NDS seed available"); return false; diff --git a/testing/Makefile b/testing/Makefile index 1a339c7..db59a91 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -23,7 +23,7 @@ DEFINES = -DAPIVERSNUM=$(APIVERSNUM) -DAPIVERSION='"$(APIVERSION)"' -DSCAPIVERS OBJS = misc.o log.o data.o crypto.o parse.o system.o system-common.o smartcard.o network.o filter.o version.o SHAREDOBJS = compat.o $(VDRDIR)/tools.o $(VDRDIR)/thread.o -LIBS = -lpthread -ljpeg -lcrypto +LIBS = -lpthread -lrt -ljpeg -lcrypto DYNLIBS = -ldl $(VDRDIR)/libsi/libsi.a NOBJS = $(patsubst %.o,../%.o,$(OBJS)) diff --git a/testing/compat.c b/testing/compat.c index e731e91..0099986 100644 --- a/testing/compat.c +++ b/testing/compat.c @@ -61,11 +61,6 @@ void InitAll(const char *cfgdir) if(Feature.KeyFile() && keys.Count()<1) PRINTF(L_GEN_ERROR,"no keys loaded for softcam!"); if(!cSystems::Init(cfgdir)) exit(2); - -#ifdef DEFAULT_PORT - smartcards.AddPort(DEFAULT_PORT); -#endif - smartcards.LaunchWatcher(); } void LogAll(void)