1 | #include "globals.h"
|
---|
2 | #include "CAM/seca.h"
|
---|
3 | #include "CAM/common.h"
|
---|
4 |
|
---|
5 | #include "simples.h"
|
---|
6 | #include "log.h"
|
---|
7 |
|
---|
8 | #include <stdio.h>
|
---|
9 | #include <time.h>
|
---|
10 |
|
---|
11 | static unsigned short pmap = 0; // provider-maptable
|
---|
12 | unsigned long long serial;
|
---|
13 | char *card;
|
---|
14 |
|
---|
15 | static int cam_seca_set_provider_info(int i)
|
---|
16 | {
|
---|
17 | static uchar ins12[] = { 0xc1, 0x12, 0x00, 0x00, 0x19 }; // get provider info
|
---|
18 | uchar result[260];
|
---|
19 | ushort result_size;
|
---|
20 |
|
---|
21 | int year, month, day;
|
---|
22 | struct tm *lt;
|
---|
23 | time_t t;
|
---|
24 | int valid = 0; //0=false, 1=true
|
---|
25 | char l_name[16 + 8 + 1] = ", name: ";
|
---|
26 |
|
---|
27 | ins12[2] = i; //select provider
|
---|
28 | cam_common_cmd2card(ins12, sizeof(ins12), result, sizeof(result), &result_size); // show provider properties
|
---|
29 | log_debug("hexdump:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x.", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14],
|
---|
30 | result[15], result[16], result[17], result[18], result[19], result[20], result[21], result[22], result[23], result[24], result[25], result[26]);
|
---|
31 |
|
---|
32 | if ((result[25] != 0x90) || (result[26] != 0x00))
|
---|
33 | return 0;
|
---|
34 | reader[ridx].prid[i][0] = 0;
|
---|
35 | reader[ridx].prid[i][1] = 0; //blanken high byte provider code
|
---|
36 | memcpy(&reader[ridx].prid[i][2], result, 2);
|
---|
37 | // sprintf(buf+strlen(buf), ",%06X", b2i(3, &reader[ridx].prid[i][1]));
|
---|
38 |
|
---|
39 | year = (result[22] >> 1) + 1990;
|
---|
40 | month = ((result[22] & 0x1) * 256 + (result[23] & 0xe0)) >> 5;
|
---|
41 | day = (result[23] & 0x1f);
|
---|
42 | t = time(NULL);
|
---|
43 | lt = localtime(&t);
|
---|
44 | if (lt->tm_year + 1900 != year) {
|
---|
45 | if (lt->tm_year + 1900 < year) {
|
---|
46 | valid = 1;
|
---|
47 | } else {
|
---|
48 | valid = 0;
|
---|
49 | }
|
---|
50 | } else if (lt->tm_mon + 1 != month) {
|
---|
51 | if (lt->tm_mon + 1 < month) {
|
---|
52 | valid = 1;
|
---|
53 | } else {
|
---|
54 | valid = 0;
|
---|
55 | }
|
---|
56 | } else if (lt->tm_mday != day) {
|
---|
57 | if (lt->tm_mday < day) {
|
---|
58 | valid = 1;
|
---|
59 | } else {
|
---|
60 | valid = 0;
|
---|
61 | }
|
---|
62 | }
|
---|
63 | memcpy(l_name + 8, result + 2, 16);
|
---|
64 | l_name[sizeof (l_name) - 1] = 0;
|
---|
65 | trim(l_name + 8);
|
---|
66 | l_name[0] = (l_name[8]) ? ',' : 0;
|
---|
67 | reader[ridx].availkeys[i][0] = valid; //misusing availkeys to register validity of provider
|
---|
68 | log_normal("provider: %d, valid: %i%s, expiry date: %4d/%02d/%02d", i + 1, valid, l_name, year, month, day);
|
---|
69 | memcpy(&reader[ridx].sa[i][0], result + 18, 4);
|
---|
70 | if (valid == 1) //if not expired
|
---|
71 | log_normal("SA: %s", cs_hexdump(0, result + 18, 4));
|
---|
72 |
|
---|
73 | return 1;
|
---|
74 | }
|
---|
75 |
|
---|
76 | //static int cam_seca_get_prov_index (uchar providhigh, uchar providlow) //returns provider id or -1 if not found
|
---|
77 | static int cam_seca_get_prov_index(char *provid) //returns provider id or -1 if not found
|
---|
78 | {
|
---|
79 | int prov;
|
---|
80 |
|
---|
81 | for (prov = 0; prov < reader[ridx].nprov; prov++) //search for provider index
|
---|
82 | if (!memcmp(provid, &reader[ridx].prid[prov][2], 2))
|
---|
83 | return (prov);
|
---|
84 | // for (prov=0; prov<reader[ridx].nprov; prov++) { //search for provider index
|
---|
85 | // if ((providhigh == reader[ridx].prid[prov][2]) &&
|
---|
86 | // (providlow == reader[ridx].prid[prov][3])) {
|
---|
87 | // return(prov);
|
---|
88 | // }
|
---|
89 | // }
|
---|
90 | return (-1);
|
---|
91 | }
|
---|
92 |
|
---|
93 | int cam_seca_detect(uchar *atr, ushort atr_size)
|
---|
94 | {
|
---|
95 | if (atr[10] == 0x0e && atr[11] == 0x6c && atr[12] == 0xb6 && atr[13] == 0xd6) {
|
---|
96 | return 1;
|
---|
97 | }
|
---|
98 |
|
---|
99 | return 0;
|
---|
100 | }
|
---|
101 |
|
---|
102 | int cam_seca_load_card()
|
---|
103 | {
|
---|
104 | static uchar ins0e[] = { 0xc1, 0x0e, 0x00, 0x00, 0x08 }; // get serial number (UA)
|
---|
105 | static uchar ins16[] = { 0xc1, 0x16, 0x00, 0x00, 0x07 }; // get nr. of prividers
|
---|
106 | static uchar ins30[] = { 0xc1, 0x30, 0x00, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }; // Unlock parental control
|
---|
107 |
|
---|
108 | int i;
|
---|
109 | uchar buf[256];
|
---|
110 | uchar result[260];
|
---|
111 | ushort result_size;
|
---|
112 |
|
---|
113 | buf[0] = 0x00;
|
---|
114 |
|
---|
115 | switch (reader[ridx].card_atr[7] << 8 | reader[ridx].card_atr[8]) {
|
---|
116 | case 0x5084:
|
---|
117 | card = "Generic";
|
---|
118 | break;
|
---|
119 | case 0x5384:
|
---|
120 | card = "Philips";
|
---|
121 | break;
|
---|
122 | case 0x5130:
|
---|
123 | case 0x5430:
|
---|
124 | case 0x5760:
|
---|
125 | card = "Thompson";
|
---|
126 | break;
|
---|
127 | case 0x5284:
|
---|
128 | case 0x5842:
|
---|
129 | case 0x6060:
|
---|
130 | card = "Siemens";
|
---|
131 | break;
|
---|
132 | case 0x7070:
|
---|
133 | card = "Canal+ NL";
|
---|
134 | break;
|
---|
135 | default:
|
---|
136 | card = "Unknown";
|
---|
137 | break;
|
---|
138 | }
|
---|
139 |
|
---|
140 | reader[ridx].caid[0] = 0x0100;
|
---|
141 | memset(reader[ridx].prid, 0xff, sizeof (reader[ridx].prid));
|
---|
142 | cam_common_cmd2card(ins0e, sizeof(ins0e), result, sizeof(result), &result_size); // read unique id
|
---|
143 | reader[ridx].hexserial[0] = 0;
|
---|
144 | reader[ridx].hexserial[1] = 0;
|
---|
145 | memcpy(reader[ridx].hexserial + 2, result + 2, 6);
|
---|
146 | serial = b2ll(5, result + 3);
|
---|
147 | log_normal("caid: %04X, serial: %llu, card: %s v%d.%d", reader[ridx].caid[0], serial, card, reader[ridx].card_atr[9] & 0x0F, reader[ridx].card_atr[9] >> 4);
|
---|
148 | cam_common_cmd2card(ins16, sizeof(ins0e), result, sizeof(result), &result_size); // read nr of providers
|
---|
149 | pmap = result[2] << 8 | result[3];
|
---|
150 | for (reader[ridx].nprov = 0, i = pmap; i; i >>= 1)
|
---|
151 | reader[ridx].nprov += i & 1;
|
---|
152 | // i=result[2]*256+result[3];
|
---|
153 | // do { n+=i&1; i>>=1; } while(i);
|
---|
154 | // reader[ridx].nprov=n;
|
---|
155 |
|
---|
156 | for (i = 0; i < 16; i++) {
|
---|
157 | if (pmap & (1 << i)) {
|
---|
158 | if (!cam_seca_set_provider_info(i))
|
---|
159 | return 0;
|
---|
160 | else
|
---|
161 | sprintf((char *) buf + strlen((char *) buf), ",%04lX", b2i(2, &reader[ridx].prid[i][2]));
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|
165 | log_normal("providers: %d (%s)", reader[ridx].nprov, buf + 1);
|
---|
166 |
|
---|
167 | // Unlock parental control
|
---|
168 | if (cfg->ulparent != 0) {
|
---|
169 | cam_common_cmd2card(ins30, sizeof(ins30), result, sizeof(result), &result_size);
|
---|
170 | log_normal("ins30_answer: %02x%02x", result[0], result[1]);
|
---|
171 | } else {
|
---|
172 | log_normal("parental locked");
|
---|
173 | }
|
---|
174 |
|
---|
175 | return 1;
|
---|
176 | }
|
---|
177 |
|
---|
178 | int cam_seca_process_ecm(ECM_REQUEST * er)
|
---|
179 | {
|
---|
180 | static unsigned char ins3c[] = { 0xc1, 0x3c, 0x00, 0x00, 0x00 }; // coding cw
|
---|
181 | static unsigned char ins3a[] = { 0xc1, 0x3a, 0x00, 0x00, 0x10 }; // decoding cw
|
---|
182 | uchar result[260];
|
---|
183 | ushort result_size;
|
---|
184 | uchar ins3cdata[256];
|
---|
185 | int i;
|
---|
186 |
|
---|
187 | // i = cam_seca_get_prov_index(er->ecm[3],er->ecm[4]);
|
---|
188 | i = cam_seca_get_prov_index((char *) er->ecm + 3);
|
---|
189 | if ((i == -1) || (reader[ridx].availkeys[i][0] == 0)) //if provider not found or expired
|
---|
190 | return 0;
|
---|
191 | ins3c[2] = i;
|
---|
192 | ins3c[3] = er->ecm[7]; //key nr
|
---|
193 | ins3c[4] = (((er->ecm[1] & 0x0f) * 256) + er->ecm[2]) - 0x05;
|
---|
194 |
|
---|
195 | memcpy(ins3cdata, er->ecm + 8, 256 - 8);
|
---|
196 | log_debug("do_ecm:ins3c=%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x.", ins3c[0], ins3c[1], ins3c[2], ins3c[3], ins3c[4], ins3cdata[0], ins3cdata[1], ins3cdata[2], ins3cdata[3], ins3cdata[4], ins3cdata[5], ins3cdata[6], ins3cdata[7], ins3cdata[8], ins3cdata[9]);
|
---|
197 | uchar ins3c_cmd[272];
|
---|
198 | memcpy(ins3c_cmd, ins3c, 5);
|
---|
199 | memcpy(ins3c_cmd + 5, ins3cdata, ins3c[4]);
|
---|
200 | cam_common_cmd2card(ins3c_cmd, 5 + ins3c[4], result, sizeof(result), &result_size); //ecm request
|
---|
201 | log_debug("do_ecm_answer:%02x%02x", result[0], result[1]);
|
---|
202 |
|
---|
203 | static unsigned char ins30[] = { 0xC1, 0x30, 0x00, 0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF };
|
---|
204 | /* We need to use a token */
|
---|
205 | if (result[0] == 0x90 && result[1] == 0x1a) {
|
---|
206 | cam_common_cmd2card(ins30, sizeof(ins30), result, sizeof(result), &result_size);
|
---|
207 | log_debug("do_ins30_answer:%02x%02x", result[0], result[1]);
|
---|
208 | cam_common_cmd2card(ins3c_cmd, 5 + ins3c[4], result, sizeof(result), &result_size); //ecm request
|
---|
209 | log_debug("do_ecm_answer2:%02x%02x", result[0], result[1]);
|
---|
210 | }
|
---|
211 |
|
---|
212 | if ((result[0] != 0x90) || (result[1] != 0x00))
|
---|
213 | return 0;
|
---|
214 | cam_common_cmd2card(ins3a, sizeof(ins3a), result, sizeof(result), &result_size); //get cw's
|
---|
215 | log_debug("cwdump:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x.", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15], result[16],
|
---|
216 | result[17]);
|
---|
217 | if ((result[16] != 0x90) || (result[17] != 0x00))
|
---|
218 | return 0; //exit if response is not 90 00 //TODO: if response is 9027 ppv mode is possible!
|
---|
219 | memcpy(er->cw, result, 16);
|
---|
220 |
|
---|
221 | return 1;
|
---|
222 | }
|
---|
223 |
|
---|
224 | int cam_seca_process_emm(EMM_PACKET * ep)
|
---|
225 | {
|
---|
226 | static unsigned char ins40[] = { 0xc1, 0x40, 0x00, 0x00, 0x00 };
|
---|
227 | uchar result[260];
|
---|
228 | ushort result_size;
|
---|
229 | uchar ins40data[256];
|
---|
230 | uchar ins40_cmd[272];
|
---|
231 | int i;
|
---|
232 |
|
---|
233 | log_debug("EMM:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x.", ep->emm[0], ep->emm[1], ep->emm[2], ep->emm[3], ep->emm[4], ep->emm[5], ep->emm[6], ep->emm[7], ep->emm[8], ep->emm[9], ep->emm[10], ep->emm[11], ep->emm[12], ep->emm[13], ep->emm[14],
|
---|
234 | ep->emm[15], ep->emm[16], ep->emm[17], ep->emm[18], ep->emm[19], ep->emm[20], ep->emm[21], ep->emm[22], ep->emm[23], ep->emm[24], ep->emm[25], ep->emm[26]);
|
---|
235 | if (ep->emm[0] == 0x84) { //shared EMM
|
---|
236 | //to test if SA matches
|
---|
237 | //first find out prov id
|
---|
238 | // i = cam_seca_get_prov_index(ep->emm[3],ep->emm[4]);
|
---|
239 | i = cam_seca_get_prov_index((char *) ep->emm + 3);
|
---|
240 | if (i == -1)
|
---|
241 | return 0;
|
---|
242 | else //prov id found, now test for SA (only first 3 bytes, custom byte does not count)
|
---|
243 | if ((ep->emm[5] != reader[ridx].sa[i][0]) || (ep->emm[6] != reader[ridx].sa[i][1]) || (ep->emm[7] != reader[ridx].sa[i][2])) {
|
---|
244 | log_normal("EMM: Shared update did not match; EMM SA:%02X%02X%02X, Reader SA:%02X,%02X,%02X.", ep->emm[5], ep->emm[6], ep->emm[7], reader[ridx].sa[i][0], reader[ridx].sa[i][1], reader[ridx].sa[i][2]);
|
---|
245 | return 0;
|
---|
246 | } else {
|
---|
247 | log_normal("EMM: Shared update matched for EMM SA %02X%02X%02X.", ep->emm[5], ep->emm[6], ep->emm[7]);
|
---|
248 | ins40[3] = ep->emm[9];
|
---|
249 | ins40[4] = (ep->emm[1] & 0x0f) * 256 + ep->emm[2] - 0x07;
|
---|
250 | memcpy(ins40data, ep->emm + 10, 256 - 10);
|
---|
251 | }
|
---|
252 |
|
---|
253 | } //end shared EMM
|
---|
254 | else if (ep->emm[0] == 0x82) { //unique EMM
|
---|
255 | //first test if UA matches
|
---|
256 | if ((reader[ridx].hexserial[2] != ep->emm[3]) || (reader[ridx].hexserial[3] != ep->emm[4]) || (reader[ridx].hexserial[4] != ep->emm[5]) || (reader[ridx].hexserial[5] != ep->emm[6]) || (reader[ridx].hexserial[6] != ep->emm[7]) || (reader[ridx].hexserial[7] != ep->emm[8])) {
|
---|
257 | log_normal("EMM: Unique update did not match; EMM Serial:%02X%02X%02X%02X%02X%02X, Reader Serial:%02X%02X%02X%02X%02X%02X.", ep->emm[3], ep->emm[4], ep->emm[5], ep->emm[6], ep->emm[7], ep->emm[8], reader[ridx].hexserial[2], reader[ridx].hexserial[3], reader[ridx].hexserial[4],
|
---|
258 | reader[ridx].hexserial[5], reader[ridx].hexserial[6], reader[ridx].hexserial[7]);
|
---|
259 | return 0;
|
---|
260 | } else {
|
---|
261 | log_normal("EMM: Unique update matched EMM Serial:%02X%02X%02X%02X%02X.", ep->emm[3], ep->emm[4], ep->emm[5], ep->emm[6], ep->emm[7], ep->emm[8]);
|
---|
262 | //first find out prov id
|
---|
263 | // i = cam_seca_get_prov_index(ep->emm[9],ep->emm[10]);
|
---|
264 | i = cam_seca_get_prov_index((char *) ep->emm + 9);
|
---|
265 | if (i == -1)
|
---|
266 | return 0;
|
---|
267 | ins40[3] = ep->emm[12];
|
---|
268 | ins40[4] = (ep->emm[1] & 0x0f) * 256 + ep->emm[2] - 0x0A;
|
---|
269 | memcpy(ins40data, ep->emm + 13, 256 - 13);
|
---|
270 | }
|
---|
271 | } //end unique EMM
|
---|
272 | else
|
---|
273 | return 0; //geen 0x84 en geen 0x82
|
---|
274 |
|
---|
275 | ins40[2] = i;
|
---|
276 | // length = ((er->ecm[1]<<8 || er->ecm[2])&0x0fff);
|
---|
277 | log_debug("do_emm:ins40=%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x.", ins40[0], ins40[1], ins40[2], ins40[3], ins40[4], ins40data[0], ins40data[1], ins40data[2], ins40data[3], ins40data[4], ins40data[5], ins40data[6], ins40data[7], ins40data[8], ins40data[9]);
|
---|
278 | memcpy(ins40_cmd, ins40, 5);
|
---|
279 | memcpy(ins40_cmd + 5, ins40data, ins40[4]);
|
---|
280 | cam_common_cmd2card(ins40_cmd, ins40[4], result, sizeof(result), &result_size); //emm request
|
---|
281 | log_debug("emmdump:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x.", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15], result[16],
|
---|
282 | result[17]);
|
---|
283 | //TODO if ((result[16] != 0x90) || (result[17] != 0x00)) return 0;
|
---|
284 | // if ((result[16] != 0x90) || (result[17] != 0x19))
|
---|
285 | // seca_card_init(); //if return code = 90 19 then PPUA changed. //untested!!
|
---|
286 | // else
|
---|
287 | if (result[0] == 0x97) {
|
---|
288 | log_normal("EMM: Update not necessary.");
|
---|
289 | return 1; //Update not necessary
|
---|
290 | }
|
---|
291 | if ((result[0] == 0x90) && ((result[1] == 0x00) || (result[1] == 0x19))) {
|
---|
292 | if (cam_seca_set_provider_info(i) != 0) { //after successfull EMM, print new provider info
|
---|
293 | return 1;
|
---|
294 | }
|
---|
295 | }
|
---|
296 |
|
---|
297 | return 0;
|
---|
298 | }
|
---|