static void camd35_process_ecm(uchar *buf, int buflen) { ECM_REQUEST er; if (!buf || buflen < 23) return; uint16_t ecmlen = (((buf[21] & 0x0f)<< 8) | buf[22])+3; if (ecmlen + 20 > buflen) return; er.ecmlen = ecmlen; er.srvid = b2i(2, buf+ 8); er.caid = b2i(2, buf+10); er.prid = b2i(4, buf+12); memcpy(er.ecm, buf + 20, er.ecmlen); if (!ProcessECM(er.caid,er.ecm,er.cw)) { er.rc = E_FOUND; } else er.rc = E_NOTFOUND; if (er.rc == E_NOTFOUND) { buf[0] = 0x08; buf[1] = 2; memset(buf + 20, 0, buf[1]); buf[22] = er.rc; //put rc in byte 22 - hopefully don't break legacy camd3 } else { if (buf[0]==3) memmove(buf + 20 + 16, buf + 20 + buf[1], 0x34); buf[0]++; buf[1] = 16; memcpy(buf+20, er.cw, buf[1]); } camd35_send(buf, 0); }
static void pandora_process_request(struct s_client *cl, uchar *buf, int32_t l) { int ecmlen; ECM_REQUEST *er; uchar md5tmp[MD5_DIGEST_LENGTH]; if (!(er = get_ecmtask())) return; er->caid = b2i(2, buf + 1); er->srvid = b2i(2, buf + 3); er->prid = b2i(4, buf + 5); //er->ecmcrc32 = crc32(0L, buf+10, CS_ECMSTORESIZE); er->chid = b2i(2, buf + 10 + CS_ECMSTORESIZE); if (l > 12 + CS_ECMSTORESIZE + 16) { ecmlen = b2i(2, buf + 12 + CS_ECMSTORESIZE); if ((ecmlen > 320) || cl->pand_ignore_ecm) er->ecmlen = 0; else { if (!memcmp(buf + 10, MD5(buf + 14 + CS_ECMSTORESIZE, ecmlen, md5tmp), CS_ECMSTORESIZE)) { er->ecmlen = ecmlen; memcpy(er->ecm, buf + 14 + CS_ECMSTORESIZE, ecmlen); //set_ecmhash(cl, er); } else er->ecmlen = 0; } } else er->ecmlen = 0; if (!er->ecmlen) usleep(cl->pand_autodelay); get_cw(cl, er); }
static int32_t griffin_card_info(struct s_reader *rdr) { def_resp int i, r = 0; rdr_log(rdr, "Reading subscription info."); griffin_cmd(GRIFFIN_CMD_SUBSCRIPTION_INFO, NULL, 0, 16); if(cta_res[0] == 0x0b) // Old cards { for(i = 0; i < cta_lr - 8; i += 9) { rdr_log(rdr, " Subscription stream %d - %c%c%c%c%c%c", r++, cta_res[i + 2], cta_res[i + 3], cta_res[i + 4], cta_res[i + 5], cta_res[i + 6], cta_res[i + 7]); } } else if(cta_res[0] == 0x1b) // Newer cards { for(i = 0; i < cta_lr; i += 4) { rdr_log(rdr, " Subscription stream #%02d - 0x%04x", r++, b2i(2, cta_res + i + 2)); } } rdr_log(rdr, "End subscription info."); return OK; }
static void camd33_request_emm(void) { uchar mbuf[20]; struct s_reader *aureader = NULL, *rdr = NULL; //TODO: just take the first reader in list LL_ITER itr = ll_iter_create(cur_client()->aureader_list); while((rdr = ll_iter_next(&itr))) { aureader = rdr; break; } if(!aureader) { return; } if(aureader->hexserial[0]) { cs_log("%s emm-request sent (reader=%s, caid=%04X, auprovid=%06X)", username(cur_client()), aureader->label, aureader->caid, aureader->auprovid ? aureader->auprovid : b2i(4, aureader->prid[0])); mbuf[0] = 0; mbuf[1] = aureader->caid >> 8; mbuf[2] = aureader->caid & 0xff; memcpy(mbuf + 3, aureader->hexserial, 4); memcpy(mbuf + 7, &aureader->prid[0][1], 3); memcpy(mbuf + 10, &aureader->prid[2][1], 3); camd33_send(mbuf, 13); }
static void ParsePMTData(emu_stream_client_data *cdata) { uint8_t* data = cdata->data; uint16_t section_length = SCT_LEN(data); int32_t i; uint16_t program_info_length = 0, es_info_length = 0; uint8_t descriptor_tag = 0, descriptor_length = 0; uint8_t stream_type; uint16_t stream_pid, caid; program_info_length = b2i(2, data+10) &0xFFF; if(12+program_info_length >= section_length) { return; } for(i=12; i+1 < 12+program_info_length; i+=descriptor_length) { descriptor_tag = data[i]; descriptor_length = data[i+1]; if(descriptor_length < 1) { break; } if(i+1+descriptor_length >= 12+program_info_length) { break; } if(descriptor_tag == 0x09 && descriptor_length >= 4) { caid = b2i(2, data+i+2); if(caid>>8 == 0x0E) { cdata->ecm_pid = b2i(2, data+i+4) &0x1FFF; cs_log_dbg(D_READER, "[Emu] stream found ecm_pid: %X", cdata->ecm_pid); break; } } }
static void oscam_ser_process_pmt(uchar *buf, int32_t l) { int32_t i; uchar sbuf[32]; struct s_serial_client *serialdata=cur_client()->serialdata; switch(serialdata->connected) { case P_SSSP: serialdata->sssp_fix=0; memset(serialdata->sssp_tab, 0, sizeof(serialdata->sssp_tab)); serialdata->sssp_srvid=b2i(2, buf+3); serialdata->sssp_num=0; for (i=9; (i<l) && (serialdata->sssp_num<SSSP_MAX_PID); i+=7) { if(chk_ser_srvid(cur_client(), b2i(2, buf+i), b2i(2, buf+3), b2i(3, buf+i+4))) { // check support for pid (caid, sid and provid in oscam.services) memcpy(sbuf+3+(serialdata->sssp_num<<1), buf+i+2, 2); serialdata->sssp_tab[serialdata->sssp_num].caid=b2i(2, buf+i ); serialdata->sssp_tab[serialdata->sssp_num].pid =b2i(2, buf+i+2); serialdata->sssp_tab[serialdata->sssp_num].prid=b2i(3, buf+i+4); serialdata->sssp_num++; } } sbuf[0]=0xF1; sbuf[1]=0; sbuf[2]=(serialdata->sssp_num<<1); oscam_ser_send(cur_client(), sbuf, sbuf[2]+3); break; } }
static int32_t camd35_recv(uchar *buf, int32_t rs) { int32_t rc = 0, s, n=0, buflen=0, len=0; for (s=0; !rc; s++) { switch(s) { case 0: if (rs < 36) { rc = -1; goto out; } break; case 1: switch (camd35_auth_client(buf)) { case 0: break; // ok case 1: rc=-2; break; // unknown user } memmove(buf, buf+4, rs-=4); break; case 2: aes_decrypt(&cl_aes_keys, buf, rs); if (rs!=boundary(4, rs)) cs_log_debug("WARNING: packet size has wrong decryption boundary"); n=(buf[0]==3) ? 0x34 : 0; //Fix for ECM request size > 255 (use ecm length field) if(buf[0]==0) buflen = (((buf[21]&0x0f)<< 8) | buf[22])+3; else buflen = buf[1]; n = boundary(4, n+20+buflen); cs_log_debug("received %d bytes from client", rs); if (n<rs) cs_log_debug("ignoring %d bytes of garbage", rs-n); else if (n>rs) rc=-3; break; case 3: if (crc32(0L, buf+20, buflen)!=b2i(4, buf+4)) rc=-4; if (!rc) rc=n; break; } } out: switch(rc) { case -2: cs_log("unknown user"); break; case -3: cs_log("incomplete request!"); break; case -4: cs_log("checksum error (wrong password?)"); break; } return(rc); }
int32_t emm_reader_match(struct s_reader *reader, uint16_t caid, uint32_t provid) { int32_t i; // if physical reader a card needs to be inserted if (!is_network_reader(reader) && reader->card_status != CARD_INSERTED) return 0; if (reader->audisabled) return 0; if (reader->caid != caid) { int caid_found = 0; for (i = 0; i < 2; i++) { if (reader->csystem.caids[i] == caid) { caid_found = 1; break; } } if (!caid_found) { rdr_debug_mask(reader, D_EMM, "reader_caid %04X != caid %04X", reader->caid, caid); return 0; } } //if (!hexserialset(reader)) { There are cards without serial, they should get emm of type global and shared! // rdr_debug_mask(reader, D_EMM, "no hexserial is set"); // return 0; //} if (!provid) { rdr_debug_mask(reader, D_EMM, "caid %04X has no provider", caid); return 1; } if (reader->auprovid && reader->auprovid == provid) { rdr_debug_mask(reader, D_EMM, "matched auprovid %06X", reader->auprovid); return 1; } if (!reader->nprov) { rdr_debug_mask(reader, D_EMM, "no provider is set"); return 1; } for (i=0; i<reader->nprov; i++) { uint32_t prid = b2i(4, reader->prid[i]); if (prid == provid || ( (reader->typ == R_CAMD35 || reader->typ == R_CS378X) && (prid & 0xFFFF) == (provid & 0xFFFF) )) { rdr_debug_mask(reader, D_EMM, "provider match %04X:%06X", caid, provid); return 1; } } rdr_debug_mask(reader, D_EMM, "skip provider %04X:%06X", caid, provid); return 0; }
static void _set_pids_status(LLIST *ca_contexts, uint16_t onid, uint16_t tsid, uint16_t sid, uchar *buf, int len) { int8_t offs = 0; uint16_t pid = 0; while(offs < len) { pid = b2i(2, buf + offs); offs += 2; _set_pid_status(ca_contexts, onid, tsid, sid, pid); } }
static void camd35_process_ecm(uchar *buf, int buflen){ ECM_REQUEST er; if (!buf || buflen < 23) return; uint16_t ecmlen = (((buf[21] & 0x0f)<< 8) | buf[22])+3; if (ecmlen + 20 > buflen) return; er.ecmlen = ecmlen; er.srvid = b2i(2, buf+ 8); er.caid = b2i(2, buf+10); er.prid = b2i(4, buf+12); er.rc = buf[3]; ProcessECM(er.caid,buf + 20,er.cw); if (er.rc == E_STOPPED) { buf[0] = 0x08; buf[1] = 2; buf[20] = 0; /* * the second Databyte should be forseen for a sleeptime in minutes * whoever knows the camd3 protocol related to CMD08 - please help! * on tests this don't work with native camd3 */ buf[21] = 0; } if ((er.rc == E_NOTFOUND) || (er.rc == E_INVALID)) { buf[0] = 0x08; buf[1] = 2; memset(buf + 20, 0, buf[1]); buf[22] = er.rc; //put rc in byte 22 - hopefully don't break legacy camd3 } else { if (buf[0]==3) memmove(buf + 20 + 16, buf + 20 + buf[1], 0x34); buf[0]++; buf[1] = 16; memcpy(buf+20, er.cw, buf[1]); } camd35_send(buf, 0); }
static void radegast_process_ecm(uchar *buf, int32_t l) { int32_t i, n, sl; ECM_REQUEST *er; struct s_client *cl = cur_client(); if(!(er = get_ecmtask())) { return; } for(i = 0; i+1 < l; i += (sl + 2)) { sl = buf[i + 1]; switch(buf[i]) { case 2: // CAID (upper byte only, oldstyle) if(i+2 >= l) { break; } er->caid = buf[i + 2] << 8; break; case 10: // CAID if(i+3 >= l) { break; } er->caid = b2i(2, buf + i + 2); break; case 3: // ECM DATA if(i+4 >= l) { break; } er->ecmlen = (((buf[i + 1 + 2] & 0x0F) << 8) | buf[i + 2 + 2]) + 3; if(er->ecmlen < 3 || er->ecmlen > MAX_ECM_SIZE || i+2+er->ecmlen > l) { break; } memcpy(er->ecm, buf + i + 2, er->ecmlen); break; case 6: // PROVID (ASCII) if(i+2+sl > l) { break; } n = (sl > 6) ? 3 : (sl >> 1); er->prid = cs_atoi((char *) buf + i + 2 + sl - (n << 1), n, 0); break; case 7: // KEYNR (ASCII), not needed break; case 8: // ECM PROCESS PID ?? don't know, not needed break; } } if(l != i) { cs_log("WARNING: ECM-request corrupt"); } else { get_cw(cl, er); } }
static void ParsePATData(emu_stream_client_data *cdata) { uint8_t* data = cdata->pat_data; uint16_t section_length = SCT_LEN(data); uint16_t srvid; int32_t i; for(i=8; i+7<section_length; i+=4) { srvid = b2i(2, data+i); if(srvid == 0) { continue; } if(cdata->srvid == srvid) { cdata->pmt_pid = b2i(2, data+i+2) & 0x1FFF; cs_log_dbg(D_READER, "stream %i found pmt pid : 0x%04X (%i)",cdata->connid, cdata->pmt_pid, cdata->pmt_pid); break; } } }
static void camd35_process_ecm(uchar *buf, int buflen){ ECM_REQUEST er; if (!buf || buflen < 23) return; uint16_t ecmlen = (((buf[21] & 0x0f)<< 8) | buf[22])+3; if (ecmlen + 20 > buflen) return; er.ecmlen = ecmlen; er.srvid = b2i(2, buf+ 8); er.caid = b2i(2, buf+10); er.prid = b2i(4, buf+12); memcpy(er.ecm, buf + 20, er.ecmlen); // ======================================================================== // HANDLE ECM HERE! Following 5 lines are just here for testing! // ======================================================================== cs_log("SRVID: %04X", er.srvid); cs_log("CAID: %04X", er.caid); cs_log("PRID: %04X", er.prid); er.rc = E_FOUND; memset(&er.cw, 0x02, sizeof(er.cw)); if (er.rc == E_NOTFOUND){ buf[0] = 0x08; buf[1] = 2; memset(buf + 20, 0, buf[1]); buf[22] = er.rc; //put rc in byte 22 - hopefully don't break legacy camd3 } else { if (buf[0]==3) memmove(buf + 20 + 16, buf + 20 + buf[1], 0x34); buf[0]++; buf[1] = 16; memcpy(buf+20, er.cw, buf[1]); } camd35_send(buf, 0); }
static void radegast_process_ecm(uchar *buf, int32_t l) { int32_t i, n, sl; ECM_REQUEST *er; struct s_client *cl = cur_client(); if (!(er=get_ecmtask())) return; for (i=0; i<l; i+=(sl+2)) { sl=buf[i+1]; switch(buf[i]) { case 2: // CAID (upper byte only, oldstyle) er->caid=buf[i+2]<<8; break; case 10: // CAID er->caid=b2i(2, buf+i+2); break; case 3: // ECM DATA er->ecmlen = sl; memcpy(er->ecm, buf+i+2, er->ecmlen); break; case 6: // PROVID (ASCII) n=(sl>6) ? 3 : (sl>>1); er->prid=cs_atoi((char *) buf+i+2+sl-(n<<1), n, 0); break; case 7: // KEYNR (ASCII), not needed break; case 8: // ECM PROCESS PID ?? don't know, not needed break; } } if (l!=i) cs_log("WARNING: ECM-request corrupt"); else get_cw(cl, er); }
uint32_t i2c_ds13x7_read() { #ifdef CLOCK_DATETIME_SUPPORT ds13x7_reg_t rtc; struct clock_datetime_t d; uint32_t temp_time; i2c_ds13x7_get_block(0, (char *)&rtc, sizeof(rtc)); d.sec = b2i(rtc.sec); d.min = b2i(rtc.min); d.hour = b2i(rtc.hour); d.dow = rtc.day; d.day = b2i(rtc.date); d.month = b2i(rtc.month&0x1f); d.year = b2i(rtc.year); if (rtc.century) d.year+= 100; uint8_t cest=0; #if TIMEZONE == TIMEZONE_CEST /* We must determine, if we have CET or CEST */ int8_t last_sunday = last_sunday_in_month(d.day, d.dow); /* march until october can be summer time */ if (d.month < 3 || d.month > 10) { cest=0; } else if (d.month == 3 && (last_sunday == -1 || (last_sunday == 0 && d.hour < 1))) { cest=0; } else if (d.month == 10 && (last_sunday == 1 || (last_sunday == 0 && d.hour > 1))) { cest=0; } else { cest=1; } #endif temp_time = clock_utc2timestamp(&d,cest); return temp_time; #else return 0; #endif /* CLOCK_DATETIME_SUPPORT */ }
static int32_t oscam_ser_check_ecm(ECM_REQUEST *er, uchar *buf, int32_t l) { int32_t i; struct s_serial_client *serialdata = cur_client()->serialdata; if (l<16) { cs_log(incomplete, l); return(1); } switch(serialdata->connected) { case P_HSIC: er->ecmlen = l-12; er->caid = b2i(2, buf+1 ); er->prid = b2i(3, buf+3 ); er->pid = b2i(2, buf+6 ); er->srvid= b2i(2, buf+10); memcpy(er->ecm, buf+12, er->ecmlen); break; case P_SSSP: er->pid=b2i(2, buf+3); for (i=0; (i<8) && (serialdata->sssp_tab[i].pid!=er->pid); i++); if (i>=serialdata->sssp_num) { cs_debug_mask(D_CLIENT, "illegal request, unknown pid=%04X", er->pid); return(2); } er->ecmlen = l-5; er->srvid= serialdata->sssp_srvid; er->caid = serialdata->sssp_tab[i].caid; er->prid = serialdata->sssp_tab[i].prid; memcpy(er->ecm, buf+5, er->ecmlen); break; case P_BOMBA: er->ecmlen = l; memcpy(er->ecm, buf, er->ecmlen); break; case P_DSR95: buf[l]='\0'; // prepare for trim trim((char *)buf+13); // strip spc, nl, cr ... er->ecmlen = strlen((char *)buf+13)>>1; er->prid=cs_atoi((char *)buf+3, 3, 0); // ignore errors er->caid=cs_atoi((char *)buf+9, 2, 0); // ignore errors if (cs_atob(er->ecm, (char *)buf+13, er->ecmlen)<0) { cs_log("illegal characters in ecm-request"); return(1); } if( serialdata->dsr9500type==P_DSR_WITHSID ) { er->ecmlen -= 2; er->srvid=cs_atoi((char *)buf+13+(er->ecmlen << 1), 2, 0); } break; case P_GS: er->ecmlen = ((buf[3]<<8)|buf[2]) - 6; er->srvid = (buf[5]<<8)|buf[4]; // sid er->caid = (buf[7]<<8)|buf[6]; er->prid = 0; if (er->ecmlen > 256) er->ecmlen = 256; memcpy(er->ecm, buf+10, er->ecmlen); break; case P_ALPHA: l=oscam_ser_alpha_convert(buf, l); er->ecmlen= b2i(2, buf+1 )-2; er->caid = b2i(2, buf+3 ); if ((er->ecmlen!=l-5) || (er->ecmlen>257)) { cs_log(incomplete, l); return(1); } memcpy(er->ecm, buf+5, er->ecmlen); break; case P_GBOX: er->srvid = b2i(2, buf+serialdata->gbox_lens.cat_len+3+3); er->ecmlen = serialdata->gbox_lens.ecm_len+3; memcpy(er->ecm, buf+serialdata->gbox_lens.cat_len+3+serialdata->gbox_lens.pmt_len+3, er->ecmlen); break; } return(0); }
static int32_t bulcrypt_card_info(struct s_reader *reader) { char tmp[512]; time_t last_upd_ts, subs_end_ts; struct tm tm; def_resp rdr_log(reader, "Reading subscription info."); cs_clear_entitlement(reader); write_cmd(cmd_sub_info1, NULL); write_cmd(cmd_sub_info2, NULL); if (cta_lr < 45) { rdr_log(reader, "(info_cmd) Unexpected card answer: %s", cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp))); return ERROR; } // Response contains: // 13 29 0B // 4F 8F 00 E9 - Unix ts set by UNIQUE_EMM_82 // 3C 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF // 3C 84 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF // 90 2B last_upd_ts = b2i(4, cta_res + 3); subs_end_ts = last_upd_ts + (31 * 86400); // *FIXME* this is just a guess reader->card_valid_to = subs_end_ts; gmtime_r(&last_upd_ts, &tm); memset(tmp, 0, sizeof(tmp)); strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S %Z", &tm); rdr_log(reader, "Subscription data last update : %s", tmp); gmtime_r(&subs_end_ts, &tm); memset(tmp, 0, sizeof(tmp)); strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S %Z", &tm); rdr_log(reader, "Subscription should be active to : %s", tmp); unsigned int subs1 = b2i(2, cta_res + 3 + 4 + 16); unsigned int subs2 = b2i(2, cta_res + 3 + 4 + 16 + 18); if (subs1 == 0xffff) { rdr_log(reader, "No active subscriptions (0x%04x, 0x%04x)", subs1, subs2); } else { unsigned int i; rdr_log(reader, "Subscription data 1 (0x%04x): %s", subs1, dec2bin_str(subs1, tmp)); rdr_log(reader, "Subscription data 2 (0x%04x): %s", subs2, dec2bin_str(subs2, tmp)); // Configure your tiers to get subscription packets name resolution // # Example oscam.tiers file // 5581:0001|Economic // 5581:0002|Standard // 5581:0004|Premium // 5581:0008|HBO // 5581:0010|Unknown Package 10 // 5581:0020|Unknown Package 20 // 5581:0040|Unknown Package 40 // 5581:0080|Unknown Package 80 for (i = 1; i < 256; i <<= 1) { if ((subs1 & i) == i) { cs_add_entitlement(reader, 0x4AEE, 0, /* provid */ i, /* id */ 0, /* class */ last_upd_ts, /* start_ts */ subs_end_ts, /* end_ts */ 4 /* type: Tier */ ); cs_add_entitlement(reader, 0x5581, 0, /* provid */ i, /* id */ 0, /* class */ last_upd_ts, /* start_ts */ subs_end_ts, /* end_ts */ 4 /* type: Tier */ ); get_tiername(i, 0x4aee, tmp); if (tmp[0] == 0x00) get_tiername(i, 0x5581, tmp); rdr_log(reader, " Package %02x is active: %s", i, tmp); } } } return OK; }
static void sha256_transform(sha256_context *ctx) { uint32 W[64]; // Words of message schedule. uint32 v[8]; // FIPS a, b, c, d, e, f, g, h working variables. if (ctx == NULL) // Clean variables and return. { cleandata(v,sizeof(v)); cleandata(W,sizeof(W)); return; } // Prepare message schedule. Loop unrolling provides some small gain here. W[0] = b2i(ctx->Data + 0 * 4 ); W[1] = b2i(ctx->Data + 1 * 4 ); W[2] = b2i(ctx->Data + 2 * 4 ); W[3] = b2i(ctx->Data + 3 * 4 ); W[4] = b2i(ctx->Data + 4 * 4 ); W[5] = b2i(ctx->Data + 5 * 4 ); W[6] = b2i(ctx->Data + 6 * 4 ); W[7] = b2i(ctx->Data + 7 * 4 ); W[8] = b2i(ctx->Data + 8 * 4 ); W[9] = b2i(ctx->Data + 9 * 4 ); W[10] = b2i(ctx->Data + 10 * 4 ); W[11] = b2i(ctx->Data + 11 * 4 ); W[12] = b2i(ctx->Data + 12 * 4 ); W[13] = b2i(ctx->Data + 13 * 4 ); W[14] = b2i(ctx->Data + 14 * 4 ); W[15] = b2i(ctx->Data + 15 * 4 ); for (uint I = 16; I < 64; I++) W[I] = sg1(W[I-2]) + W[I-7] + sg0(W[I-15]) + W[I-16]; uint32 *H=ctx->H; for (uint I = 0; I < 8; I++) v[I]=H[I]; // MSVC -O2 partially unrolls this loop automatically. for (uint I = 0; I < 64; I++) { uint T1 = v[7] + Sg1(v[4]) + Ch(v[4], v[5], v[6]) + K[I] + W[I]; // It is possible to eliminate variable copying if we unroll loop // and rename variables every time. But my test did not show any speed // gain on i7 for such full or partial unrolling. v[7] = v[6]; v[6] = v[5]; v[5] = v[4]; v[4] = v[3] + T1; // It works a little faster when moved here from beginning of loop. uint T2 = Sg0(v[0]) + Maj(v[0], v[1], v[2]); v[3] = v[2]; v[2] = v[1]; v[1] = v[0]; v[0] = T1 + T2; } for (uint I = 0; I < 8; I++) H[I]+=v[I]; }
static int32_t viaccess_card_info(struct s_reader * reader) { def_resp; int32_t i, l; uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item static const uchar ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin static const uchar cls[] = { 0x00, 0x21, 0xff, 0x9f}; static const uchar pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}; reader->last_geo.provid = 0; reader->last_geo.geo_len = 0; reader->last_geo.geo[0] = 0; rdr_log(reader, "card detected"); cs_clear_entitlement(reader); //reset the entitlements // set pin write_cmd(ins24, pin); insac[2]=0xa4; write_cmd(insac, NULL); // request unique id insb8[4]=0x07; write_cmd(insb8, NULL); // read unique id rdr_log_sensitive(reader, "serial: {%llu}", (unsigned long long) b2ll(5, cta_res+2)); insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0 for (i=1; (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0); i++) { uint32_t l_provid, l_sa; uchar l_name[64]; insc0[4]=0x1a; write_cmd(insc0, NULL); // show provider properties cta_res[2]&=0xF0; l_provid=b2i(3, cta_res); insac[2]=0xa5; write_cmd(insac, NULL); // request sa insb8[4]=0x06; write_cmd(insb8, NULL); // read sa l_sa=b2i(4, cta_res+2); insac[2]=0xa7; write_cmd(insac, NULL); // request name insb8[4]=0x02; write_cmd(insb8, NULL); // read name nano + len l=cta_res[1]; insb8[4]=l; write_cmd(insb8, NULL); // read name cta_res[l]=0; trim((char *)cta_res); if (cta_res[0]) snprintf((char *)l_name, sizeof(l_name), ", name: %s", cta_res); else l_name[0]=0; // read GEO insac[2]=0xa6; write_cmd(insac, NULL); // request GEO insb8[4]=0x02; write_cmd(insb8, NULL); // read GEO nano + len l=cta_res[1]; char tmp[l*3+1]; insb8[4]=l; write_cmd(insb8, NULL); // read geo rdr_log_sensitive(reader, "provider: %d, id: {%06X%s}, sa: {%08X}, geo: %s", i, l_provid, l_name, l_sa, (l<4) ? "empty" : cs_hexdump(1, cta_res, l, tmp, sizeof(tmp))); // read classes subscription insac[2]=0xa9; insac[4]=4; write_cmd(insac, cls); // request class subs while( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) ) { insb8[4]=0x02; write_cmd(insb8, NULL); // read class subs nano + len if( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) ) { l=cta_res[1]; insb8[4]=l; write_cmd(insb8, NULL); // read class subs if( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0x00 || cta_res[cta_lr-1]==0x08) ) { show_class(reader, NULL, l_provid, cta_res, cta_lr-2); } } } insac[4]=0; insa4[2]=0x02; write_cmd(insa4, NULL); // select next provider } //return ERROR; return OK; }
static int32_t viaccess_do_emm(struct s_reader * reader, EMM_PACKET *ep) { def_resp; static const unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id unsigned char insf0[] = { 0xca,0xf0,0x00,0x01,0x22 }; // set adf unsigned char insf4[] = { 0xca,0xf4,0x00,0x01,0x00 }; // set adf, encrypted unsigned char ins18[] = { 0xca,0x18,0x01,0x01,0x00 }; // set subscription unsigned char ins1c[] = { 0xca,0x1c,0x01,0x01,0x00 }; // set subscription, encrypted static const unsigned char insc8[] = { 0xca,0xc8,0x00,0x00,0x02 }; // read extended status // static const unsigned char insc8Data[] = { 0x00,0x00 }; // data for read extended status int32_t emmdatastart=7; if (ep->type == UNIQUE) emmdatastart++; int32_t emmLen=SCT_LEN(ep->emm)-emmdatastart; int32_t rc=0; ///cs_dump(ep->emm, emmLen+emmdatastart, "RECEIVED EMM VIACCESS"); int32_t emmUpToEnd; uchar *emmParsed = ep->emm+emmdatastart; int32_t provider_ok = 0; uint32_t emm_provid; uchar keynr = 0; int32_t ins18Len = 0; uchar ins18Data[512]; uchar insData[512]; uchar *nano81Data = 0; uchar *nano91Data = 0; uchar *nano92Data = 0; uchar *nano9EData = 0; uchar *nanoF0Data = 0; for (emmUpToEnd=emmLen; (emmParsed[1] != 0) && (emmUpToEnd > 0); emmUpToEnd -= (2 + emmParsed[1]), emmParsed += (2 + emmParsed[1])) { ///cs_dump (emmParsed, emmParsed[1] + 2, "NANO"); if (emmParsed[0]==0x90 && emmParsed[1]==0x03) { /* identification of the service operator */ uchar soid[3], ident[3], i; for (i=0; i<3; i++) { soid[i]=ident[i]=emmParsed[2+i]; } ident[2]&=0xF0; emm_provid=b2i(3, ident); keynr=soid[2]&0x0F; if (chk_prov(reader, ident, keynr)) { provider_ok = 1; } else { rdr_log(reader, "EMM: provider or key not found on card (%x, %x)", emm_provid, keynr); return ERROR; } // check if the provider changes. If yes, set the new one. If not, don't .. card will return an error if we do. if( reader->last_geo.provid != emm_provid ) { write_cmd(insa4, ident); if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) { cs_dump(insa4, 5, "set provider cmd:"); cs_dump(soid, 3, "set provider data:"); rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]); return ERROR; } } // as we are maybe changing the used provider, clear the cache, so the next ecm will re-select the correct one reader->last_geo.provid = 0; reader->last_geo.geo_len = 0; reader->last_geo.geo[0] = 0; } else if (emmParsed[0]==0x9e && emmParsed[1]==0x20) { /* adf */ if (!nano91Data) { /* adf is not crypted, so test it */ uchar custwp; uchar *afd; custwp=reader->sa[0][3]; afd=(uchar*)emmParsed+2; if( afd[31-custwp/8] & (1 << (custwp & 7)) ) rdr_debug_mask(reader, D_READER, "emm for our card %08X", b2i(4, &reader->sa[0][0])); else return SKIPPED; } // memorize nano9EData = emmParsed; } else if (emmParsed[0]==0x81) { nano81Data = emmParsed; } else if (emmParsed[0]==0x91 && emmParsed[1]==0x08) { nano91Data = emmParsed; } else if (emmParsed[0]==0x92 && emmParsed[1]==0x08) { nano92Data = emmParsed; } else if (emmParsed[0]==0xF0 && emmParsed[1]==0x08) { nanoF0Data = emmParsed; } else { /* other nanos */ show_subs(reader, emmParsed); memcpy(ins18Data+ins18Len, emmParsed, emmParsed[1] + 2); ins18Len += emmParsed [1] + 2; } } if (!provider_ok) { rdr_debug_mask(reader, D_READER, "provider not found in emm, continue anyway"); // force key to 1... keynr = 1; ///return ERROR; } if (!nanoF0Data) { cs_dump(ep->emm, ep->emmlen, "can't find 0xf0 in emm..."); return ERROR; // error } if (nano9EData) { if (!nano91Data) { // set adf insf0[3] = keynr; // key insf0[4] = nano9EData[1] + 2; write_cmd(insf0, nano9EData); if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) { cs_dump(insf0, 5, "set adf cmd:"); cs_dump(nano9EData, insf0[4] , "set adf data:"); rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]); return ERROR; } } else { // set adf crypte insf4[3] = keynr; // key insf4[4] = nano91Data[1] + 2 + nano9EData[1] + 2; memcpy (insData, nano91Data, nano91Data[1] + 2); memcpy (insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2); write_cmd(insf4, insData); if(( cta_res[cta_lr-2]!=0x90 && cta_res[cta_lr-2]!=0x91) || cta_res[cta_lr-1]!=0x00 ) { cs_dump(insf4, 5, "set adf encrypted cmd:"); cs_dump(insData, insf4[4], "set adf encrypted data:"); rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]); return ERROR; } } } if (!nano92Data) { // send subscription ins18[2] = nano9EData ? 0x01: 0x00; // found 9E nano ? ins18[3] = keynr; // key ins18[4] = ins18Len + nanoF0Data[1] + 2; memcpy (insData, ins18Data, ins18Len); memcpy (insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2); write_cmd(ins18, insData); if( (cta_res[cta_lr-2]==0x90 || cta_res[cta_lr-2]==0x91) && cta_res[cta_lr-1]==0x00 ) { rdr_debug_mask(reader, D_READER, "update successfully written"); rc=1; // written } else { cs_dump(ins18, 5, "set subscription cmd:"); cs_dump(insData, ins18[4], "set subscription data:"); rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]); } } else { // send subscription encrypted if (!nano81Data) { cs_dump(ep->emm, ep->emmlen, "0x92 found, but can't find 0x81 in emm..."); return ERROR; // error } ins1c[2] = nano9EData ? 0x01: 0x00; // found 9E nano ? if (ep->type == UNIQUE) ins1c[2] = 0x02; ins1c[3] = keynr; // key ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2; memcpy (insData, nano92Data, nano92Data[1] + 2); memcpy (insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2); memcpy (insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2); write_cmd(ins1c, insData); if( (cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0x00) ) { rdr_log(reader, "update successfully written"); rc=1; // written } else { if( cta_res[cta_lr-2]&0x1 ) rdr_log(reader, "update not written. Data already exists or unknown address"); //if( cta_res[cta_lr-2]&0x8 ) { write_cmd(insc8, NULL); if( (cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0x00) ) { rdr_log(reader, "extended status %02X %02X", cta_res[0], cta_res[1]); } //} return ERROR; } } /* Sub Main() Sc.Write("CA A4 04 00 03") RX Sc.Write("02 07 11") RX Sc.Write("CA F0 00 01 22") RX Sc.Write("9E 20") Sc.Write("10 10 08 8A 80 00 04 00 10 10 26 E8 54 80 1E 80") Sc.Write("00 01 00 00 00 00 00 50 00 00 80 02 22 00 08 50") RX Sc.Write("CA 18 01 01 11") RX Sc.Write("A9 05 34 DE 34 FF 80") Sc.Write("F0 08 1A 3E AF B5 2B EE E3 3B") RX End Sub */ return rc; }
static int32_t viaccess_do_ecm(struct s_reader * reader, const ECM_REQUEST *er, struct s_ecm_answer *ea) { def_resp; static const unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id unsigned char ins88[] = { 0xca,0x88,0x00,0x00,0x00 }; // set ecm unsigned char insf8[] = { 0xca,0xf8,0x00,0x00,0x00 }; // set geographic info static const unsigned char insc0[] = { 0xca,0xc0,0x00,0x00,0x12 }; // read dcw // //XXX what is the 4th byte for ?? int32_t ecm88Len = MIN(MAX_ECM_SIZE-4, SCT_LEN(er->ecm)-4); if(ecm88Len < 1){ rdr_log(reader, "ECM: Size of ECM couldn't be correctly calculated."); return ERROR; } uchar ecmData[ecm88Len]; memset(ecmData, 0, ecm88Len); memcpy(ecmData, er->ecm+4, ecm88Len); uchar *ecm88Data = &ecmData[0]; uint32_t provid=0; int32_t rc=0; int32_t hasD2 = 0; int32_t curEcm88len=0; int32_t nanoLen=0; uchar *nextEcm; uchar DE04[256]; int32_t D2KeyID=0; int32_t curnumber_ecm=0; //nanoD2 d2 02 0d 02 -> D2 nano, len 2 // 0d -> post AES decrypt CW // 0b -> pre AES decrypt CW int32_t nanoD2 = 0; // 0x0b = 1 0x0d = 2 memset(DE04, 0, sizeof(DE04)); //fix dorcel de04 bug nextEcm=ecm88Data; while (ecm88Len>0 && !rc) { if(ecm88Data[0] ==0x00 && ecm88Data[1] == 0x00) { // nano 0x00 and len 0x00 aren't valid ... something is obviously wrong with this ecm. rdr_log(reader, "ECM: Invalid ECM structure. Rejecting"); return ERROR; } // 80 33 nano 80 (ecm) + len (33) if(ecm88Data[0]==0x80) { // nano 80, give ecm len curEcm88len=ecm88Data[1]; nextEcm=ecm88Data+curEcm88len+2; ecm88Data += 2; ecm88Len -= 2; } if(!curEcm88len) { //there was no nano 80 -> simple ecm curEcm88len=ecm88Len; } // d2 02 0d 02 -> D2 nano, len 2, select the AES key to be used if(ecm88Data[0]==0xd2) { // test if need post or pre AES decrypt if(ecm88Data[2]==0x0b) { nanoD2 = 1; rdr_debug_mask(reader, D_READER, "ECM: nano D2 0x0b"); } if(ecm88Data[2]==0x0d) { nanoD2 = 2; rdr_debug_mask(reader, D_READER, "ECM: nano D2 0x0d"); } // use the d2 arguments to get the key # to be used int32_t len = ecm88Data[1] + 2; D2KeyID=ecm88Data[3]; ecm88Data += len; ecm88Len -= len; curEcm88len -=len; hasD2 = 1; } else hasD2 = 0; // 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here // 09 -> use key #9 // 05 67 00 if ((ecm88Data[0]==0x90 || ecm88Data[0]==0x40) && (ecm88Data[1]==0x03 || ecm88Data[1]==0x07 ) ) { uchar ident[3], keynr; uchar *ecmf8Data=0; int32_t ecmf8Len=0; nanoLen=ecm88Data[1] + 2; keynr=ecm88Data[4]&0x0F; // 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here // 09 -> use key #9 if(nanoLen>5) { curnumber_ecm =(ecm88Data[6]<<8) | (ecm88Data[7]); rdr_debug_mask(reader, D_READER, "checking if the ecm number (%x) match the card one (%x)",curnumber_ecm,reader->last_geo.number_ecm); // if we have an ecm number we check it. // we can't assume that if the nano len is 5 or more we have an ecm number // as some card don't support this if( reader->last_geo.number_ecm > 0 ) { if (reader->last_geo.number_ecm == curnumber_ecm && !( ecm88Data[nanoLen-1] == 0x01 && (ecm88Data[2] == 0x03 && ecm88Data[3] == 0x0B && ecm88Data[4] == 0x00 ) )) { keynr=ecm88Data[5]; rdr_debug_mask(reader, D_READER, "keyToUse = %02x, ECM ending with %02x",ecm88Data[5], ecm88Data[nanoLen-1]); } else { if( ecm88Data[nanoLen-1] == 0x01 && (ecm88Data[2] == 0x03 && ecm88Data[3] == 0x0B && ecm88Data[4] == 0x00 ) ) { rdr_debug_mask(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x) for provider %02x%02x%02x",ecm88Data[nanoLen-1], curnumber_ecm, ecm88Data[2], ecm88Data[3], ecm88Data[4]); } rdr_debug_mask(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x)",ecm88Data[nanoLen-1], curnumber_ecm); ecm88Data=nextEcm; ecm88Len-=curEcm88len; continue; //loop to next ecm } } else { // long ecm but we don't have an ecm number so we have to try them all. keynr=ecm88Data[5]; rdr_debug_mask(reader, D_READER, "keyToUse = %02x",ecm88Data[5]); } } memcpy (ident, &ecm88Data[2], sizeof(ident)); provid = b2i(3, ident); ident[2]&=0xF0; if(hasD2 && reader->aes_list) { // check that we have the AES key to decode the CW // if not there is no need to send the ecm to the card if(!aes_present(reader->aes_list, 0x500, (uint32_t) (provid & 0xFFFFF0) , D2KeyID)) return ERROR; } if (!chk_prov(reader, ident, keynr)) { rdr_debug_mask(reader, D_READER, "ECM: provider or key not found on card"); snprintf( ea->msglog, MSGLOGSIZE, "provider(%02x%02x%02x) or key(%d) not found on card", ident[0],ident[1],ident[2], keynr ); return ERROR; } ecm88Data+=nanoLen; ecm88Len-=nanoLen; curEcm88len-=nanoLen; // DE04 if (ecm88Data[0]==0xDE && ecm88Data[1]==0x04) { memcpy (DE04, &ecm88Data[0], 6); ecm88Data+=6; } // if( reader->last_geo.provid != provid ) { reader->last_geo.provid = provid; reader->last_geo.geo_len = 0; reader->last_geo.geo[0] = 0; write_cmd(insa4, ident); // set provider } //Nano D2 0x0b Pre AES decrypt CW if ( hasD2 && nanoD2 == 1) { uchar *ecm88DataCW = ecm88Data; int32_t cwStart = 0; //int32_t cwStartRes = 0; int32_t must_exit = 0; // find CW start while(cwStart < curEcm88len -1 && !must_exit) { if(ecm88Data[cwStart] == 0xEA && ecm88Data[cwStart+1] == 0x10) { ecm88DataCW = ecm88DataCW + cwStart + 2; must_exit = 1; } cwStart++; } // use AES from list to decrypt CW rdr_debug_mask(reader, D_READER, "Decoding CW : using AES key id %d for provider %06x",D2KeyID, (provid & 0xFFFFF0)); if (aes_decrypt_from_list(reader->aes_list,0x500, (uint32_t) (provid & 0xFFFFF0), D2KeyID, &ecm88DataCW[0], 16) == 0) snprintf( ea->msglog, MSGLOGSIZE, "AES Decrypt : key id %d not found for CAID %04X , provider %06x", D2KeyID, 0x500, (provid & 0xFFFFF0) ); } while(ecm88Len>1 && ecm88Data[0]<0xA0) { nanoLen=ecm88Data[1]+2; if (!ecmf8Data) ecmf8Data=(uchar *)ecm88Data; ecmf8Len+=nanoLen; ecm88Len-=nanoLen; curEcm88len-=nanoLen; ecm88Data+=nanoLen; } if(ecmf8Len) { if( reader->last_geo.geo_len!=ecmf8Len || memcmp(reader->last_geo.geo, ecmf8Data, reader->last_geo.geo_len)) { memcpy(reader->last_geo.geo, ecmf8Data, ecmf8Len); reader->last_geo.geo_len= ecmf8Len; insf8[3]=keynr; insf8[4]=ecmf8Len; write_cmd(insf8, ecmf8Data); } } ins88[2]=ecmf8Len?1:0; ins88[3]=keynr; ins88[4]= curEcm88len; // // we should check the nano to make sure the ecm is valid // we should look for at least 1 E3 nano, 1 EA nano and the F0 signature nano // // DE04 if (DE04[0]==0xDE) { uint32_t l = curEcm88len-6; if (l > 256 || curEcm88len <= 6) { //don't known if this is ok... rdr_log(reader, "ecm invalid/too long! len=%d", curEcm88len); return ERROR; } memcpy(DE04+6, (uchar *)ecm88Data, l); write_cmd(ins88, DE04); // request dcw } else { write_cmd(ins88, (uchar *)ecm88Data); // request dcw } // write_cmd(insc0, NULL); // read dcw switch(cta_res[0]) { case 0xe8: // even if(cta_res[1]==8) { memcpy(ea->cw,cta_res+2,8); rc=1; } break; case 0xe9: // odd if(cta_res[1]==8) { memcpy(ea->cw+8,cta_res+2,8); rc=1; } break; case 0xea: // complete if(cta_res[1]==16) { memcpy(ea->cw,cta_res+2,16); rc=1; } break; default : ecm88Data=nextEcm; ecm88Len-=curEcm88len; rdr_debug_mask(reader, D_READER, "ECM: key to use is not the current one, trying next ECM"); snprintf( ea->msglog, MSGLOGSIZE, "key to use is not the current one, trying next ECM" ); } } else { //ecm88Data=nextEcm; //ecm88Len-=curEcm88len; rdr_debug_mask(reader, D_READER, "ECM: Unknown ECM type"); snprintf( ea->msglog, MSGLOGSIZE, "Unknown ECM type" ); return ERROR; /*Lets interupt the loop and exit, because we don't know this ECM type.*/ } } if ( hasD2 && !dcw_crc(ea->cw) && nanoD2 == 2) { rdr_debug_mask(reader, D_READER, "Decoding CW : using AES key id %d for provider %06x",D2KeyID, (provid & 0xFFFFF0)); rc=aes_decrypt_from_list(reader->aes_list,0x500, (uint32_t) (provid & 0xFFFFF0), D2KeyID,ea->cw, 16); if( rc == 0 ) snprintf( ea->msglog, MSGLOGSIZE, "AES Decrypt : key id %d not found for CAID %04X , provider %06x", D2KeyID, 0x500, (provid & 0xFFFFF0) ); } return(rc?OK:ERROR); }
static int32_t viaccess_card_init(struct s_reader * reader, ATR *newatr) { get_atr; def_resp; int32_t i; uchar buf[256]; uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item static const uchar insFAC[] = { 0x87, 0x02, 0x00, 0x00, 0x03 }; // init FAC static const uchar FacDat[] = { 0x00, 0x00, 0x28 }; static unsigned char ins8702_data[] = { 0x00, 0x00, 0x11}; static unsigned char ins8704[] = { 0x87, 0x04, 0x00, 0x00, 0x07 }; static unsigned char ins8706[] = { 0x87, 0x06, 0x00, 0x00, 0x04 }; if ((atr[1]!=0x77) || ((atr[2]!=0x18) && (atr[2]!=0x11) && (atr[2]!=0x19)) || ((atr[9]!=0x68) && (atr[9]!=0x6C))) return ERROR; write_cmd(insFAC, FacDat); if( !(cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0) ) return ERROR; memset(&reader->last_geo, 0, sizeof(reader->last_geo)); write_cmd(insFAC, ins8702_data); if ((cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0x00)) { write_cmd(ins8704, NULL); if ((cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0x00)) { write_cmd(ins8706, NULL); if ((cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0x00)) { reader->last_geo.number_ecm =(cta_res[2]<<8) | (cta_res[3]); rdr_log(reader, "using ecm #%x for long viaccess ecm",reader->last_geo.number_ecm); } } } // switch((atr[atrsize-4]<<8)|atr[atrsize-3]) // { // case 0x6268: ver="2.3"; break; // case 0x6668: ver="2.4(?)"; break; // case 0xa268: // default: ver="unknown"; break; // } reader->caid=0x500; memset(reader->prid, 0xff, sizeof(reader->prid)); insac[2]=0xa4; write_cmd(insac, NULL); // request unique id insb8[4]=0x07; write_cmd(insb8, NULL); // read unique id memcpy(reader->hexserial, cta_res+2, 5); // rdr_log(reader, "[viaccess-reader] type: Viaccess, ver: %s serial: %llu", ver, b2ll(5, cta_res+2)); rdr_log_sensitive(reader, "type: Viaccess (%sstandard atr), caid: %04X, serial: {%llu}", atr[9]==0x68?"":"non-",reader->caid, (unsigned long long) b2ll(5, cta_res+2)); i=0; insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0 buf[0]=0; while((cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0)) { insc0[4]=0x1a; write_cmd(insc0, NULL); // show provider properties cta_res[2]&=0xF0; reader->prid[i][0]=0; memcpy(&reader->prid[i][1], cta_res, 3); memcpy(&reader->availkeys[i][0], cta_res+10, 16); snprintf((char *)buf+strlen((char *)buf), sizeof(buf)-strlen((char *)buf), ",%06X", b2i(3, &reader->prid[i][1])); //rdr_log(reader, "[viaccess-reader] buf: %s", buf); insac[2]=0xa5; write_cmd(insac, NULL); // request sa insb8[4]=0x06; write_cmd(insb8, NULL); // read sa memcpy(&reader->sa[i][0], cta_res+2, 4); /* insac[2]=0xa7; write_cmd(insac, NULL); // request name insb8[4]=0x02; write_cmd(insb8, NULL); // read name nano + len l=cta_res[1]; insb8[4]=l; write_cmd(insb8, NULL); // read name cta_res[l]=0; rdr_log(reader, "[viaccess-reader] name: %s", cta_res); */ insa4[2]=0x02; write_cmd(insa4, NULL); // select next issuer i++; } reader->nprov=i; rdr_log(reader, "providers: %d (%s)", reader->nprov, buf+1); if (cfg.ulparent) unlock_parental(reader); rdr_log(reader, "ready for requests"); return OK; }
static int32_t conax_card_init(struct s_reader * reader, ATR *newatr) { unsigned char cta_res[CTA_RES_LEN]; int32_t i, j, n; static const uchar ins26[] = {0xDD, 0x26, 0x00, 0x00, 0x03, 0x10, 0x01, 0x40}; uchar ins82[] = {0xDD, 0x82, 0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0xb0, 0x0f, 0xff, \ 0xff, 0xfb, 0x00, 0x00, 0x09, 0x04, 0x0b, 0x00, 0xe0, 0x30, 0x2b }; uchar cardver=0; get_hist; if ((hist_size < 4) || (memcmp(hist,"0B00",4))) return ERROR; reader->caid=0xB00; if ((n=read_record(reader, ins26, ins26+5, cta_res))<=0) return ERROR; // read caid, card-version for (i=0; i<n; i+=cta_res[i+1]+2) switch(cta_res[i]) { case 0x20: cardver=cta_res[i+2]; break; case 0x28: reader->caid=(cta_res[i+2]<<8)|cta_res[i+3]; } // Ins82 command needs to use the correct CAID reported in nano 0x28 ins82[17]=(reader->caid>>8)&0xFF; ins82[18]=(reader->caid)&0xFF; if ((n=read_record(reader, ins82, ins82+5, cta_res))<=0) return ERROR; // read serial reader->nprov = 0; for (j=0, i=2; i<n; i+=cta_res[i+1]+2) switch(cta_res[i]) { case 0x23: if (cta_res[i+5] != 0x00) { memcpy(reader->hexserial, &cta_res[i+3], 6); } else { memcpy(reader->sa[j], &cta_res[i+5], 4); j++; reader->nprov++; } break; } memset(reader->prid, 0x00, sizeof(reader->prid)); rdr_log_sensitive(reader, "type: Conax, caid: %04X, serial: {%llu}, hex serial: {%02x%02x%02x%02x}, card: v%d", reader->caid, (unsigned long long) b2ll(6, reader->hexserial), reader->hexserial[2], reader->hexserial[3], reader->hexserial[4], reader->hexserial[5], cardver); rdr_log(reader, "Providers: %d", reader->nprov); for (j=0; j<reader->nprov; j++) { rdr_log(reader, "Provider: %d Provider-Id: %06X", j+1, b2i(4, reader->prid[j])); rdr_log_sensitive(reader, "Provider: %d SharedAddress: {%08X}", j+1, b2i(4, reader->sa[j])); } return OK; }
void cc_cacheex_filter_in(struct s_client *cl, uchar *buf) { struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader; int i = 0, j; CECSPVALUETAB *filter; //mode==2 write filters to acc if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 2 && cl->account->cacheex.allow_filter == 1) { filter = &cl->account->cacheex.filter_caidtab; } //mode==3 write filters to rdr else if(rdr && rdr->cacheex.mode == 3 && rdr->cacheex.allow_filter == 1) { filter = &rdr->cacheex.filter_caidtab; } else { return; } filter->n = b2i(2, buf + i); i += 2; int32_t max_filters = 30; for(j=0; j<max_filters; j++) { if(j<CS_MAXCAIDTAB) { filter->caid[j] = b2i(4, buf + i); } i += 4; } for(j=0; j<max_filters && j<CS_MAXCAIDTAB; j++) { if(j<CS_MAXCAIDTAB) { filter->cmask[j] = b2i(4, buf + i); } i += 4; } for(j=0; j<max_filters && j<CS_MAXCAIDTAB; j++) { if(j<CS_MAXCAIDTAB) { filter->prid[j] = b2i(4, buf + i); } i += 4; } for(j=0; j<max_filters && j<CS_MAXCAIDTAB; j++) { if(j<CS_MAXCAIDTAB) { filter->srvid[j] = b2i(4, buf + i); } i += 4; } cs_log_dbg(D_CACHEEX, "cacheex: received push filter request from %s", username(cl)); }
void cc_cacheex_push_in(struct s_client *cl, uchar *buf) { struct cc_data *cc = cl->cc; ECM_REQUEST *er; if(!cc) { return; } if(cl->reader) { cl->reader->last_s = cl->reader->last_g = time((time_t *)0); } if(cl) { cl->last = time(NULL); } int8_t rc = buf[14]; if(rc != E_FOUND && rc != E_UNHANDLED) //Maybe later we could support other rcs { return; } uint16_t size = buf[12] | (buf[13] << 8); if(size != sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) { cs_log_dbg(D_CACHEEX, "cacheex: %s received old cash-push format! data ignored!", username(cl)); return; } if(!(er = get_ecmtask())) { return; } er->caid = b2i(2, buf + 0); er->prid = b2i(4, buf + 2); er->srvid = b2i(2, buf + 10); er->ecm[0] = buf[19]!=0x80 && buf[19]!=0x81 ? 0 : buf[19]; //odd/even byte, usefull to send it over CSP and to check cw for swapping er->rc = rc; er->ecmlen = 0; if(buf[18]) { if(buf[18] & (0x01 << 7)) { er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime er->cwc_next_cw_cycle = 1; } else { er->cwc_cycletime = buf[18]; er->cwc_next_cw_cycle = 0; } } if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2) { if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) { cl->account->cwc_info++; } else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) { cl->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); } uint8_t *ofs = buf + 20; //Read ecmd5 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); //16 ofs += sizeof(er->ecmd5); if(!check_cacheex_filter(cl, er)) { return; } //Read csp_hash: er->csp_hash = ntohl(b2i(4, ofs)); ofs += 4; //Read cw: memcpy(er->cw, ofs, sizeof(er->cw)); //16 ofs += sizeof(er->cw); //Read lastnode count: uint8_t count = *ofs; ofs++; //check max nodes: if(count > cacheex_maxhop(cl)) { cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count, cacheex_maxhop(cl), username(cl)); NULLFREE(er); return; } cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl)); //Read lastnodes: uint8_t *data; if (er){ er->csp_lastnodes = ll_create("csp_lastnodes"); } while(count) { if(!cs_malloc(&data, 8)) { break; } memcpy(data, ofs, 8); ofs += 8; ll_append(er->csp_lastnodes, data); count--; cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl)); } //for compatibility: add peer node if no node received: if(!ll_count(er->csp_lastnodes)) { if(!cs_malloc(&data, 8)) { return; } memcpy(data, cc->peer_node_id, 8); ll_append(er->csp_lastnodes, data); cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data)); } cacheex_add_to_cache(cl, er); }
static int32_t camd35_recv(struct s_client *client, uchar *buf, int32_t l) { int32_t rc, s, rs, n = 0, buflen = 0, len = 0; for(rc = rs = s = 0; !rc; s++) { switch(s) { case 0: if(!client->udp_fd) { return (-9); } if(client->is_udp && client->typ == 'c') { rs = recv_from_udpipe(buf); } else { //read minimum packet size (4 byte ucrc + 32 byte data) to detect packet size (tcp only) //rs = cs_recv(client->udp_fd, buf, client->is_udp ? l : 36, 0); if(client->is_udp){ while (1){ rs = cs_recv(client->udp_fd, buf, l, 0); if (rs < 0){ if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { continue; } //EAGAIN needs select procedure again cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); break; }else {break;} } }else{ int32_t tot=36, readed=0; rs = 0; do { readed = cs_recv(client->udp_fd, buf+rs, tot, 0); if (readed < 0){ if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { continue; } //EAGAIN needs select procedure again cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); break; } if (readed == 0){ // nothing to read left! rc = -5; break; } if (readed > 0){ // received something, add it! tot-=readed; rs+=readed; } } while(tot!=0); } } if(rs < 36) { if(rc != -5) { rc = -1; } goto out; } break; case 1: switch(camd35_auth_client(client, buf)) { case 0: break; // ok case 1: rc = -2; break; // unknown user default: rc = -9; break; // error's from cs_auth() } memmove(buf, buf + 4, rs -= 4); break; case 2: aes_decrypt(client->aes_keys, buf, rs); if(rs != boundary(4, rs)) cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "WARNING: packet size has wrong decryption boundary"); n = (buf[0] == 3) ? 0x34 : 0; //Fix for ECM request size > 255 (use ecm length field) if(buf[0] == 0) { buflen = (((buf[21] & 0x0f) << 8) | buf[22]) + 3; } else if(buf[0] == 0x3d || buf[0] == 0x3e || buf[0] == 0x3f) //cacheex-push { buflen = buf[1] | (buf[2] << 8); } else { buflen = buf[1]; } n = boundary(4, n + 20 + buflen); if(!(client->is_udp && client->typ == 'c') && (rs < n) && ((n - 32) > 0)) { //len = cs_recv(client->udp_fd, buf+32, n-32, 0); // read the rest of the packet int32_t tot=n-32, readed=0; len = 0; do{ readed = cs_recv(client->udp_fd, buf+32+len, tot, 0); // read the rest of the packet if (readed < 0){ if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { continue; } //EAGAIN needs select procedure again cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); break; } if (readed == 0){ // nothing to read left! break; } if (readed > 0){ // received something, add it! tot-=readed; len+=readed; } } while(tot!=0); if(len > 0) { rs += len; aes_decrypt(client->aes_keys, buf + 32, len); } if(len < 0) { rc = -1; goto out; } } cs_log_dump_dbg(client->typ == 'c' ? D_CLIENT : D_READER, buf, rs, "received %d bytes from %s", rs, remote_txt()); if(n < rs) cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ignoring %d bytes of garbage", rs - n); else if(n > rs) { rc = -3; } break; case 3: if(crc32(0L, buf + 20, buflen) != b2i(4, buf + 4)) { rc = -4; } if(!rc) { rc = n; } break; } } out: if((rs > 0) && ((rc == -1) || (rc == -2))) { cs_log_dump_dbg(client->typ == 'c' ? D_CLIENT : D_READER, buf, rs, "received %d bytes from %s (native)", rs, remote_txt()); } if(rc >= 0) { client->last = time(NULL); } // last client action is now switch(rc) { //case 0: break; case -1: cs_log("packet is too small (received %d bytes, expected %d bytes)", rs, l); break; case -2: if(cs_auth_client(client, 0, "unknown user")) { cs_disconnect_client(client); } break; case -3: cs_log("incomplete request !"); break; case -4: cs_log("checksum error (wrong password ?)"); break; case -5: cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "connection closed"); break; //default: cs_log_dbg(D_TRACE, "camd35_recv returns rc=%d", rc); break; } return (rc); }
void log_emm_request(struct s_reader *rdr){ cs_log("%s emm-request sent (reader=%s, caid=%04X, auprovid=%06X)", username(cur_client()), rdr->label, rdr->caid, rdr->auprovid ? rdr->auprovid : b2i(4, rdr->prid[0])); }
static void camd35_request_emm(ECM_REQUEST *er) { int32_t i; time_t now; uchar mbuf[1024]; struct s_client *cl = cur_client(); struct s_reader *aureader = NULL, *rdr = NULL; if(er->selected_reader && !er->selected_reader->audisabled && ll_contains(cl->aureader_list, er->selected_reader)) { aureader = er->selected_reader; } if(!aureader && cl->aureader_list) { LL_ITER itr = ll_iter_create(cl->aureader_list); while((rdr = ll_iter_next(&itr))) { if(emm_reader_match(rdr, er->caid, er->prid)) { aureader = rdr; break; } } } if(!aureader) { return; } // TODO uint16_t au_caid = aureader->caid; if(!au_caid && caid_is_bulcrypt(er->caid)) // Bulcrypt has 2 caids and aureader->caid can't be used. Use ECM_REQUEST caid for AU. { au_caid = er->caid; } time(&now); if(!memcmp(cl->lastserial, aureader->hexserial, 8)) if(llabs(now - cl->last) < 180) { return; } memcpy(cl->lastserial, aureader->hexserial, 8); cl->last = now; if(au_caid) { cl->disable_counter = 0; cs_log("%s emm-request sent (reader=%s, caid=%04X, auprovid=%06X)", username(cur_client()), aureader->label, au_caid, aureader->auprovid ? aureader->auprovid : b2i(4, aureader->prid[0])); } else if(cl->disable_counter > 2) { return; } else { cl->disable_counter++; } memset(mbuf, 0, sizeof(mbuf)); mbuf[2] = mbuf[3] = 0xff; // must not be zero i2b_buf(2, er->srvid, mbuf + 8); //override request provid with auprovid if set in CMD05 if(aureader->auprovid) { if(aureader->auprovid != er->prid) { i2b_buf(4, aureader->auprovid, mbuf + 12); } else { i2b_buf(4, er->prid, mbuf + 12); } } else { i2b_buf(4, er->prid, mbuf + 12); } i2b_buf(2, er->pid, mbuf + 16); mbuf[0] = 5; mbuf[1] = 111; if(au_caid) { mbuf[39] = 1; // no. caids mbuf[20] = au_caid >> 8; // caid's (max 8) mbuf[21] = au_caid & 0xff; memcpy(mbuf + 40, aureader->hexserial, 6); // serial now 6 bytes mbuf[47] = aureader->nprov; for(i = 0; i < aureader->nprov; i++) { if((au_caid >= 0x1700 && au_caid <= 0x1799) || // Betacrypt (au_caid >= 0x0600 && au_caid <= 0x0699)) // Irdeto (don't know if this is correct, cause I don't own a IRDETO-Card) { mbuf[48 + (i * 5)] = aureader->prid[i][0]; memcpy(&mbuf[50 + (i * 5)], &aureader->prid[i][1], 3); } else { mbuf[48 + (i * 5)] = aureader->prid[i][2]; mbuf[49 + (i * 5)] = aureader->prid[i][3]; memcpy(&mbuf[50 + (i * 5)], &aureader->sa[i][0], 4); // for conax we need at least 4 Bytes } } //we think client/server protocols should deliver all information, and only readers should discard EMM mbuf[128] = (aureader->blockemm & EMM_GLOBAL && !(aureader->saveemm & EMM_GLOBAL)) ? 0 : 1; mbuf[129] = (aureader->blockemm & EMM_SHARED && !(aureader->saveemm & EMM_SHARED)) ? 0 : 1; mbuf[130] = (aureader->blockemm & EMM_UNIQUE && !(aureader->saveemm & EMM_UNIQUE)) ? 0 : 1; mbuf[127] = (aureader->blockemm & EMM_UNKNOWN && !(aureader->saveemm & EMM_UNKNOWN)) ? 0 : 1; } else // disable emm { mbuf[20] = mbuf[39] = mbuf[40] = mbuf[47] = mbuf[49] = 1; }
static int32_t dre_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea) { def_resp; uint16_t overcryptId; uint8_t tmp[16]; char tmp_dbg[256]; struct dre_data *csystem_data = reader->csystem_data; 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] = csystem_data->provider; memcpy(ecmcmd41 + 4, er->ecm + 8, 16); ecmcmd41[20] = er->ecm[6]; //keynumber ecmcmd41[21] = 0x58 + er->ecm[25]; //package number rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 8, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg(reader, D_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 if(reader->caid == 0x4ae1) { if(csystem_data->provider == 0x11 || csystem_data->provider == 0x14) { 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); rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 5, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 37, 4, tmp_dbg, sizeof(tmp_dbg))); ecmcmd51[33] = csystem_data->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 if(er->ecm[2] >= 46 && er->ecm[43] == 1 && csystem_data->provider == 0x11) { memcpy(tmp, cta_res + 11, 8); memcpy(tmp + 8, cta_res + 3, 8); overcryptId = b2i(2, &er->ecm[44]); rdr_log_dbg(reader, D_READER, "ICG ID: %04X", overcryptId); Drecrypt2OverCW(overcryptId,tmp); if(isValidDCW(tmp)) { memcpy(ea->cw, tmp, 16); return OK; } return ERROR; } DREover(reader, er->ecm, cta_res + 3); if(isValidDCW(cta_res + 3)) { memcpy(ea->cw, cta_res + 11, 8); memcpy(ea->cw + 8, cta_res + 3, 8); return OK; } } } else if((csystem_data->provider == 0x02 || csystem_data->provider == 0x03) && er->ecm[3] == 3) { // DRE 3 if (er->ecm[4] == 2) { memcpy( ea->cw , &er->ecm[42], 8); memcpy(&ea->cw[8], &er->ecm[34], 8); return OK; } uchar cmdlen; uchar crypted = er->ecm[8] & 1; uchar cryptkey = (er->ecm[8] & 6) >> 1; if (crypted == 0) { cmdlen = 50; } else { cmdlen = 57; } uchar ecmcmd[cmdlen]; memcpy(ecmcmd, &er->ecm[17], cmdlen-1); ecmcmd[cmdlen-1] = csystem_data->provider; dre_cmd_c(ecmcmd, crypted, cryptkey); if(cta_res[2] == 0xD2 && isValidDCW(cta_res + 3)) { memcpy(ea->cw, cta_res+11, 8); memcpy(ea->cw+8, cta_res+3, 8); return OK; } } } else if(reader->caid == 0x2710 && er->ecm[3] == 4)
static int32_t camd35_recv(uint8_t *buf, int32_t rs) { int32_t rc, s, n = 0, buflen = 0; for(rc = s = 0; !rc; s++) { switch(s) { case 0: if(rs < 36) { rc = -1; goto out; } break; case 1: switch(camd35_auth_client(buf)) { case 0: break; // ok case 1: rc = -2; break; // unknown user default: rc = -9; break; // error's from cs_auth() } memmove(buf, buf + 4, rs -= 4); break; case 2: aes_decrypt(&cl_aes_keys, buf, rs); if(rs != boundary(4, rs)) { cs_log_dbg(0, "WARNING: packet size has wrong decryption boundary"); } n = (buf[0] == 3) ? 0x34 : 0; //Fix for ECM request size > 255 (use ecm length field) if(buf[0] == 0) { buflen = (((buf[21] & 0x0f) << 8) | buf[22]) + 3; } else if(buf[0] == 0x3d || buf[0] == 0x3e || buf[0] == 0x3f) //cacheex-push { buflen = buf[1] | (buf[2] << 8); } else { buflen = buf[1]; } n = boundary(4, n + 20 + buflen); cs_log_dbg(0, "received %d bytes from client", rs); if(n < rs) { cs_log_dbg(0, "ignoring %d bytes of garbage", rs - n); } else if(n > rs) { rc = -3; } break; case 3: if(crc32(0, buf + 20, buflen) != b2i(4, buf + 4)) { rc = -4; cs_log_dump_dbg(buf, rs, "camd35 checksum failed for packet: "); cs_log_dbg(0, "checksum: %X", b2i(4, buf+4)); } if(!rc) { rc = n; } break; } } out: if((rs > 0) && ((rc == -1) || (rc == -2))) { cs_log_dbg(0, "received %d bytes from client (native)", rs); } switch(rc) { case -1: cs_log("packet is too small (received %d bytes, expected at least 36 bytes)", rs); break; case -2: cs_log("unknown user"); break; case -3: cs_log("incomplete request !"); break; case -4: cs_log("checksum error (wrong password ?)"); break; } return (rc); }