SASC
DVBSoftCAM

sc-conax.c

Go to the documentation of this file.
00001 /*
00002  * Softcam plugin to VDR (C++)
00003  *
00004  * This code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00018  */
00019 
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <ctype.h>
00023 
00024 #include "system-common.h"
00025 #include "smartcard.h"
00026 #include "parse.h"
00027 #include "misc.h"
00028 #include "log-sc.h"
00029 #include "log-core.h"
00030 #include "version.h"
00031 
00032 SCAPIVERSTAG();
00033 
00034 #define SYSTEM_CONAX         0x0B00
00035 
00036 #define SYSTEM_NAME          "SC-Conax"
00037 #define SYSTEM_PRI           -5
00038 #define SYSTEM_CAN_HANDLE(x) ((x)==SYSTEM_CONAX)
00039 
00040 #define SC_NAME "Conax"
00041 #define SC_ID   MAKE_SC_ID('C','o','n','x')
00042 
00043 #define L_SC        9
00044 #define L_SC_ALL    LALL(L_SC_LASTDEF)
00045 
00046 static const struct LogModule lm_sc = {
00047   (LMOD_ENABLE|L_SC_ALL)&LOPT_MASK,
00048   (LMOD_ENABLE|L_SC_DEFDEF)&LOPT_MASK,
00049   "sc-conax",
00050   { L_SC_DEFNAMES }
00051   };
00052 ADD_MODULE(L_SC,lm_sc)
00053 
00054 // -- cSystemScConax -----------------------------------------------------------
00055 
00056 class cSystemScConax : public cSystemScCore {
00057 public:
00058   cSystemScConax(void);
00059   };
00060 
00061 cSystemScConax::cSystemScConax(void)
00062 :cSystemScCore(SYSTEM_NAME,SYSTEM_PRI,SC_ID,"SC Conax")
00063 {
00064   hasLogger=true;
00065 }
00066 
00067 // -- cSystemLinkScConax -------------------------------------------------------
00068 
00069 class cSystemLinkScConax : public cSystemLink {
00070 public:
00071   cSystemLinkScConax(void);
00072   virtual bool CanHandle(unsigned short SysId);
00073   virtual cSystem *Create(void) { return new cSystemScConax; }
00074   };
00075 
00076 static cSystemLinkScConax staticInit;
00077 
00078 cSystemLinkScConax::cSystemLinkScConax(void)
00079 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
00080 {
00081   Feature.NeedsSmartCard();
00082 }
00083 
00084 bool cSystemLinkScConax::CanHandle(unsigned short SysId)
00085 {
00086   bool res=false;
00087   cSmartCard *card=smartcards.LockCard(SC_ID);
00088   if(card) {
00089     res=card->CanHandle(SysId);
00090     smartcards.ReleaseCard(card);
00091     }
00092   return res;
00093 }
00094 
00095 // -- cSmartCardDataConax ---------------------------------------------------
00096 
00097 enum eDataType { dtPIN };
00098 
00099 class cSmartCardDataConax : public cSmartCardData {
00100 private:
00101   int IdLen(void) const { return 7; }
00102 public:
00103   eDataType type;
00104   unsigned char id[7], pin[4];
00105   //
00106   cSmartCardDataConax(void);
00107   cSmartCardDataConax(eDataType Type, unsigned char *Id);
00108   virtual bool Parse(const char *line);
00109   virtual bool Matches(cSmartCardData *param);
00110   };
00111 
00112 cSmartCardDataConax::cSmartCardDataConax(void)
00113 :cSmartCardData(SC_ID)
00114 {
00115   memset(id,0,sizeof(id));
00116 }
00117 
00118 cSmartCardDataConax::cSmartCardDataConax(eDataType Type, unsigned char *Id)
00119 :cSmartCardData(SC_ID)
00120 {
00121   type=Type;
00122   memset(id,0,sizeof(id));
00123   memcpy(id,Id,IdLen());
00124 }
00125 
00126 bool cSmartCardDataConax::Matches(cSmartCardData *param)
00127 {
00128   cSmartCardDataConax *cd=(cSmartCardDataConax *)param;
00129   return cd->type==type && !memcmp(cd->id,id,IdLen());
00130 }
00131 
00132 bool cSmartCardDataConax::Parse(const char *line)
00133 {
00134   line=skipspace(line);
00135   if(!strncasecmp(line,"PIN",3)) { type=dtPIN; line+=3; }
00136   else {
00137     PRINTF(L_CORE_LOAD,"smartcarddataconax: format error: datatype");
00138     return false;
00139     }
00140   line=skipspace(line);
00141   if(GetHex(line,id,IdLen())!=IdLen()) {
00142     PRINTF(L_CORE_LOAD,"smartcarddataconax: format error: serial");
00143     return false;
00144     }
00145   line=skipspace(line);
00146   if(type==dtPIN) {
00147     for(int i=0; i<4; i++) {
00148       if(!isdigit(*line)) {
00149         PRINTF(L_CORE_LOAD,"smartcarddataconax: format error: pin");
00150         return false;
00151         }
00152       pin[i]=*line++;
00153       }
00154     }
00155   return true;
00156 }
00157 
00158 // -- cSmartCardConax ----------------------------------------------------------
00159 
00160 #define STDENTTAG 0x32
00161 #define PPVENTTAG 0x39
00162 #define ADDR_SIZE 7
00163 
00164 struct stdent {
00165   unsigned short id;
00166   char name[16], date[4][16];
00167   unsigned int pbm[2];
00168   };
00169 
00170 class cSmartCardConax : public cSmartCard, private cIdSet {
00171 private:
00172   int sysId, cardVer, currency;
00173   unsigned char ua[ADDR_SIZE];
00174   //
00175   int GetLen(void);
00176 public:
00177   cSmartCardConax(void);
00178   virtual bool Init(void);
00179   virtual bool Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw);
00180   virtual bool Update(int pid, int caid, const unsigned char *data);
00181   virtual bool CanHandle(unsigned short SysId);
00182   };
00183 
00184 static const struct StatusMsg msgs[] = {
00185   { { 0x90,0x00 }, "Instruction executed without errors", true },
00186   { { 0x90,0x11 }, "Bad instruction", false },
00187   { { 0x90,0x12 }, "Access denied, check your subscription", false },
00188   { { 0x90,0x13 }, "Bit error detected", false },
00189   { { 0x90,0x16 }, "Insuficient info", false },
00190   { { 0x94,0x00 }, "Instruction executed without errors, waiting for user interaction", true },
00191   { { 0x98,0xFF }, "Instruction accepted, data to be read", true },
00192   { { 0x9c,0xFF }, "Instruction accepted, data to be read", true },
00193   { { 0xFF,0xFF }, 0, false }
00194   };
00195 
00196 static const struct CardConfig cardCfg = {
00197   SM_8E2,1000,100
00198   };
00199 
00200 cSmartCardConax::cSmartCardConax(void)
00201 :cSmartCard(&cardCfg,msgs)
00202 {
00203   sysId=0; cardVer=0; currency=0;
00204   memset(ua,0,sizeof(ua));
00205 }
00206 
00207 bool cSmartCardConax::CanHandle(unsigned short SysId)
00208 {
00209   return (SysId==sysId);
00210 }
00211 
00212 int cSmartCardConax::GetLen(void)
00213 {
00214   return (sb[0]==0x98 || sb[0]==0x9C || (sb[0]==0x90 && sb[1]==0x00)) ? sb[1] : -1;
00215 }
00216 
00217 bool cSmartCardConax::Init(void)
00218 {
00219   static const unsigned char cnxHist[] = { '0','B','0','0' }; // XXX is this always true ?
00220 
00221   sysId=0; cardVer=0; currency=0;
00222   memset(ua,0,sizeof(ua));
00223   ResetIdSet();
00224   if(atr->histLen<4 || memcmp(atr->hist, cnxHist, atr->histLen)) {
00225     PRINTF(L_SC_INIT,"doesn't look like a Conax card");
00226     return false;
00227     }
00228 
00229   infoStr.Begin();
00230   infoStr.Strcat("Conax smartcard\n");
00231   static unsigned char ins26[] = { 0xdd, 0x26, 0x00, 0x00, 0x03 };
00232   static unsigned char insc6[] = { 0xdd, 0xc6, 0x00, 0x00, 0x03 };
00233   static unsigned char insca[] = { 0xdd, 0xca, 0x00, 0x00, 0x00 };
00234   static const unsigned char hostVer[] = { 0x10,0x01,0x01 };  // host version
00235   unsigned char buff[MAX_LEN];
00236   int l;
00237   if(!IsoWrite(ins26,hostVer) || !Status() || (l=GetLen())<=0) {
00238     PRINTF(L_SC_ERROR,"card caid request failed");
00239     return false;
00240     }
00241   insca[4]=l;
00242   if(!IsoRead(insca,buff) || !Status()) {
00243     PRINTF(L_SC_ERROR,"card caid read failed");
00244     return false;
00245     }
00246   for(int i=0; i<l; i+=buff[i+1]+2) {
00247     switch(buff[i]) {
00248       case 0x20: cardVer=buff[i+2]; break;
00249       case 0x28: {
00250                  int s=(buff[i+2]<<8)+buff[i+3];
00251                  if(s!=sysId) CaidsChanged();
00252                  sysId=s;
00253                  break;
00254                  }
00255       case 0x2f: currency=(buff[i+2]<<8)+buff[i+3]; break;
00256       }
00257     }
00258   infoStr.Printf("Card v.%d Caid %04x\n",cardVer,sysId);
00259   PRINTF(L_SC_INIT,"card v.%d caid %04x",cardVer,sysId);
00260   snprintf(idStr,sizeof(idStr),"%s (V.%d)",SC_NAME,cardVer);
00261 
00262   static unsigned char ins82[] = { 0xdd,0x82,0x00,0x00,0x11 };
00263   static const unsigned char ins82Data[] = { 0x11,0x0f,0x01,0xb0,0x0f,0xff,0xff,0xfb,0x00,0x00,0x09,0x04,0x0b,0x00,0xe0,0x30,0x2b };
00264   if(!IsoWrite(ins82,ins82Data) || !Status() || (l=GetLen())<=0) {
00265     PRINTF(L_SC_ERROR,"card serial request failed");
00266     return false;
00267     }
00268   insca[4]=l;
00269   if(!IsoRead(insca,buff) || !Status()) {
00270     PRINTF(L_SC_ERROR,"card serial read failed");
00271     return false;
00272     }
00273   LBSTARTF(L_SC_INIT);
00274   LBPUT("card serials");
00275   for(int i=2; i<l; i+=buff[i+1]+2) {
00276     if(buff[i]==0x23 && buff[i+1]==ADDR_SIZE) { // Card Address
00277       if(CheckNull(&buff[i+2],4)) {
00278         AddProv(new cProviderConax(&buff[i+2]));
00279         LBPUT(" prov");
00280         }
00281       else {
00282         SetCard(new cCardConax(&buff[i+2]));
00283         memcpy(ua,&buff[i+2],sizeof(ua));
00284         LBPUT(" card");
00285         }
00286       char str[ADDR_SIZE*2+4];
00287       LBPUT(" %s",HexStr(str,&buff[i+2],ADDR_SIZE));
00288       }
00289     }
00290   LBEND();
00291 
00292   static const unsigned char stdEntits[] = { 0x1C,0x01,0x00 };
00293   if(IsoWrite(insc6,stdEntits) && Status() && (l=GetLen())>0) {
00294     infoStr.Printf("Subscriptions:\n");
00295     infoStr.Printf("|id  |name        |date             |\n");
00296     infoStr.Printf("+----+------------+-----------------+\n");
00297 
00298     do {
00299       insca[4]=l;
00300       if(!IsoRead(insca,buff) || !Status()) {
00301         PRINTF(L_SC_ERROR,"failed to read entitlements");
00302         break;
00303         }
00304       for(int i=0; i<l; i+=buff[i+1]+2) {
00305         if(buff[i]!=STDENTTAG) {
00306           PRINTF(L_SC_ERROR,"bad entitlement format %02x != %02x",buff[i],STDENTTAG);
00307           break;
00308           }
00309 
00310         struct stdent ent;
00311         memset(&ent,0,sizeof(ent));
00312         ent.id=(buff[i+2]<<8)|buff[i+3];
00313 
00314         int date=0, pbm=0;
00315         int max=i+buff[i+1]+2;
00316         for(int j=i+4; j<max; j+=buff[j+1]+2) {
00317           switch(buff[j]) {
00318             case 0x01: // prov. name
00319               snprintf(ent.name,sizeof(ent.name),"%.12s",&buff[j+2]);
00320               break;
00321             case 0x30: // date
00322               if(date<=3) {
00323                 snprintf(ent.date[date],sizeof(ent.date[0]),"%02d.%02d.%02d",buff[j+2]&0x1F,buff[j+3]&0xF,(1990+((buff[j+3]>>4)+((buff[j+2]>>5)&0x7)*10))%100);
00324                 date++;
00325                 }
00326               break;
00327             case 0x20:
00328               if(pbm<=1) {
00329                 ent.pbm[pbm]=(buff[j+2]<<24)|(buff[j+3]<<16)|(buff[j+4]<<8)|buff[j+5];
00330                 pbm++;
00331                 }
00332               break;
00333             }         
00334           }
00335         infoStr.Printf("|%04X|%s|%s-%s|\n",ent.id,ent.name,ent.date[0],ent.date[1]);
00336         infoStr.Printf("|    |            |%s-%s|\n",ent.date[2],ent.date[3]);
00337         }
00338       } while((l=GetLen())>0);
00339     }
00340   else
00341     PRINTF(L_SC_ERROR,"requesting entitlements failed");
00342 
00343 /*
00344   static const unsigned char ppvEntits[] = { 0x1C,0x01,0x01 };
00345   if(IsoWrite(ins26,ppvEntits) && Status()) {
00346     while((l=GetLen())>0) {
00347       insca[4]=l;
00348       if(!IsoRead(insca,buff) || !Status()) {
00349         PRINTF(L_SC_ERROR,"failed to read PPV entitlements");
00350         break;
00351         }
00352 
00353 
00354       }
00355     }
00356   else
00357     PRINTF(L_SC_ERROR,"getting PPV entitlements failed");
00358 */
00359 
00360   infoStr.Finish();
00361   return true;
00362 }
00363 
00364 bool cSmartCardConax::Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
00365 {
00366   static unsigned char insa2[] = { 0xDD,0xA2,0x00,0x00,0x00 };
00367   static unsigned char insca[] = { 0xDD,0xCA,0x00,0x00,0x00 };
00368   static unsigned char insc8[] = { 0xDD,0xC8,0x00,0x00,0x07 };
00369   static unsigned char insc8data[] = { 0x1D,0x05,0x01,0x00,0x00,0x00,0x00 };
00370 
00371   int l;
00372   if((l=CheckSctLen(data,3))<=0) return false;
00373   unsigned char buff[MAX_LEN];
00374   buff[0]=0x14;
00375   buff[1]=l+1;
00376   buff[2]=0;
00377   memcpy(buff+3,data,l);
00378 
00379   insa2[4]=l+3;
00380   if(!IsoWrite(insa2,buff) || !Status() || (l=GetLen())<=0) return false;
00381   int gotIdx=0;
00382   do {
00383     insca[4]=l;
00384     if(!IsoRead(insca,buff) || !Status()) return false;
00385     for(int i=0; i<l; i+=buff[i+1]+2) {
00386       switch(buff[i]) {
00387         case 0x25:
00388           if(buff[i+1]>=13) {
00389             int idx=buff[i+4];
00390             if(idx<=1) {
00391               gotIdx|=(1<<idx);
00392               memcpy(cw+idx*8,&buff[i+7],8);
00393               }
00394             }
00395           break;
00396         case 0x31:
00397           {
00398           if(buff[i+1]==0x02 && (buff[i+2]==0x00 || buff[i+2]==0x40) && buff[i+3]==0x00)
00399             break;
00400           // PIN required
00401           cSmartCardDataConax cd(dtPIN,ua);
00402           cSmartCardDataConax *entry=(cSmartCardDataConax *)smartcards.FindCardData(&cd);
00403           if(entry) {
00404             memcpy(&insc8data[3],entry->pin,4);
00405             if(!IsoWrite(insc8,insc8data) || !Status()) {
00406               PRINTF(L_SC_ERROR,"failed to send PIN");
00407               return false;
00408               }
00409             // resend ECM request
00410             if(!IsoWrite(insa2,buff) || !Status() || GetLen()<=0) return false;
00411             gotIdx=0;
00412             l=0; continue; // abort loop
00413             }
00414           else {
00415             PRINTF(L_SC_ERROR,"no PIN available");
00416             return false;
00417             }
00418           break;
00419           }
00420         }
00421       }
00422     } while((l=GetLen())>0);
00423   if(gotIdx!=3) PRINTF(L_SC_ERROR,"strange, only got index %d cw. Failing... (this may be a bug)",gotIdx==1?0:1);
00424   return gotIdx==3;
00425 }
00426 
00427 bool cSmartCardConax::Update(int pid, int caid, const unsigned char *data)
00428 {
00429   static unsigned char ins84[] = { 0xdd,0x84,0x00,0x00,0x00 };
00430   unsigned char buff[MAX_LEN];
00431 
00432   if(MatchEMM(data)) {
00433     int l;
00434     if((l=CheckSctLen(data,2))>0) {
00435       buff[0]=0x12; buff[1]=l;
00436       memcpy(&buff[2],data,l);
00437       ins84[4]=l+2;
00438       if(IsoWrite(ins84,buff) && !Status()) return true;
00439       }
00440     }
00441   return false;
00442 }
00443 
00444 // -- cSmartCardLinkConax -------------------------------------------------------------
00445 
00446 class cSmartCardLinkConax : public cSmartCardLink {
00447 public:
00448   cSmartCardLinkConax(void):cSmartCardLink(SC_NAME,SC_ID) {}
00449   virtual cSmartCard *Create(void) { return new cSmartCardConax(); }
00450   };
00451 
00452 static cSmartCardLinkConax staticScInit;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines