1 | #include "globals.h"
|
---|
2 | #ifdef READER_DRECAS
|
---|
3 | #include "cscrypt/des.h"
|
---|
4 | #include "reader-common.h"
|
---|
5 | #include "reader-dre-common.h"
|
---|
6 | #include "csctapi/icc_async.h"
|
---|
7 |
|
---|
8 | struct dre_data
|
---|
9 | {
|
---|
10 | uint8_t provider;
|
---|
11 | };
|
---|
12 |
|
---|
13 | struct stm_keys
|
---|
14 | {
|
---|
15 | uint8_t stmcmd34[64][0x30];
|
---|
16 | } stm_keys_t;
|
---|
17 |
|
---|
18 | uint8_t stm_curkey[2] = {0,0};
|
---|
19 | extern char cs_confdir[128];
|
---|
20 |
|
---|
21 | #define MSP_CMD_BYTE 0x59
|
---|
22 | #define STM_CMD_BYTE 0x74
|
---|
23 | #define MOD_CMD_BYTE 0xDB
|
---|
24 |
|
---|
25 | #define READ 0
|
---|
26 | #define WRITE 1
|
---|
27 |
|
---|
28 | static void stm_key_operaion(struct s_reader *reader, int operation)
|
---|
29 | {
|
---|
30 | FILE *file = NULL;
|
---|
31 | char stmkeyfile[256];
|
---|
32 | int i;
|
---|
33 |
|
---|
34 | if(reader->stmkeys == NULL)
|
---|
35 | {
|
---|
36 | snprintf(stmkeyfile,256,"%sstmkeys.bin",cs_confdir);
|
---|
37 | }
|
---|
38 | else
|
---|
39 | {
|
---|
40 | if(strchr(reader->stmkeys, '/') == NULL)
|
---|
41 | {
|
---|
42 | snprintf(stmkeyfile,256,"%s%s",cs_confdir, reader->stmkeys);
|
---|
43 | }
|
---|
44 | else
|
---|
45 | {
|
---|
46 | snprintf(stmkeyfile,256,"%s",reader->stmkeys);
|
---|
47 | }
|
---|
48 | }
|
---|
49 |
|
---|
50 | if((file = fopen(stmkeyfile, operation == READ ? "rb" : "wb")) == NULL)
|
---|
51 | {
|
---|
52 | cs_log("Error: can't' open stm key file (%s)", stmkeyfile);
|
---|
53 | return;
|
---|
54 | }
|
---|
55 |
|
---|
56 | if(operation == WRITE)
|
---|
57 | {
|
---|
58 | i = fwrite(&stm_keys_t, sizeof(stm_keys_t), 1, file);
|
---|
59 | }
|
---|
60 | else
|
---|
61 | {
|
---|
62 | i = fread(&stm_keys_t, sizeof(stm_keys_t), 1, file);
|
---|
63 | }
|
---|
64 |
|
---|
65 | fclose(file);
|
---|
66 |
|
---|
67 | if(!i) cs_log("Error read/write stm key file (%s)", stmkeyfile);
|
---|
68 | }
|
---|
69 |
|
---|
70 | static uint8_t xor(const uint8_t *cmd, int32_t cmdlen)
|
---|
71 | {
|
---|
72 | int32_t i;
|
---|
73 | uint8_t checksum = 0x00;
|
---|
74 | for(i = 0; i < cmdlen; i++)
|
---|
75 | { checksum ^= cmd[i]; }
|
---|
76 | return checksum;
|
---|
77 | }
|
---|
78 |
|
---|
79 | static int8_t isValidDCW(uint8_t *dw)
|
---|
80 | {
|
---|
81 | if (((dw[0] + dw[1] + dw[2]) & 0xFF) != dw[3])
|
---|
82 | {
|
---|
83 | return 0;
|
---|
84 | }
|
---|
85 | if (((dw[4] + dw[5] + dw[6]) & 0xFF) != dw[7])
|
---|
86 | {
|
---|
87 | return 0;
|
---|
88 | }
|
---|
89 | if (((dw[8] + dw[9] + dw[10]) & 0xFF) != dw[11])
|
---|
90 | {
|
---|
91 | return 0;
|
---|
92 | }
|
---|
93 | if (((dw[12] + dw[13] + dw[14]) & 0xFF) != dw[15])
|
---|
94 | {
|
---|
95 | return 0;
|
---|
96 | }
|
---|
97 | return 1;
|
---|
98 | }
|
---|
99 |
|
---|
100 | static int32_t drecas_send_cmd(struct s_reader *reader, uint8_t *cmd, int32_t cmdlen, uint8_t *cta_res, uint16_t *p_cta_lr, uint8_t dest)
|
---|
101 | {
|
---|
102 | // any command starts with this,
|
---|
103 | // last byte is nr of bytes of the command that will be sent
|
---|
104 | uint8_t startcmd[3] = { 0xDB, 0x00, 0x00 };
|
---|
105 |
|
---|
106 | uint8_t command[260];
|
---|
107 | uint8_t checksum;
|
---|
108 | char tmp[256];
|
---|
109 |
|
---|
110 | startcmd[1] = cmdlen + 2; // command + length + len + checksum bytes
|
---|
111 | startcmd[2] = dest;
|
---|
112 |
|
---|
113 | memcpy(command, startcmd, 3);
|
---|
114 | memcpy(command + 3, cmd, cmdlen);
|
---|
115 | cmdlen += 3;
|
---|
116 | checksum = xor(command+2, cmdlen-2);
|
---|
117 | command[cmdlen++] = checksum;
|
---|
118 |
|
---|
119 | rdr_log_dbg(reader, D_READER, "write to module: %s", cs_hexdump(0, command, cmdlen, tmp, sizeof(tmp)));
|
---|
120 |
|
---|
121 | ICC_Async_Transmit(reader, (uint32_t) cmdlen, 0, command, 0, 200);
|
---|
122 | ICC_Async_Receive(reader, 2, cta_res, 50, 3000000);
|
---|
123 |
|
---|
124 | ICC_Async_Receive(reader, cta_res[1], cta_res+2, 50, 3000000);
|
---|
125 | *p_cta_lr = cta_res[1] + 2;
|
---|
126 |
|
---|
127 | rdr_log_dbg(reader, D_READER, "answer from module: %s", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
128 |
|
---|
129 | checksum = xor(cta_res + 2, *p_cta_lr - 3);
|
---|
130 |
|
---|
131 | if(cta_res[*p_cta_lr - 1] != checksum)
|
---|
132 | {
|
---|
133 | rdr_log(reader, "checksum does not match, expected %02x received %02x:%s", checksum,
|
---|
134 | cta_res[*p_cta_lr - 1], cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
135 | return ERROR; // error
|
---|
136 | }
|
---|
137 |
|
---|
138 | return OK;
|
---|
139 | }
|
---|
140 |
|
---|
141 | static int32_t drecas_MSP_command(struct s_reader *reader, const uint8_t *cmd, int32_t cmdlen, uint8_t *cta_res, uint16_t *p_cta_lr)
|
---|
142 | {
|
---|
143 | // attention: inputcommand will be changed!!!
|
---|
144 | // answer will be in cta_res, length cta_lr ; returning 1 = no error, return ERROR = err
|
---|
145 |
|
---|
146 | uint8_t startcmd[] = { 0x80, 0xFF, 0x10, 0x01, 0x05 }; // any command starts with this,
|
---|
147 | uint8_t command[256];
|
---|
148 | uint8_t checksum;
|
---|
149 | char tmp[256];
|
---|
150 |
|
---|
151 | startcmd[4] = cmdlen + 3; // command + length + len + checksum bytes
|
---|
152 | memcpy(command, startcmd, 5);
|
---|
153 | command[5] = MSP_CMD_BYTE; // type
|
---|
154 | command[6] = cmdlen + 1; // len = command + 1 checksum byte
|
---|
155 | memcpy(command + 7, cmd, cmdlen);
|
---|
156 |
|
---|
157 | checksum = ~xor(cmd, cmdlen);
|
---|
158 |
|
---|
159 | cmdlen += 7;
|
---|
160 | command[cmdlen++] = checksum;
|
---|
161 |
|
---|
162 | if(drecas_send_cmd(reader, command, cmdlen, cta_res, p_cta_lr, 1) != OK) return ERROR;
|
---|
163 |
|
---|
164 | if(cta_res[4] != MSP_CMD_BYTE) return ERROR;
|
---|
165 |
|
---|
166 | if((cta_res[5] == 0x03) && (cta_res[6] == 0xe2))
|
---|
167 | {
|
---|
168 | switch(cta_res[7])
|
---|
169 | {
|
---|
170 | case 0xe1:
|
---|
171 | rdr_log(reader, "checksum error: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
172 | break;
|
---|
173 |
|
---|
174 | case 0xe2:
|
---|
175 | rdr_log(reader, "wrong cmd len: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
176 | break;
|
---|
177 |
|
---|
178 | case 0xe3:
|
---|
179 | rdr_log(reader, "illegal command: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
180 | break;
|
---|
181 |
|
---|
182 | case 0xe4:
|
---|
183 | rdr_log(reader, "wrong adress type: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
184 | break;
|
---|
185 |
|
---|
186 | case 0xe5:
|
---|
187 | rdr_log(reader, "wrong CMD param: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
188 | break;
|
---|
189 |
|
---|
190 | case 0xe6:
|
---|
191 | rdr_log(reader, "wrong UA: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
192 | break;
|
---|
193 |
|
---|
194 | case 0xe7:
|
---|
195 | rdr_log(reader, "wrong group: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
196 | break;
|
---|
197 |
|
---|
198 | case 0xe8:
|
---|
199 | rdr_log(reader, "wrong key num: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
200 | break;
|
---|
201 |
|
---|
202 | case 0xeb:
|
---|
203 | rdr_log(reader, "No key or subscribe : %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
204 | break;
|
---|
205 |
|
---|
206 | case 0xec:
|
---|
207 | rdr_log(reader, "wrong signature: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
208 | break;
|
---|
209 |
|
---|
210 | case 0xed:
|
---|
211 | rdr_log(reader, "wrong provider: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
212 | break;
|
---|
213 |
|
---|
214 | case 0xef:
|
---|
215 | rdr_log(reader, "wrong GEO code: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
216 | break;
|
---|
217 |
|
---|
218 | default:
|
---|
219 | rdr_log_dbg(reader, D_READER, "unknown error: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
220 | break;
|
---|
221 | }
|
---|
222 | return ERROR; // error
|
---|
223 | }
|
---|
224 |
|
---|
225 | int32_t length_excl_leader = *p_cta_lr;
|
---|
226 |
|
---|
227 | checksum = ~xor(cta_res + 6, length_excl_leader - 8);
|
---|
228 |
|
---|
229 | if(cta_res[length_excl_leader - 2] != checksum)
|
---|
230 | {
|
---|
231 | rdr_log(reader, "checksum does not match, expected %02x received %02x:%s", checksum,
|
---|
232 | cta_res[length_excl_leader - 2], cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
233 | return ERROR; // error
|
---|
234 | }
|
---|
235 |
|
---|
236 | return OK;
|
---|
237 | }
|
---|
238 |
|
---|
239 | #define drecas_MSP_script_nb(cmd, len) \
|
---|
240 | drecas_MSP_command(reader, cmd, len, cta_res, &cta_lr); \
|
---|
241 |
|
---|
242 | #define drecas_MSP_script(cmd, len) \
|
---|
243 | { \
|
---|
244 | drecas_MSP_script_nb(cmd, len) \
|
---|
245 | }
|
---|
246 |
|
---|
247 | #define drecas_MSP_cmd_nb(cmd) \
|
---|
248 | drecas_MSP_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr); \
|
---|
249 |
|
---|
250 | #define drecas_MSP_cmd(cmd) \
|
---|
251 | { \
|
---|
252 | drecas_MSP_cmd_nb(cmd) \
|
---|
253 | }
|
---|
254 |
|
---|
255 | static int32_t drecas_STM_command(struct s_reader *reader, const uint8_t *cmd, int32_t cmdlen, uint8_t *cta_res, uint16_t *p_cta_lr)
|
---|
256 | {
|
---|
257 | // attention: inputcommand will be changed!!!!
|
---|
258 | //answer will be in cta_res, length cta_lr ; returning 1 = no error, return ERROR = err
|
---|
259 |
|
---|
260 | uint8_t command[256];
|
---|
261 | uint8_t checksum;
|
---|
262 | char tmp[256];
|
---|
263 |
|
---|
264 | command[0] = 0xC2;
|
---|
265 | command[1] = STM_CMD_BYTE; // type
|
---|
266 | command[2] = cmdlen + 1; // len = command + 1 checksum byte
|
---|
267 | memcpy(command + 3, cmd, cmdlen);
|
---|
268 |
|
---|
269 | checksum = ~xor(cmd, cmdlen);
|
---|
270 |
|
---|
271 | cmdlen += 3;
|
---|
272 | command[cmdlen++] = checksum;
|
---|
273 |
|
---|
274 | if(drecas_send_cmd(reader, command, cmdlen, cta_res, p_cta_lr, 0) != OK) return ERROR;
|
---|
275 |
|
---|
276 | if(cta_res[4] != STM_CMD_BYTE) return ERROR;
|
---|
277 |
|
---|
278 | if((cta_res[5] == 0x03) && (cta_res[6] == 0xe2))
|
---|
279 | {
|
---|
280 | switch(cta_res[7])
|
---|
281 | {
|
---|
282 | case 0xe1:
|
---|
283 | rdr_log(reader, "checksum error: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
284 | break;
|
---|
285 |
|
---|
286 | case 0xe2:
|
---|
287 | rdr_log(reader, "wrong cmd len: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
288 | break;
|
---|
289 |
|
---|
290 | case 0xe3:
|
---|
291 | rdr_log(reader, "illegal command: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
292 | break;
|
---|
293 |
|
---|
294 | case 0xe4:
|
---|
295 | rdr_log(reader, "wrong adress type: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
296 | break;
|
---|
297 |
|
---|
298 | case 0xe5:
|
---|
299 | rdr_log(reader, "wrong CMD param: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
300 | break;
|
---|
301 |
|
---|
302 | case 0xe6:
|
---|
303 | rdr_log(reader, "wrong UA: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
304 | break;
|
---|
305 |
|
---|
306 | case 0xe7:
|
---|
307 | rdr_log(reader, "wrong group: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
308 | break;
|
---|
309 |
|
---|
310 | case 0xe8:
|
---|
311 | rdr_log(reader, "wrong key num: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
312 | break;
|
---|
313 |
|
---|
314 | case 0xeb:
|
---|
315 | rdr_log(reader, "No key or subscribe : %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
316 | break;
|
---|
317 |
|
---|
318 | case 0xec:
|
---|
319 | rdr_log(reader, "wrong signature: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
320 | break;
|
---|
321 |
|
---|
322 | case 0xed:
|
---|
323 | rdr_log(reader, "wrong provider: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
324 | break;
|
---|
325 |
|
---|
326 | case 0xef:
|
---|
327 | rdr_log(reader, "wrong GEO code: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
328 | break;
|
---|
329 |
|
---|
330 | default:
|
---|
331 | rdr_log_dbg(reader, D_READER, "unknown error: %s.", cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
332 | break;
|
---|
333 | }
|
---|
334 | return ERROR; // error
|
---|
335 | }
|
---|
336 |
|
---|
337 | int32_t length_excl_leader = *p_cta_lr;
|
---|
338 |
|
---|
339 | checksum = ~xor(cta_res + 6, length_excl_leader - 8);
|
---|
340 |
|
---|
341 | if(cta_res[length_excl_leader - 2] != checksum)
|
---|
342 | {
|
---|
343 | rdr_log(reader, "checksum does not match, expected %02x received %02x:%s", checksum,
|
---|
344 | cta_res[length_excl_leader - 2], cs_hexdump(0, cta_res, *p_cta_lr, tmp, sizeof(tmp)));
|
---|
345 | return ERROR; // error
|
---|
346 | }
|
---|
347 |
|
---|
348 | return OK;
|
---|
349 | }
|
---|
350 |
|
---|
351 | #define drecas_STM_script_nb(cmd, len) \
|
---|
352 | drecas_STM_command(reader, cmd, len, cta_res, &cta_lr); \
|
---|
353 |
|
---|
354 | #define drecas_STM_script(cmd, len) \
|
---|
355 | { \
|
---|
356 | drecas_STM_script_nb(cmd, len) \
|
---|
357 | }
|
---|
358 |
|
---|
359 | #define drecas_STM_cmd_nb(cmd) \
|
---|
360 | drecas_STM_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr); \
|
---|
361 |
|
---|
362 | #define drecas_STM_cmd(cmd) \
|
---|
363 | { \
|
---|
364 | drecas_STM_cmd_nb(cmd) \
|
---|
365 | }
|
---|
366 |
|
---|
367 | static int32_t drecas_set_provider_info(struct s_reader *reader)
|
---|
368 | {
|
---|
369 | def_resp;
|
---|
370 | int32_t i;
|
---|
371 | uint8_t subscr[] = { 0x59, 0x14 }; // subscriptions
|
---|
372 | uint8_t dates[] = { 0x5b, 0x00, 0x14 }; // validity dates
|
---|
373 | struct dre_data *csystem_data = reader->csystem_data;
|
---|
374 | subscr[1] = csystem_data->provider;
|
---|
375 |
|
---|
376 | cs_clear_entitlement(reader);
|
---|
377 |
|
---|
378 | if(({drecas_MSP_cmd_nb(subscr)})) // ask subscription packages, returns error on 0x11 card
|
---|
379 | {
|
---|
380 | uint8_t pbm[32];
|
---|
381 | char tmp_dbg[65];
|
---|
382 | memcpy(pbm, cta_res + 7, 32);
|
---|
383 | rdr_log_dbg(reader, D_READER, "pbm: %s", cs_hexdump(0, pbm, 32, tmp_dbg, sizeof(tmp_dbg)));
|
---|
384 |
|
---|
385 | for(i = 0; i < 32; i++)
|
---|
386 | {
|
---|
387 | if(pbm[i] != 0xff)
|
---|
388 | {
|
---|
389 | dates[1] = i;
|
---|
390 | dates[2] = csystem_data->provider;
|
---|
391 | drecas_MSP_cmd(dates); // ask for validity dates
|
---|
392 |
|
---|
393 | time_t start;
|
---|
394 | time_t end;
|
---|
395 | start = (cta_res[7] << 24) | (cta_res[8] << 16) | (cta_res[9] << 8) | cta_res[10];
|
---|
396 | end = (cta_res[11] << 24) | (cta_res[12] << 16) | (cta_res[13] << 8) | cta_res[14];
|
---|
397 |
|
---|
398 | struct tm temp;
|
---|
399 |
|
---|
400 | localtime_r(&start, &temp);
|
---|
401 | int32_t startyear = temp.tm_year + 1900;
|
---|
402 | int32_t startmonth = temp.tm_mon + 1;
|
---|
403 | int32_t startday = temp.tm_mday;
|
---|
404 | localtime_r(&end, &temp);
|
---|
405 | int32_t endyear = temp.tm_year + 1900;
|
---|
406 | int32_t endmonth = temp.tm_mon + 1;
|
---|
407 | int32_t endday = temp.tm_mday;
|
---|
408 | rdr_log(reader, "active package %i valid from %04i/%02i/%02i to %04i/%02i/%02i",
|
---|
409 | i, startyear, startmonth, startday, endyear, endmonth, endday);
|
---|
410 | cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), 0, i, start, end, 5, 1);
|
---|
411 | }
|
---|
412 | }
|
---|
413 | }
|
---|
414 |
|
---|
415 | return OK;
|
---|
416 | }
|
---|
417 |
|
---|
418 | static int32_t drecas_card_init(struct s_reader *reader, ATR *newatr)
|
---|
419 | {
|
---|
420 | get_atr;
|
---|
421 | def_resp;
|
---|
422 | uint8_t ua[] = { 0x43, 0x15 }; // get serial number (UA)
|
---|
423 | uint8_t providers[] = { 0x49, 0x15 }; // get providers
|
---|
424 | int32_t i;
|
---|
425 | char *card;
|
---|
426 | char tmp[9];
|
---|
427 | uint8_t module_atr[] = { 0xDB, 0x0B, 0x08, 0xA3, 0x3B, 0x15, 0x11, 0x12, 0x01, 0x01, 0x11, 0x07, 0x90 };
|
---|
428 |
|
---|
429 | if(memcmp(atr, module_atr, sizeof(module_atr)) != 0)
|
---|
430 | { return ERROR; }
|
---|
431 |
|
---|
432 | if(!cs_malloc(&reader->csystem_data, sizeof(struct dre_data)))
|
---|
433 | { return ERROR; }
|
---|
434 | struct dre_data *csystem_data = reader->csystem_data;
|
---|
435 |
|
---|
436 | csystem_data->provider = atr[10];
|
---|
437 | uint8_t checksum = xor(atr + 5, 6);
|
---|
438 |
|
---|
439 | if(checksum != atr[11])
|
---|
440 | { rdr_log(reader, "warning: expected ATR checksum %02x, smartcard reports %02x", checksum, atr[7]); }
|
---|
441 |
|
---|
442 | switch(atr[10])
|
---|
443 | {
|
---|
444 | case 0x11:
|
---|
445 | card = "Tricolor Centr DRE2";
|
---|
446 | reader->caid = 0x4ae1;
|
---|
447 | break; // 59 type card = MSP (74 type = ATMEL)
|
---|
448 |
|
---|
449 | case 0x14:
|
---|
450 | card = "Tricolor Syberia DRE2";
|
---|
451 | reader->caid = 0x4ae1;
|
---|
452 | break; // 59 type card
|
---|
453 |
|
---|
454 | default:
|
---|
455 | return ERROR;
|
---|
456 | }
|
---|
457 |
|
---|
458 | memset(reader->prid, 0x00, 8);
|
---|
459 |
|
---|
460 | reader->prid[0][3] = csystem_data->provider;
|
---|
461 |
|
---|
462 | uint8_t cmd54[] = { 0x54, 0x14 }; // geocode
|
---|
463 | cmd54[1] = csystem_data->provider;
|
---|
464 | uint8_t geocode = 0;
|
---|
465 |
|
---|
466 | if(({drecas_MSP_cmd_nb(cmd54)})) // error would not be fatal, like on 0x11 cards
|
---|
467 | { geocode = cta_res[7]; }
|
---|
468 |
|
---|
469 | providers[1] = csystem_data->provider;
|
---|
470 |
|
---|
471 | if(!({drecas_MSP_cmd_nb(providers)}))
|
---|
472 | { return ERROR; } // fatal error
|
---|
473 |
|
---|
474 | if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
|
---|
475 | { return ERROR; }
|
---|
476 |
|
---|
477 | uint8_t provname[128];
|
---|
478 |
|
---|
479 | for(i = 0; ((i < cta_res[6] - 6) && (i < 128)); i++)
|
---|
480 | {
|
---|
481 | provname[i] = cta_res[10 + i];
|
---|
482 | if(provname[i] == 0x00)
|
---|
483 | { break; }
|
---|
484 | }
|
---|
485 |
|
---|
486 | int32_t major_version = cta_res[7];
|
---|
487 | int32_t minor_version = cta_res[8];
|
---|
488 |
|
---|
489 | ua[1] = csystem_data->provider;
|
---|
490 | drecas_MSP_cmd(ua); // error would not be fatal
|
---|
491 |
|
---|
492 | // discard first and last byte, last byte is always checksum, first is answer code
|
---|
493 | int32_t hexlength = cta_res[5] - 2;
|
---|
494 |
|
---|
495 | if(reader->force_ua)
|
---|
496 | {
|
---|
497 | rdr_log(reader, "WARNING!!!! used UA from force_ua %08X", reader->force_ua);
|
---|
498 | memcpy(cta_res + 7, &reader->force_ua, 8);
|
---|
499 | }
|
---|
500 |
|
---|
501 | reader->hexserial[0] = 0;
|
---|
502 | reader->hexserial[1] = 0;
|
---|
503 | memcpy(reader->hexserial + 2, cta_res + 7, hexlength);
|
---|
504 |
|
---|
505 | int32_t low_dre_id, dre_chksum;
|
---|
506 | uint8_t buf[32];
|
---|
507 |
|
---|
508 | low_dre_id = ((cta_res[8] << 16) | (cta_res[9] << 8) | cta_res[10]) - 48608;
|
---|
509 | dre_chksum = 0;
|
---|
510 | snprintf((char *)buf, sizeof(buf), "%i%i%08i", csystem_data->provider - 16, major_version + 1, low_dre_id);
|
---|
511 |
|
---|
512 | for(i = 0; i < 32; i++)
|
---|
513 | {
|
---|
514 | if(buf[i] == 0x00)
|
---|
515 | { break; }
|
---|
516 | dre_chksum += buf[i] - 48;
|
---|
517 | }
|
---|
518 |
|
---|
519 | rdr_log(reader, "type: DRE Crypt, caid: %04X, serial: {%s}, dre id: %i%i%i%08i, geocode %i, card: %s v%i.%i",
|
---|
520 | reader->caid, cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)), dre_chksum, csystem_data->provider - 16,
|
---|
521 | major_version + 1, low_dre_id, geocode, card, major_version, minor_version);
|
---|
522 |
|
---|
523 | rdr_log(reader, "Provider name:%s.", provname);
|
---|
524 |
|
---|
525 |
|
---|
526 | memset(reader->sa, 0, sizeof(reader->sa));
|
---|
527 | // copy first byte of unique address also in shared address, because we don't know what it is...
|
---|
528 | memcpy(reader->sa[0], reader->hexserial + 2, 1);
|
---|
529 |
|
---|
530 | rdr_log_sensitive(reader, "SA = %02X%02X%02X%02X, UA = {%s}", reader->sa[0][0], reader->sa[0][1], reader->sa[0][2],
|
---|
531 | reader->sa[0][3], cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)));
|
---|
532 |
|
---|
533 | reader->nprov = 1;
|
---|
534 |
|
---|
535 | // exec user script, wicardd format
|
---|
536 | if(reader->userscript != NULL)
|
---|
537 | {
|
---|
538 | uint8_t *usercmd = NULL;
|
---|
539 | int cmd_len;
|
---|
540 | int n;
|
---|
541 | char *tempbuf = malloc(2048);
|
---|
542 | trim2(reader->userscript);
|
---|
543 | FILE *pFile = fopen(reader->userscript, "rt");
|
---|
544 |
|
---|
545 | if(pFile != NULL)
|
---|
546 | {
|
---|
547 | do
|
---|
548 | {
|
---|
549 | tempbuf[0] = '\0';
|
---|
550 | if(usercmd != NULL) NULLFREE(usercmd);
|
---|
551 |
|
---|
552 | if(fgets(tempbuf, 2048, pFile) == NULL) continue;
|
---|
553 |
|
---|
554 | if(cs_strlen(tempbuf) < 10) continue;
|
---|
555 |
|
---|
556 | trim2(tempbuf);
|
---|
557 |
|
---|
558 | if((tempbuf[0] != '5' && tempbuf[1] != '9') && (tempbuf[0] != '7' && tempbuf[1] != '4')) continue;
|
---|
559 |
|
---|
560 | strtoupper(tempbuf);
|
---|
561 |
|
---|
562 | cmd_len = cs_strlen(tempbuf) / 2 - 3;
|
---|
563 | usercmd = malloc(cmd_len);
|
---|
564 |
|
---|
565 | for(i = 0, n = 4; i < cmd_len; i++, n += 2)
|
---|
566 | {
|
---|
567 | usercmd[i] = ((tempbuf[n] - (tempbuf[n] > 0x39 ? 0x37 : 0x30)) << 4) + ((tempbuf[n + 1] - (tempbuf[n + 1] > 0x39 ? 0x37 : 0x30)) & 0xF);
|
---|
568 | }
|
---|
569 |
|
---|
570 | if(tempbuf[0] != '7' && tempbuf[1] != '4')
|
---|
571 | {
|
---|
572 | rdr_log(reader, "Script %s", ({drecas_MSP_script_nb(usercmd, cmd_len)}) ? "done" : "error");
|
---|
573 | }
|
---|
574 | else
|
---|
575 | {
|
---|
576 | rdr_log(reader, "Script %s", ({drecas_STM_script_nb(usercmd, cmd_len)}) ? "done" : "error");
|
---|
577 | }
|
---|
578 | }
|
---|
579 | while(!feof(pFile));
|
---|
580 | }
|
---|
581 | else
|
---|
582 | {
|
---|
583 | rdr_log(reader, "Can't open script file (%s)", reader->userscript);
|
---|
584 | }
|
---|
585 |
|
---|
586 | if(usercmd != NULL) free(usercmd);
|
---|
587 | if(tempbuf != NULL) free(tempbuf);
|
---|
588 | }
|
---|
589 |
|
---|
590 | if(csystem_data->provider == 0x11)
|
---|
591 | {
|
---|
592 | memset(reader->prid[1], 0x00, 8);
|
---|
593 | reader->prid[1][3] = 0xFE;
|
---|
594 | reader->nprov = 2;
|
---|
595 | }
|
---|
596 |
|
---|
597 | if(!drecas_set_provider_info(reader))
|
---|
598 | { return ERROR; } // fatal error
|
---|
599 |
|
---|
600 | stm_key_operaion(reader, READ);
|
---|
601 |
|
---|
602 | rdr_log(reader, "ready for requests");
|
---|
603 | return OK;
|
---|
604 | }
|
---|
605 |
|
---|
606 | static void DREover(struct s_reader *reader, const uint8_t *ECMdata, uint8_t *DW)
|
---|
607 | {
|
---|
608 | uint32_t key_schedule[32];
|
---|
609 |
|
---|
610 | if(reader->des_key_length < 128)
|
---|
611 | {
|
---|
612 | rdr_log(reader, "error: deskey is missing or too short");
|
---|
613 | return;
|
---|
614 | }
|
---|
615 |
|
---|
616 | if(ECMdata[2] >= (43 + 4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B)
|
---|
617 | {
|
---|
618 | des_set_key(&reader->des_key[(ECMdata[42] & 0x0F) * 8], key_schedule);
|
---|
619 |
|
---|
620 | des(DW, key_schedule, 0); // even DW post-process
|
---|
621 | des(DW + 8, key_schedule, 0); // odd DW post-process
|
---|
622 | };
|
---|
623 | };
|
---|
624 |
|
---|
625 | static int32_t drecas_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
|
---|
626 | {
|
---|
627 | def_resp;
|
---|
628 | uint16_t overcryptId;
|
---|
629 | uint8_t tmp[16];
|
---|
630 | char tmp_dbg[256];
|
---|
631 | struct dre_data *csystem_data = reader->csystem_data;
|
---|
632 |
|
---|
633 | if(reader->caid == 0x4ae1)
|
---|
634 | {
|
---|
635 | if(csystem_data->provider == 0x11 || csystem_data->provider == 0x14)
|
---|
636 | {
|
---|
637 | uint8_t ecmcmd51[] = { 0x51, 0x02, 0x56, 0x05, 0x00, 0x4A, 0xE3, // fixed header?
|
---|
638 | 0x9C, 0xDA, // first three nibbles count up, fourth nibble counts down; all ECMs sent twice
|
---|
639 | 0xC1, 0x71, 0x21, 0x06, 0xF0, 0x14, 0xA7, 0x0E, // next key?
|
---|
640 | 0x89, 0xDA, 0xC9, 0xD7, 0xFD, 0xB9, 0x06, 0xFD, // current key?
|
---|
641 | 0xD5, 0x1E, 0x2A, 0xA3, 0xB5, 0xA0, 0x82, 0x11, // key or signature?
|
---|
642 | 0x14 }; // provider
|
---|
643 |
|
---|
644 | memcpy(ecmcmd51 + 1, er->ecm + 5, 0x21);
|
---|
645 | rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 5, tmp_dbg, sizeof(tmp_dbg)));
|
---|
646 | rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 37, 4, tmp_dbg, sizeof(tmp_dbg)));
|
---|
647 |
|
---|
648 | rdr_log_dbg(reader, D_READER, "ECM: %s",cs_hexdump(0, er->ecm, er->ecm[2] + 3, tmp_dbg, sizeof(tmp_dbg)));
|
---|
649 |
|
---|
650 | ecmcmd51[33] = csystem_data->provider; // no part of sig
|
---|
651 |
|
---|
652 | if(({drecas_MSP_cmd_nb(ecmcmd51)})) // ecm request
|
---|
653 | {
|
---|
654 | if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
|
---|
655 | { return ERROR; } // exit if response is not 90 00
|
---|
656 |
|
---|
657 | if(er->ecm[3] == 0x01)
|
---|
658 | {
|
---|
659 | uint8_t ecmcmd33[18] = { 0x33, 0x1F,
|
---|
660 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
661 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
---|
662 |
|
---|
663 | int i;
|
---|
664 | for(i = 0; i < 16; i++)
|
---|
665 | {
|
---|
666 | ecmcmd33[i + 2] = cta_res[7 + (i ^ 3)];
|
---|
667 | }
|
---|
668 |
|
---|
669 | if(er->ecm[5] != stm_curkey[0] || er->ecm[6] != stm_curkey[1])
|
---|
670 | {
|
---|
671 | uint8_t blank[0x30];
|
---|
672 | memset(blank, 0, 0x30);
|
---|
673 |
|
---|
674 | if(memcmp(blank, stm_keys_t.stmcmd34[er->ecm[5] + (er->ecm[6] == 0x3B ? 0 : 32)], 0x30) == 0)
|
---|
675 | {
|
---|
676 | rdr_log_dbg(reader, D_READER, "STM key not found");
|
---|
677 | return ERROR;
|
---|
678 | }
|
---|
679 |
|
---|
680 | if(!({drecas_STM_cmd_nb(stm_keys_t.stmcmd34[er->ecm[5] + (er->ecm[6] == 0x3B ? 0 : 32)])}))
|
---|
681 | {
|
---|
682 | rdr_log_dbg(reader, D_READER, "Error STM set key: %s",cs_hexdump(0, cta_res, cta_lr, tmp_dbg, sizeof(tmp_dbg)));
|
---|
683 | return ERROR;
|
---|
684 | }
|
---|
685 |
|
---|
686 | if((cta_res[cta_lr - 4] != 0x02) || (cta_res[cta_lr - 3] != 0xA2))
|
---|
687 | {
|
---|
688 | rdr_log_dbg(reader, D_READER, "Error STM set key: %s",cs_hexdump(0, cta_res, cta_lr, tmp_dbg, sizeof(tmp_dbg)));
|
---|
689 | return ERROR;
|
---|
690 | }
|
---|
691 | }
|
---|
692 |
|
---|
693 | stm_curkey[0] = er->ecm[5];
|
---|
694 | stm_curkey[1] = er->ecm[6];
|
---|
695 |
|
---|
696 | if(!({drecas_STM_cmd_nb(ecmcmd33)}))
|
---|
697 | { return ERROR; }
|
---|
698 |
|
---|
699 | if(cta_res[1] != 0x17 || cta_res[6] != 0xD2)
|
---|
700 | { return ERROR; }
|
---|
701 |
|
---|
702 | memcpy(tmp, &cta_res[7], 16);
|
---|
703 |
|
---|
704 | for(i = 0; i < 16; i++)
|
---|
705 | {
|
---|
706 | cta_res[i + 7] = tmp[i ^ 3];
|
---|
707 | }
|
---|
708 | }
|
---|
709 |
|
---|
710 | if(er->ecm[2] >= 46 && er->ecm[43] == 1 && csystem_data->provider == 0x11)
|
---|
711 | {
|
---|
712 | memcpy(&tmp[0], &cta_res[15], 8);
|
---|
713 | memcpy(&tmp[8], &cta_res[7], 8);
|
---|
714 |
|
---|
715 | overcryptId = b2i(2, &er->ecm[44]);
|
---|
716 |
|
---|
717 | rdr_log_dbg(reader, D_READER, "ICG ID: %04X", overcryptId);
|
---|
718 |
|
---|
719 | Drecrypt2OverCW(overcryptId,tmp);
|
---|
720 |
|
---|
721 | if(isValidDCW(tmp))
|
---|
722 | {
|
---|
723 | memcpy(ea->cw, tmp, 16);
|
---|
724 | return OK;
|
---|
725 | }
|
---|
726 | return ERROR;
|
---|
727 | }
|
---|
728 |
|
---|
729 | DREover(reader, er->ecm, cta_res + 7);
|
---|
730 |
|
---|
731 | if(isValidDCW(cta_res + 7))
|
---|
732 | {
|
---|
733 | memcpy(ea->cw, cta_res + 15, 8);
|
---|
734 | memcpy(ea->cw + 8, cta_res + 7, 8);
|
---|
735 | return OK;
|
---|
736 | }
|
---|
737 | }
|
---|
738 | }
|
---|
739 | }
|
---|
740 | return ERROR;
|
---|
741 | }
|
---|
742 |
|
---|
743 | static int32_t drecas_do_emm(struct s_reader *reader, EMM_PACKET *ep)
|
---|
744 | {
|
---|
745 | def_resp;
|
---|
746 | struct dre_data *csystem_data = reader->csystem_data;
|
---|
747 |
|
---|
748 | if(reader->caid == 0x4ae1)
|
---|
749 | {
|
---|
750 | if(reader->caid != b2i(2, ep->caid)) return ERROR;
|
---|
751 |
|
---|
752 | if(ep->type == UNIQUE && ep->emm[39] == 0x3d)
|
---|
753 | {
|
---|
754 | /* For new package activation. */
|
---|
755 | uint8_t emmcmd58[26];
|
---|
756 | emmcmd58[0] = 0x58;
|
---|
757 | memcpy(&emmcmd58[1], &ep->emm[40], 24);
|
---|
758 | emmcmd58[25] = csystem_data->provider;
|
---|
759 |
|
---|
760 | if(({drecas_MSP_cmd_nb(emmcmd58)}))
|
---|
761 | if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
|
---|
762 | { return ERROR; }
|
---|
763 | }
|
---|
764 | else if(ep->emm[0] == 0x86 && ep->emm[4] == 0x02 /*&& csystem_data->provider != 0x11*/)
|
---|
765 | {
|
---|
766 | uint8_t emmcmd52[0x3a];
|
---|
767 | emmcmd52[0] = 0x52;
|
---|
768 | int32_t i;
|
---|
769 |
|
---|
770 | for(i = 0; i < 2; i++)
|
---|
771 | {
|
---|
772 | memcpy(emmcmd52 + 1, ep->emm + 5 + 32 + i * 56, 56);
|
---|
773 |
|
---|
774 | // check for shared address
|
---|
775 | if(ep->emm[3] != reader->sa[0][0])
|
---|
776 | { return OK; } // ignore, wrong address
|
---|
777 |
|
---|
778 | emmcmd52[0x39] = csystem_data->provider;
|
---|
779 |
|
---|
780 | if(({drecas_MSP_cmd_nb(emmcmd52)}))
|
---|
781 | if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
|
---|
782 | { return ERROR; } // exit if response is not 90 00
|
---|
783 | }
|
---|
784 | }
|
---|
785 | else if(ep->emm[0] == 0x86 && ep->emm[4] == 0x4D && csystem_data->provider == 0x11)
|
---|
786 | {
|
---|
787 | uint8_t emmcmd52[0x3a];
|
---|
788 | emmcmd52[0] = 0x52;
|
---|
789 | emmcmd52[1] = 0x01;
|
---|
790 | emmcmd52[2] = ep->emm[5];
|
---|
791 | emmcmd52[3] = 0x01;
|
---|
792 | emmcmd52[4] = ep->emm[3];
|
---|
793 | emmcmd52[5] = 0;
|
---|
794 | emmcmd52[6] = 0;
|
---|
795 | emmcmd52[7] = 0;
|
---|
796 | emmcmd52[9] = 0x01;
|
---|
797 | emmcmd52[10] = 0x01;
|
---|
798 | emmcmd52[11] = 0;
|
---|
799 | memcpy(emmcmd52 + 13, ep->emm + 0x5C, 4);
|
---|
800 | int32_t i;
|
---|
801 |
|
---|
802 | for(i = 0; i < 2; i++)
|
---|
803 | {
|
---|
804 | emmcmd52[8] = ep->emm[0x61 + i * 0x29];
|
---|
805 |
|
---|
806 | if(i == 0) emmcmd52[12] = ep->emm[0x60] == 0x56 ? 0x56 : 0x3B;
|
---|
807 | else emmcmd52[12] = ep->emm[0x60] == 0x56 ? 0x3B : 0x56;
|
---|
808 |
|
---|
809 | memcpy(emmcmd52 + 0x11, ep->emm + 0x62 + i * 0x29, 40);
|
---|
810 |
|
---|
811 | // check for shared address
|
---|
812 | if(ep->emm[3] != reader->sa[0][0])
|
---|
813 | { return OK; } // ignore, wrong address
|
---|
814 |
|
---|
815 | emmcmd52[0x39] = csystem_data->provider;
|
---|
816 |
|
---|
817 | if(({drecas_MSP_cmd_nb(emmcmd52)}))
|
---|
818 | if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
|
---|
819 | { return ERROR; } // exit if response is not 90 00
|
---|
820 | }
|
---|
821 |
|
---|
822 | uint8_t emmcmd34[0x30] = {
|
---|
823 | 0x34, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x10,
|
---|
824 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
825 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
826 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
827 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
---|
828 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
---|
829 | };
|
---|
830 | emmcmd34[1] = ep->emm[0x05];
|
---|
831 | emmcmd34[2] = ep->emm[0x5A];
|
---|
832 | emmcmd34[3] = ep->emm[0x03];
|
---|
833 | uint8_t need_save = 0;
|
---|
834 |
|
---|
835 | for(i = 0; i < 2; i++)
|
---|
836 | {
|
---|
837 | memcpy(&emmcmd34[7], &ep->emm[(i * 0x29) + 8] , 41);
|
---|
838 |
|
---|
839 | if(memcmp(emmcmd34, stm_keys_t.stmcmd34[ep->emm[0x05] + (ep->emm[7] == 0x3B ? i * 32 : (i == 0 ? 32 : 0))], 0x30) != 0)
|
---|
840 | {
|
---|
841 | memcpy(stm_keys_t.stmcmd34[ep->emm[0x05] + (ep->emm[7] == 0x3B ? i * 32 : (i == 0 ? 32 : 0))], emmcmd34, 0x30);
|
---|
842 | need_save = 1;
|
---|
843 | }
|
---|
844 | }
|
---|
845 |
|
---|
846 | if(need_save == 1) stm_key_operaion(reader, WRITE);
|
---|
847 | }
|
---|
848 | else if(ep->type == GLOBAL && ep->emm[0] == 0x91)
|
---|
849 | {
|
---|
850 | Drecrypt2OverEMM(ep->emm);
|
---|
851 | return OK;
|
---|
852 | }
|
---|
853 | else return OK;
|
---|
854 | }
|
---|
855 |
|
---|
856 | return ERROR;
|
---|
857 | }
|
---|
858 |
|
---|
859 | static int32_t drecas_card_info(struct s_reader *UNUSED(rdr))
|
---|
860 | {
|
---|
861 | return OK;
|
---|
862 | }
|
---|
863 |
|
---|
864 | const struct s_cardsystem reader_drecas =
|
---|
865 | {
|
---|
866 | .desc = "drecas",
|
---|
867 | .caids = (uint16_t[]){ 0x4AE1, 0 },
|
---|
868 | .do_emm = drecas_do_emm,
|
---|
869 | .do_ecm = drecas_do_ecm,
|
---|
870 | .card_info = drecas_card_info,
|
---|
871 | .card_init = drecas_card_init,
|
---|
872 | .get_emm_type = dre_common_get_emm_type,
|
---|
873 | .get_emm_filter = dre_common_get_emm_filter,
|
---|
874 | };
|
---|
875 |
|
---|
876 | #endif
|
---|