#include "globals.h" #ifdef READER_DRE #include "reader-common.h" #define OK_RESPONSE 0x61 #define CMD_BYTE 0x59 static uchar xor (const uchar * cmd, int32_t cmdlen) { int32_t i; uchar checksum = 0x00; for (i = 0; i < cmdlen; i++) checksum ^= cmd[i]; return checksum; } static int32_t dre_command (struct s_reader * reader, const uchar * cmd, int32_t cmdlen, unsigned char * cta_res, uint16_t * p_cta_lr) //attention: inputcommand will be changed!!!! answer will be in cta_res, length cta_lr ; returning 1 = no error, return ERROR = err { uchar startcmd[] = { 0x80, 0xFF, 0x10, 0x01, 0x05 }; //any command starts with this, //last byte is nr of bytes of the command that will be sent //after the startcmd //response on startcmd+cmd: = { 0x61, 0x05 } //0x61 = "OK", last byte is nr. of bytes card will send uchar reqans[] = { 0x00, 0xC0, 0x00, 0x00, 0x08 }; //after command answer has to be requested, //last byte must be nr. of bytes that card has reported to send uchar command[256]; char tmp[256]; int32_t headerlen = sizeof (startcmd); startcmd[4] = cmdlen + 3; //commandlength + type + len + checksum bytes memcpy (command, startcmd, headerlen); command[headerlen++] = CMD_BYTE; //type command[headerlen++] = cmdlen + 1; //len = command + 1 checksum byte memcpy (command + headerlen, cmd, cmdlen); uchar checksum = ~xor (cmd, cmdlen); //cs_debug_mask(D_READER, "[dre-reader] Checksum: %02x", checksum); cmdlen += headerlen; command[cmdlen++] = checksum; reader_cmd2icc (reader, command, cmdlen, cta_res, p_cta_lr); if ((*p_cta_lr != 2) || (cta_res[0] != OK_RESPONSE)) { cs_log ("[dre-reader] command sent to card: %s", cs_hexdump(0, command, cmdlen, tmp, sizeof(tmp))); cs_log ("[dre-reader] unexpected answer from card: %s", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); return ERROR; //error } reqans[4] = cta_res[1]; //adapt length byte reader_cmd2icc (reader, reqans, 5, cta_res, p_cta_lr); if (cta_res[0] != CMD_BYTE) { cs_log ("[dre-reader] unknown response: cta_res[0] expected to be %02x, is %02x", CMD_BYTE, cta_res[0]); return ERROR; } if ((cta_res[1] == 0x03) && (cta_res[2] == 0xe2)) { switch (cta_res[3]) { case 0xe1: cs_log ("[dre-reader] checksum error: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); break; case 0xe2: cs_log ("[dre-reader] wrong provider: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); break; case 0xe3: cs_log ("[dre-reader] illegal command: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); break; case 0xec: cs_log ("[dre-reader] wrong signature: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); break; default: cs_debug_mask(D_READER, "[dre-reader] unknown error: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); break; } return ERROR; //error } int32_t length_excl_leader = *p_cta_lr; if ((cta_res[*p_cta_lr - 2] == 0x90) && (cta_res[*p_cta_lr - 1] == 0x00)) length_excl_leader -= 2; checksum = ~xor (cta_res + 2, length_excl_leader - 3); if (cta_res[length_excl_leader - 1] != checksum) { cs_log ("[dre-reader] checksum does not match, expected %02x received %02x:%s", checksum, cta_res[length_excl_leader - 1], cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp))); return ERROR; //error } return OK; } #define dre_cmd(cmd) \ { \ dre_command(reader, cmd, sizeof(cmd),cta_res,&cta_lr); \ } static int32_t dre_set_provider_info (struct s_reader * reader) { def_resp; int32_t i; uchar cmd59[] = { 0x59, 0x14 }; // subscriptions uchar cmd5b[] = { 0x5b, 0x00, 0x14 }; //validity dates cs_clear_entitlement(reader); cmd59[1] = reader->provider; if ((dre_cmd (cmd59))) { //ask subscription packages, returns error on 0x11 card uchar pbm[32]; tmp_dbg(65); memcpy (pbm, cta_res + 3, cta_lr - 6); cs_debug_mask(D_READER, "[dre-reader] pbm: %s", cs_hexdump(0, pbm, 32, tmp_dbg, sizeof(tmp_dbg))); if (pbm[0] == 0xff) cs_ri_log (reader, "[dre-reader] no active packages"); else for (i = 0; i < 32; i++) if (pbm[i] != 0xff) { cmd5b[1] = i; cmd5b[2] = reader->provider; dre_cmd (cmd5b); //ask for validity dates time_t start; time_t end; start = (cta_res[3] << 24) | (cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]; end = (cta_res[7] << 24) | (cta_res[8] << 16) | (cta_res[9] << 8) | cta_res[10]; struct tm temp; localtime_r (&start, &temp); int32_t startyear = temp.tm_year + 1900; int32_t startmonth = temp.tm_mon + 1; int32_t startday = temp.tm_mday; localtime_r (&end, &temp); int32_t endyear = temp.tm_year + 1900; int32_t endmonth = temp.tm_mon + 1; int32_t endday = temp.tm_mday; cs_ri_log (reader, "[dre-reader] active package %i valid from %04i/%02i/%02i to %04i/%02i/%02i", i, startyear, startmonth, startday, endyear, endmonth, endday); cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), 0, 0, start, end, 1); } } return OK; } static int32_t dre_card_init (struct s_reader * reader, ATR newatr) { get_atr; def_resp; uchar ua[] = { 0x43, 0x15 }; // get serial number (UA) uchar providers[] = { 0x49, 0x15 }; // get providers int32_t i; char *card; char tmp[9]; if ((atr[0] != 0x3b) || (atr[1] != 0x15) || (atr[2] != 0x11) || (atr[3] != 0x12) || ( ((atr[4] != 0xca) || (atr[5] != 0x07)) && ((atr[4] != 0x01) || (atr[5] != 0x01)) )) return ERROR; reader->provider = atr[6]; uchar checksum = xor (atr + 1, 6); if (checksum != atr[7]) cs_log ("[dre-reader] warning: expected ATR checksum %02x, smartcard reports %02x", checksum, atr[7]); switch (atr[6]) { case 0x11: card = "Tricolor Centr"; reader->caid = 0x4ae1; break; //59 type card = MSP (74 type = ATMEL) case 0x12: card = "Cable TV"; reader->caid = 0x4ae1; //TODO not sure about this one break; case 0x14: card = "Tricolor Syberia / Platforma HD new"; reader->caid = 0x4ae1; break; //59 type card case 0x15: card = "Platforma HD / DW old"; reader->caid = 0x4ae1; break; //59 type card default: card = "Unknown"; reader->caid = 0x4ae1; break; } memset (reader->prid, 0x00, 8); static const uchar cmd30[] = { 0x30, 0x81, 0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x06, 0x87, 0x08, 0x09, 0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x00 }; dre_cmd (cmd30); //unknown command, generates error on card 0x11 and 0x14 /* response: 59 03 E2 E3 FE 48 */ uchar cmd54[] = { 0x54, 0x14 }; // geocode cmd54[1] = reader->provider; uchar geocode = 0; if ((dre_cmd (cmd54))) //error would not be fatal, like on 0x11 cards geocode = cta_res[3]; providers[1] = reader->provider; if (!(dre_cmd (providers))) return ERROR; //fatal error if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; uchar provname[128]; for (i = 0; ((i < cta_res[2] - 6) && (i < 128)); i++) { provname[i] = cta_res[6 + i]; if (provname[i] == 0x00) break; } int32_t major_version = cta_res[3]; int32_t minor_version = cta_res[4]; ua[1] = reader->provider; dre_cmd (ua); //error would not be fatal int32_t hexlength = cta_res[1] - 2; //discard first and last byte, last byte is always checksum, first is answer code reader->hexserial[0] = 0; reader->hexserial[1] = 0; memcpy (reader->hexserial + 2, cta_res + 3, hexlength); int32_t low_dre_id = ((cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]) - 48608; int32_t dre_chksum = 0; uchar buf[32]; snprintf ((char *)buf, sizeof(buf), "%i%i%08i", reader->provider - 16, major_version + 1, low_dre_id); for (i = 0; i < 32; i++) { if (buf[i] == 0x00) break; dre_chksum += buf[i] - 48; } //cs_ri_log("[dre-reader] type: DRE Crypt, caid: %04X, serial: %llu, card: v%x", cs_ri_log (reader, "[dre-reader] type: DRE Crypt, caid: %04X, serial: %s, dre id: %i%i%i%08i, geocode %i, card: %s v%i.%i", reader->caid, cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)), dre_chksum, reader->provider - 16, major_version + 1, low_dre_id, geocode, card, major_version, minor_version); cs_ri_log (reader, "[dre-reader] Provider name:%s.", provname); memset (reader->sa, 0, sizeof (reader->sa)); memcpy (reader->sa[0], reader->hexserial + 2, 1); //copy first byte of unique address also in shared address, because we dont know what it is... cs_ri_log (reader, "[dre-reader] SA = %02X%02X%02X%02X, UA = %s", reader->sa[0][0], reader->sa[0][1], reader->sa[0][2], reader->sa[0][3], cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp))); reader->nprov = 1; if (!dre_set_provider_info (reader)) return ERROR; //fatal error cs_log ("[dre-reader] ready for requests"); return OK; } static unsigned char DESkeys[16*8]= { 0x4A,0x11,0x23,0xB1,0x45,0x99,0xCF,0x10, // 00 0x21,0x1B,0x18,0xCD,0x02,0xD4,0xA1,0x1F, // 01 0x07,0x56,0xAB,0xB4,0x45,0x31,0xAA,0x23, // 02 0xCD,0xF2,0x55,0xA1,0x13,0x4C,0xF1,0x76, // 03 0x57,0xD9,0x31,0x75,0x13,0x98,0x89,0xC8, // 04 0xA3,0x36,0x5B,0x18,0xC2,0x83,0x45,0xE2, // 05 0x19,0xF7,0x35,0x08,0xC3,0xDA,0xE1,0x28, // 06 0xE7,0x19,0xB5,0xD8,0x8D,0xE3,0x23,0xA4, // 07 0xA7,0xEC,0xD2,0x15,0x8B,0x42,0x59,0xC5, // 08 0x13,0x49,0x83,0x2E,0xFB,0xAD,0x7C,0xD3, // 09 0x37,0x25,0x78,0xE3,0x72,0x19,0x53,0xD9, // 0A 0x7A,0x15,0xA4,0xC7,0x15,0x49,0x32,0xE8, // 0B 0x63,0xD5,0x96,0xA7,0x27,0xD8,0xB2,0x68, // 0C 0x42,0x5E,0x1A,0x8C,0x41,0x69,0x8E,0xE8, // 0D 0xC2,0xAB,0x37,0x29,0xD3,0xCF,0x93,0xA7, // 0E 0x49,0xD3,0x33,0xC2,0xEB,0x71,0xD3,0x14 // 0F }; static void DREover(const unsigned char *ECMdata, unsigned char *DW) { uchar key[8]; if(ECMdata[2] >= (43+4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B) { memcpy(key, &DESkeys[(ECMdata[42] & 0x0F) * 8], 8); doPC1(key); des(key, DES_ECS2_DECRYPT, DW); // even DW post-process des(key, DES_ECS2_DECRYPT, DW+8); // odd DW post-process }; }; static int32_t dre_do_ecm(struct s_reader * reader, const ECM_REQUEST *er, struct s_ecm_answer *ea) { def_resp; tmp_dbg(256); if (reader->caid == 0x4ae0) { uchar ecmcmd41[] = { 0x41, 0x58, 0x1f, 0x00, //fixed part, dont change 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, //0x01 - 0x08: next key 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, //0x11 - 0x18: current key 0x3b, 0x59, 0x11 //0x3b = keynumber, can be a value 56 ;; 0x59 number of package = 58+1 - Pay Package ;; 0x11 = provider }; ecmcmd41[22] = reader->provider; memcpy (ecmcmd41 + 4, er->ecm + 8, 16); ecmcmd41[20] = er->ecm[6]; //keynumber ecmcmd41[21] = 0x58 + er->ecm[25]; //package number cs_debug_mask(D_READER, "[dre-reader] unused ECM info front:%s", cs_hexdump(0, er->ecm, 8, tmp_dbg, sizeof(tmp_dbg))); cs_debug_mask(D_READER, "[dre-reader] unused ECM info back:%s", cs_hexdump(0, er->ecm + 24, er->ecm[2] + 2 - 24, tmp_dbg, sizeof(tmp_dbg))); if ((dre_cmd (ecmcmd41))) { //ecm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 memcpy (ea->cw, cta_res + 11, 8); memcpy (ea->cw + 8, cta_res + 3, 8); return OK; } } else { uchar ecmcmd51[] = { 0x51, 0x02, 0x56, 0x05, 0x00, 0x4A, 0xE3, //fixed header? 0x9C, 0xDA, //first three nibbles count up, fourth nibble counts down; all ECMs sent twice 0xC1, 0x71, 0x21, 0x06, 0xF0, 0x14, 0xA7, 0x0E, //next key? 0x89, 0xDA, 0xC9, 0xD7, 0xFD, 0xB9, 0x06, 0xFD, //current key? 0xD5, 0x1E, 0x2A, 0xA3, 0xB5, 0xA0, 0x82, 0x11, //key or signature? 0x14 //provider }; memcpy (ecmcmd51 + 1, er->ecm + 5, 0x21); cs_debug_mask(D_READER, "[dre-reader] unused ECM info front:%s", cs_hexdump(0, er->ecm, 5, tmp_dbg, sizeof(tmp_dbg))); cs_debug_mask(D_READER, "[dre-reader] unused ECM info back:%s", cs_hexdump(0, er->ecm + 37, 4, tmp_dbg, sizeof(tmp_dbg))); ecmcmd51[33] = reader->provider; //no part of sig if ((dre_cmd (ecmcmd51))) { //ecm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 DREover(er->ecm, cta_res + 3); memcpy (ea->cw, cta_res + 11, 8); memcpy (ea->cw + 8, cta_res + 3, 8); return OK; } } return ERROR; } static int32_t dre_get_emm_type(EMM_PACKET *ep, struct s_reader * rdr) { switch (ep->emm[0]) { case 0x87: ep->type = UNIQUE; return TRUE; //FIXME: no filling of ep->hexserial case 0x89: ep->type = SHARED; // FIXME: Seems to be that SA is only used with caid 0x4ae1 if (rdr->caid == 0x4ae1) { memset(ep->hexserial, 0, 8); memcpy(ep->hexserial, ep->emm + 3, 4); return (!memcmp(&rdr->sa[0][0], ep->emm + 3, 4)); } else return TRUE; default: ep->type = UNKNOWN; return TRUE; } } void dre_get_emm_filter(struct s_reader * rdr, uchar *filter) { int32_t idx = 2; filter[0]=0xFF; filter[1]=0; filter[idx++]=EMM_GLOBAL; filter[idx++]=1; //not active //FIXME: Dont now how to filter GLOBAL EMM's filter[idx+0] = 0xFF; //dummy filter[idx+0+16] = 0xFF; filter[1]++; idx += 32; filter[idx++]=EMM_SHARED; filter[idx++]=0; filter[idx+0] = 0x89; filter[idx+0+16] = 0xFF; // FIXME: Seems to be that SA is only used with caid 0x4ae1 if (rdr->caid == 0x4ae1) { memcpy(filter+idx+1, &rdr->sa[0][0], 4); memset(filter+idx+1+16, 0xFF, 4); } filter[1]++; idx += 32; filter[70]=EMM_UNIQUE; filter[71]=0; filter[72+0] = 0x87; filter[72+0+16] = 0xFF; //FIXME: No filter for hexserial filter[1]++; idx += 32; return; } static int32_t dre_do_emm (struct s_reader * reader, EMM_PACKET * ep) { def_resp; cs_ddump_mask(D_READER, ep->emm, ((ep->emm[1] & 0x0f) << 8) + ep->emm[2] + 3, "EMM:"); if (reader->caid == 0x4ae1) { if(ep->type == UNIQUE && ep->emm[39] == 0x3d) { /* For new package activation. */ uchar emmcmd58[26]; emmcmd58[0] = 0x58; memcpy(&emmcmd58[1], &ep->emm[40], 24); emmcmd58[25] = 0x15; if ((dre_cmd (emmcmd58))) if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; } else { uchar emmcmd52[0x3a]; emmcmd52[0] = 0x52; int32_t i; for (i = 0; i < 2; i++) { memcpy (emmcmd52 + 1, ep->emm + 5 + 32 + i * 56, 56); // check for shared address if(ep->emm[3]!=reader->sa[0][0]) return OK; // ignore, wrong address emmcmd52[0x39] = reader->provider; if ((dre_cmd (emmcmd52))) if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } } else { uchar emmcmd42[] = { 0x42, 0x85, 0x58, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0C, 0xBD, 0x7B, 0x07, 0x04, 0xC8, 0x77, 0x31, 0x95, 0xF2, 0x30, 0xB7, 0xE9, 0xEE, 0x0F, 0x81, 0x39, 0x1C, 0x1F, 0xA9, 0x11, 0x3E, 0xE5, 0x0E, 0x8E, 0x50, 0xA4, 0x31, 0xBB, 0x01, 0x00, 0xD6, 0xAF, 0x69, 0x60, 0x04, 0x70, 0x3A, 0x91, 0x56, 0x58, 0x11 }; int32_t i; switch (ep->type) { case UNIQUE: for (i = 0; i < 2; i++) { memcpy (emmcmd42 + 1, ep->emm + 42 + i*49, 48); emmcmd42[49] = ep->emm[i*49 + 41]; //keynr emmcmd42[50] = 0x58 + ep->emm[40]; //package nr emmcmd42[51] = reader->provider; if ((dre_cmd (emmcmd42))) { if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } break; case SHARED: default: memcpy (emmcmd42 + 1, ep->emm + 6, 48); emmcmd42[51] = reader->provider; //emmcmd42[50] = ecmcmd42[2]; //TODO package nr could also be fixed 0x58 emmcmd42[50] = 0x58; emmcmd42[49] = ep->emm[5]; //keynr /* response: 59 05 A2 02 05 01 5B 90 00 */ if ((dre_cmd (emmcmd42))) { //first emm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 memcpy (emmcmd42 + 1, ep->emm + 55, 7); //TODO OR next two lines? /*memcpy (emmcmd42 + 1, ep->emm + 55, 7); //FIXME either I cant count or my EMM log contains errors memcpy (emmcmd42 + 8, ep->emm + 67, 41); */ emmcmd42[51] = reader->provider; //emmcmd42[50] = ecmcmd42[2]; //TODO package nr could also be fixed 0x58 emmcmd42[50] = 0x58; emmcmd42[49] = ep->emm[54]; //keynr if ((dre_cmd (emmcmd42))) { //second emm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } } } return OK; //success } static int32_t dre_card_info (void) { return OK; } void reader_dre(struct s_cardsystem *ph) { ph->do_emm=dre_do_emm; ph->do_ecm=dre_do_ecm; ph->card_info=dre_card_info; ph->card_init=dre_card_init; ph->get_emm_type=dre_get_emm_type; ph->get_emm_filter=dre_get_emm_filter; ph->caids[0]=0x4A; ph->desc="dre"; } #endif