|
SASC
DVBSoftCAM
|
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;