1 /*
2 * driver for Rutoken devices
3 *
4 * Copyright (C) 2007, Pavel Mironchik <rutoken@rutoken.ru>
5 * Copyright (C) 2007, Eugene Hermann <e_herman@rutoken.ru>
6 */
7
8 #include "internal.h"
9 #include <unistd.h>
10 #include <string.h>
11 #include <stdlib.h>
12
13 #define MAX_BUF_T0_LEN 256
14 #define T0_HDR_LEN 5
15
16 #define USB_ICC_POWER_ON 0x62
17 #define USB_ICC_POWER_OFF 0x63
18 #define USB_ICC_XFR_BLOCK 0x65
19 #define USB_ICC_DATA_BLOCK 0x6F
20 #define USB_ICC_GET_STATUS 0xA0
21
22 #define ICC_STATUS_IDLE 0x00
23 #define ICC_STATUS_READY_DATA 0x10
24 #define ICC_STATUS_READY_SW 0x20
25 #define ICC_STATUS_BUSY_COMMON 0x40
26 #define ICC_STATUS_MUTE 0x80
27
28 #define OUR_ATR_LEN 19
29
rutoken_open(ifd_reader_t * reader,const char * device_name)30 static int rutoken_open(ifd_reader_t * reader, const char *device_name)
31 {
32 ifd_device_t *dev;
33 ifd_device_params_t params;
34
35 ifd_debug(6, "rutoken_open - %s", device_name);
36
37 reader->name = "Rutoken S driver";
38 reader->nslots = 1;
39 if (!(dev = ifd_device_open(device_name)))
40 return -1;
41
42 if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
43 ct_error("Rutoken: device %s is not a USB device", device_name);
44 ifd_device_close(dev);
45 return -1;
46 }
47
48 params = dev->settings;
49 params.usb.interface = 0;
50 if (ifd_device_set_parameters(dev, ¶ms) < 0) {
51 ct_error("Rutoken: setting parameters failed", device_name);
52 ifd_device_close(dev);
53 return -1;
54 }
55
56 reader->device = dev;
57 dev->timeout = 1000;
58
59 ifd_debug(6, "rutoken_open - %s - successful", device_name);
60 return 0;
61 }
62
rutoken_activate(ifd_reader_t * reader)63 static int rutoken_activate(ifd_reader_t * reader)
64 {
65 ifd_debug(6, "called.");
66 return 0;
67 }
68
rutoken_deactivate(ifd_reader_t * reader)69 static int rutoken_deactivate(ifd_reader_t * reader)
70 {
71 ifd_debug(6, "called.");
72 return -1;
73 }
74
rutoken_getstatus(ifd_reader_t * reader,unsigned char * status)75 static int rutoken_getstatus(ifd_reader_t * reader, unsigned char *status)
76 {
77 if(ifd_usb_control(reader->device, 0xc1, USB_ICC_GET_STATUS,
78 0, 0, status, 1, 1000) < 0 )
79 return -1;
80 if((*status & 0xF0) == ICC_STATUS_BUSY_COMMON){
81 unsigned char prev_status;
82 int i;
83 for(i = 0; i < 200; i++) { // 2 s (200 * 10 ms)
84 do {
85 usleep(10000); // 10 ms
86 prev_status = *status;
87 if(ifd_usb_control(reader->device, 0xc1,
88 USB_ICC_GET_STATUS, 0, 0,
89 status, 1, 1000) < 0
90 )
91 return -1;
92 if((*status & 0xF0) != ICC_STATUS_BUSY_COMMON)
93 return *status;
94 } while((((prev_status & 0x0F) + 1) & 0x0F) == (*status & 0x0F));
95 }
96 return -1;
97 }
98 return *status;
99 }
100
rutoken_card_reset(ifd_reader_t * reader,int slot,void * atr,size_t atr_len)101 static int rutoken_card_reset(ifd_reader_t * reader, int slot, void *atr,
102 size_t atr_len)
103 {
104 int nLen = 0, i;
105 ifd_debug(6, "rutoken_card_reset, slot = %X", slot);
106 if(ifd_usb_control(reader->device, 0x41, USB_ICC_POWER_OFF, 0, 0, 0, 0, -1) < 0)
107 {
108 ifd_debug(6, "error poweroff");
109 return -1;
110 }
111 unsigned char status;
112 if( rutoken_getstatus(reader, &status) < 0)
113 {
114 ifd_debug(6, "error get status");
115 return -1;
116 }
117 if( status == ICC_STATUS_READY_DATA ) {
118 char buf[OUR_ATR_LEN];
119 memset(buf, 0, OUR_ATR_LEN);
120
121 nLen = ifd_usb_control(reader->device, 0xc1, USB_ICC_POWER_ON, 0, 0,
122 buf, OUR_ATR_LEN, 1000);
123 if( nLen < 0 )
124 {
125 ifd_debug(6, "error poewron");
126 return -1;
127 }
128
129 ifd_debug(6, "returned len = %d", nLen);
130 for(i = 0; i < OUR_ATR_LEN; i++) ifd_debug(6, "%c", buf[i]);
131 memcpy(atr, buf, nLen);
132 return nLen;
133 }
134
135 ifd_debug(6, "error bad status");
136 return -1;
137 }
138
rutoken_restart(ifd_reader_t * reader)139 static int rutoken_restart(ifd_reader_t * reader)
140 {
141 char atr[256];
142 return rutoken_card_reset(reader, 0, atr, 256);
143 }
144
145 /*
146 * Select a protocol.
147 */
rutoken_set_protocol(ifd_reader_t * reader,int nslot,int proto)148 static int rutoken_set_protocol(ifd_reader_t * reader, int nslot, int proto)
149 {
150 ifd_slot_t *slot;
151 ifd_protocol_t *p;
152
153 ifd_debug(6, "proto=%d", proto);
154 if (proto != IFD_PROTOCOL_T0 && proto != IFD_PROTOCOL_TRANSPARENT) {
155 ct_error("%s: protocol %d not supported", reader->name, proto);
156 return IFD_ERROR_NOT_SUPPORTED;
157 }
158 slot = &reader->slot[nslot];
159 p = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT, reader, slot->dad);
160 if (p == NULL) {
161 ct_error("%s: internal error", reader->name);
162 return IFD_ERROR_GENERIC;
163 }
164 if (slot->proto) {
165 ifd_protocol_free(slot->proto);
166 slot->proto = NULL;
167 }
168 slot->proto = p;
169 ifd_debug(6, "success");
170 return 0;
171 }
172
rutoken_card_status(ifd_reader_t * reader,int slot,int * status)173 static int rutoken_card_status(ifd_reader_t * reader, int slot,
174 int *status)
175 {
176 *status = IFD_CARD_PRESENT;
177 return 0;
178 }
179
rutoken_send(ifd_reader_t * reader,unsigned int dad,const unsigned char * buffer,size_t len)180 static int rutoken_send(ifd_reader_t * reader, unsigned int dad,
181 const unsigned char *buffer, size_t len)
182 {
183 int ret;
184 unsigned char status;
185 ifd_debug(3, "usb send %s len %d", ct_hexdump(buffer, len), len);
186 ret = ifd_usb_control(reader->device, 0x41, USB_ICC_XFR_BLOCK, 0, 0,
187 (void *)buffer, len, -1);
188
189 if (rutoken_getstatus(reader, &status) < 0)
190 {
191 ret = -1;
192 ifd_debug(6, "error get status");
193 }
194 return ret;
195 }
196
rutoken_recv(ifd_reader_t * reader,unsigned int dad,unsigned char * buffer,size_t len,long timeout)197 static int rutoken_recv(ifd_reader_t * reader, unsigned int dad,
198 unsigned char *buffer, size_t len, long timeout)
199 {
200 unsigned char status;
201 int ret = len;
202 // USB_ICC_DATA_BLOCK
203 if( (ret = ifd_usb_control(reader->device, 0xc1, USB_ICC_DATA_BLOCK, 0, 0,
204 buffer, len, timeout)) >= 0)
205 if (rutoken_getstatus(reader, &status) < 0)
206 {
207 ret = -1;
208 ifd_debug(6, "error get status, %0x", status);
209 }
210 ifd_debug(3, "usd recv %s len %d", ct_hexdump(buffer, ret), ret);
211 return ret;
212 }
213
rutoken_recv_sw(ifd_reader_t * reader,int dad,unsigned char * sw)214 static int rutoken_recv_sw(ifd_reader_t * reader, int dad, unsigned char *sw)
215 {
216 unsigned char status;
217 if(rutoken_getstatus(reader, &status) == ICC_STATUS_MUTE)
218 { //If device not responsive
219 ifd_debug(6, "status = ICC_STATUS_MUTE");
220 return(rutoken_restart(reader));
221 }
222 if(status == ICC_STATUS_READY_SW)
223 {
224 ifd_debug(6, "status = ICC_STATUS_READY_SW;");
225 if(rutoken_recv(reader, 0, sw, 2, 10000) < 0)
226 return -5;
227 ifd_debug(6, "Get SW %x %x", sw[0], sw[1]);
228 return 2;
229 }
230 return -1;
231 }
232
233 // return how mach byte send
234 // sbuf - APDU bufer
235 // slen
rutoken_send_tpducomand(ifd_reader_t * reader,int dad,const void * sbuf,size_t slen,void * rbuf,size_t rlen,int iscase4)236 static int rutoken_send_tpducomand(ifd_reader_t * reader, int dad, const void *sbuf,
237 size_t slen, void *rbuf, size_t rlen, int iscase4)
238 {
239 ifd_debug(6, "send tpdu command %s, len: %d", ct_hexdump(sbuf, slen), slen);
240 int rrecv = 0;
241 unsigned char status;
242 unsigned char sw[2];
243 ifd_iso_apdu_t iso;
244 if ( ifd_iso_apdu_parse(sbuf, slen, &iso) < 0)
245 return -1;
246 unsigned char hdr[T0_HDR_LEN]={iso.cla, iso.ins, iso.p1, iso.p2, 0};
247 switch(iso.cse){
248 case IFD_APDU_CASE_1:
249 // {cla, ins, p1, p2, 0};
250 ifd_debug(6, "case 1");
251 break;
252 case IFD_APDU_CASE_2S:
253 // {cla, ins, p1, p2, le};
254 // Rutoken Bug!!!
255 ifd_debug(6, "case 2");
256 /* select file */
257 if (iso.cla == 0 && iso.ins == 0xa4)
258 iso.le = 0x20;
259 /* get_do_info */
260 else if (iso.cla == 0x80 && iso.ins == 0x30)
261 iso.le = 0xff;
262 hdr[4] = iso.le;
263 break;
264 case IFD_APDU_CASE_3S:
265 // {cla, ins, p1, p2, lc};
266 ifd_debug(6, "case 3");
267 hdr[4] = iso.lc;
268 break;
269 default:
270 break;
271 }
272 //send TPDU header
273 if (rutoken_send(reader, 0, hdr, T0_HDR_LEN) < 0)
274 return -1;
275 // send TPDU data or get answere and sw
276 switch(iso.cse){
277 case IFD_APDU_CASE_1:
278 // get sw
279 if (rutoken_recv_sw(reader, 0, sw) < 0)
280 return -2;
281 break;
282 case IFD_APDU_CASE_2S:
283 // get answere
284 ifd_debug(6, "Get Data %d", iso.le);
285 if(rutoken_getstatus(reader, &status) == ICC_STATUS_READY_DATA)
286 {
287 rrecv = rutoken_recv(reader, 0, rbuf, iso.le, 10000);
288 if (rrecv < 0)
289 return -2;
290 ifd_debug(6, "Get TPDU Anser %s",
291 ct_hexdump(rbuf, iso.le));
292 }
293 if (rutoken_recv_sw(reader, 0, sw) < 0)
294 return -2;
295 if ( sw[0] == 0x67) {
296 // Le definitely not accepted
297 break;
298 }
299 if ( (sw[0] == 0x6c) ) {
300 unsigned char sbuftmp[slen];
301 memcpy(sbuftmp, sbuf, slen);
302 sbuftmp[4] = sw[1];
303 return rutoken_send_tpducomand(reader, dad, sbuftmp,
304 slen, rbuf, rlen, 0);
305 }
306 break;
307 case IFD_APDU_CASE_3S:
308 // send data
309 ifd_debug(6, "Send Data %d", iso.lc);
310 if(rutoken_getstatus(reader, &status) == ICC_STATUS_READY_DATA)
311 {
312 ifd_debug(6, "Send TPDU Data %s",
313 ct_hexdump(iso.data, iso.lc));
314 if (rutoken_send(reader, 0, iso.data, iso.lc) < 0)
315 return -4;
316 } else return -3;
317 // get sw
318 if (rutoken_recv_sw(reader, 0, sw) < 0)
319 return -2;
320
321 // NOT STANDART TPDU!!! BEGIN
322 if ( sw[0]== 0x61){
323 unsigned char lx = sw[1];
324 hdr[0] = 0x00; // iso.cla; (ruTokens specific)
325 hdr[1] = 0xc0; // ins get response
326 hdr[2] = 0; // p1
327 hdr[3] = 0; // p2
328 hdr[4] = lx ; //lx (case 2)
329 if(iscase4)
330 return rutoken_send_tpducomand(reader, dad, hdr,
331 T0_HDR_LEN, rbuf, rlen, 0);
332 else {
333 int recvtmp = rutoken_send_tpducomand(reader,dad,
334 hdr, T0_HDR_LEN, rbuf, rlen, 0);
335 rrecv = 0;
336 memcpy(sw, (unsigned char*)rbuf+recvtmp-2, 2);
337 break;
338 }
339 }
340
341 if ( (sw[0] == 0x90) && (sw[1] == 0x00))
342 {
343 hdr[0] = 0x00; //iso.cla;
344 hdr[1] = 0xc0; // ins get response
345 hdr[2] = 0; // p1
346 hdr[3] = 0; // p2
347 hdr[4] = iso.le; // le (case 2)
348 if(iscase4)
349 return rutoken_send_tpducomand(reader, dad, hdr,
350 T0_HDR_LEN, rbuf, rlen, 0);
351 }
352 // NOT STANDART TPDU!!! END
353
354 break;
355 default:
356 break;
357 }
358 // Add SW to respond
359 memcpy(((char *)rbuf)+rrecv, sw, 2);
360 rrecv+=2;
361 ifd_debug(6, "Recv %d bytes", rrecv);
362 return rrecv;
363 }
364
swap_pair(unsigned char * buf,size_t len)365 static void swap_pair(unsigned char *buf, size_t len)
366 {
367 size_t i;
368 unsigned char tmp;
369
370 for (i = 0; i + 1 < len; i += 2) {
371 tmp = buf[i];
372 buf[i] = buf[i + 1];
373 buf[i + 1] = tmp;
374 }
375 }
376
swap_four(unsigned char * buf,size_t len)377 static void swap_four(unsigned char *buf, size_t len)
378 {
379 size_t i;
380 unsigned char tmp;
381
382 for (i = 0; i + 3 < len; i += 4) {
383 tmp = buf[i];
384 buf[i] = buf[i + 3];
385 buf[i + 3] = tmp;
386
387 swap_pair(&buf[i + 1], 2);
388 }
389 }
390
read_tag(unsigned char * buf,size_t buf_len,unsigned char tag_in,unsigned char * out,size_t out_len)391 static int read_tag(unsigned char *buf, size_t buf_len,
392 unsigned char tag_in, unsigned char *out, size_t out_len)
393 {
394 unsigned char tag;
395 size_t taglen, i = 0;
396
397 while (i + 2 <= buf_len) {
398 tag = buf[i];
399 taglen = buf[i + 1];
400 i += 2;
401 if (taglen + i > buf_len)
402 return -1;
403 if (tag == tag_in) {
404 if (taglen != out_len)
405 return -1;
406 memcpy(out, buf + i, out_len);
407 return 0;
408 }
409 i += taglen;
410 }
411 return -1;
412 }
413
convert_doinfo_to_rtprot(void * data,size_t data_len)414 static int convert_doinfo_to_rtprot(void *data, size_t data_len)
415 {
416 unsigned char dohdr[32] = { 0 };
417 unsigned char secattr[40], data_a5[0xff];
418 unsigned char *p = data;
419 size_t i, data_a5_len;
420
421 if (read_tag(p, data_len, 0x80, &dohdr[0], 2) == 0) {
422 swap_pair(&dohdr[0], 2);
423 ifd_debug(6, "tag 0x80 (file size) = %02x %02x", dohdr[0], dohdr[1]);
424 }
425 data_a5_len = dohdr[1] & 0xff;
426 if (read_tag(p, data_len, 0xA5, data_a5, data_a5_len) == 0)
427 ifd_debug(6, "tag 0xA5 = %s", ct_hexdump(data_a5, data_a5_len));
428 else
429 data_a5_len = 0;
430 if (data_len < sizeof(dohdr) + data_a5_len) {
431 ifd_debug(6, "data_len = %u", data_len);
432 return -1;
433 }
434 if (read_tag(p, data_len, 0x83, &dohdr[2], 2) == 0)
435 ifd_debug(6, "tag 0x83 (Type,ID) = %02x %02x", dohdr[2], dohdr[3]);
436 if (read_tag(p, data_len, 0x85, &dohdr[4], 3) == 0)
437 ifd_debug(6, "tag 0x85 (Opt,Flags,MaxTry) = %02x %02x %02x",
438 dohdr[4], dohdr[5], dohdr[6]);
439 if (read_tag(p, data_len, 0x86, secattr, sizeof(secattr)) == 0) {
440 i = 17;
441 memcpy(dohdr + i, secattr, 8);
442 for (i += 8, p = &secattr[8]; i < sizeof(dohdr); ++i, p += 4)
443 dohdr[i] = *p;
444 ifd_debug(6, "tag 0x86 = %s", ct_hexdump(&dohdr[17], 15));
445 }
446 memcpy(data, dohdr, sizeof(dohdr));
447 memcpy((unsigned char*)data + sizeof(dohdr), data_a5, data_a5_len);
448 return sizeof(dohdr) + data_a5_len;
449 }
450
convert_fcp_to_rtprot(void * data,size_t data_len)451 static int convert_fcp_to_rtprot(void *data, size_t data_len)
452 {
453 unsigned char rtprot[32] = { 0 };
454 unsigned char secattr[40];
455 unsigned char *p = data;
456 size_t i;
457
458 if (data_len < sizeof(rtprot)) {
459 ifd_debug(6, "data_len = %u", data_len);
460 return -1;
461 }
462 /* 0x62 - FCP */
463 if (p[0] != 0x62 || (size_t)p[1] + 2 > data_len) {
464 ifd_debug(6, "Tag = %02x len = %u", p[0], p[1]);
465 return -1;
466 }
467 p += 2;
468 data_len -= 2;
469 /* file type */
470 if (read_tag(p, data_len, 0x82, &rtprot[4], 2) != 0)
471 return -1;
472 ifd_debug(6, "tag 0x82 (file type) = %02x %02x", rtprot[4], rtprot[5]);
473 /* file id */
474 if (read_tag(p, data_len, 0x83, &rtprot[6], 2) != 0)
475 return -1;
476 swap_pair(&rtprot[6], 2);
477 ifd_debug(6, "tag 0x83 (file id) = %02x %02x", rtprot[6], rtprot[7]);
478 /* file size */
479 if (read_tag(p, data_len, 0x81, &rtprot[0], 2) == 0) {
480 swap_pair(&rtprot[0], 2);
481 ifd_debug(6, "tag 0x81 (complete file size) = %02x %02x",
482 rtprot[0], rtprot[1]);
483 }
484 if (read_tag(p, data_len, 0x80, &rtprot[2], 2) == 0) {
485 swap_pair(&rtprot[2], 2);
486 ifd_debug(6, "tag 0x80 (file size) = %02x %02x", rtprot[2], rtprot[3]);
487 }
488 if (read_tag(p, data_len, 0x86, secattr, sizeof(secattr)) == 0) {
489 i = 17;
490 memcpy(rtprot + i, secattr, 8);
491 for (i += 8, p = &secattr[8]; i < sizeof(rtprot); ++i, p += 4)
492 rtprot[i] = *p;
493 ifd_debug(6, "tag 0x86 = %s", ct_hexdump(&rtprot[17], 15));
494 }
495 memcpy(data, rtprot, sizeof(rtprot));
496 return sizeof(rtprot);
497 }
498
convert_rtprot_to_doinfo(void * data,size_t data_len)499 static int convert_rtprot_to_doinfo(void *data, size_t data_len)
500 {
501 unsigned char doinfo[0xff] = { 0 };
502 unsigned char *pdata = data;
503 size_t i, doinfo_len = 0;
504
505 if (data_len < 32) {
506 ifd_debug(6, "data_len = %u", data_len);
507 return -1;
508 }
509 if (pdata[0] != 0 && pdata[0] < sizeof(doinfo) - 4 - 4 - 5 - 42 - 2) {
510 /* Tag 0x80 */
511 doinfo[doinfo_len++] = 0x80;
512 doinfo[doinfo_len++] = 2;
513 memcpy(doinfo + doinfo_len, pdata, 2);
514 swap_pair(doinfo + doinfo_len, 2);
515 doinfo_len += 2;
516 }
517 /* Tag 0x83 */
518 doinfo[doinfo_len++] = 0x83;
519 doinfo[doinfo_len++] = 2;
520 doinfo[doinfo_len++] = pdata[2];
521 doinfo[doinfo_len++] = pdata[3];
522
523 /* Tag 0x85 */
524 doinfo[doinfo_len++] = 0x85;
525 doinfo[doinfo_len++] = 3;
526 doinfo[doinfo_len++] = pdata[4];
527 doinfo[doinfo_len++] = pdata[5];
528 doinfo[doinfo_len++] = pdata[6];
529
530 /* Tag 0x86 */
531 doinfo[doinfo_len++] = 0x86;
532 doinfo[doinfo_len++] = 40;
533 memcpy(doinfo + doinfo_len, pdata + 17, 8);
534 doinfo_len += 8;
535 for (i = 0; i < 7 && doinfo_len + 3 < sizeof(doinfo); ++i, doinfo_len += 4)
536 doinfo[doinfo_len] = pdata[17 + 8 + i];
537 doinfo_len += 4; /* for reserved */
538 if (pdata[0] != 0 && pdata[0] + doinfo_len + 2 < sizeof(doinfo)) {
539 /* Tag 0xA5 */
540 if (data_len - 32 < pdata[0]) {
541 ifd_debug(6, "for tag 0xA5 incorrect data_len = %u", data_len);
542 return -1;
543 }
544 doinfo[doinfo_len++] = 0xA5;
545 doinfo[doinfo_len++] = pdata[0];
546 memcpy(doinfo + doinfo_len, pdata + 32, pdata[0]);
547 doinfo_len += pdata[0];
548 }
549 ifd_debug(6, "doinfo = %s", ct_hexdump(doinfo, doinfo_len));
550 memcpy(data, doinfo, doinfo_len);
551 return doinfo_len;
552 }
553
convert_rtprot_to_fcp(void * data,size_t data_len)554 static int convert_rtprot_to_fcp(void *data, size_t data_len)
555 {
556 unsigned char fcp[63] = {
557 0x62, sizeof(fcp) - 2,
558 0x81, 2, 0, 0,
559 0x80, 2, 0, 0,
560 0x82, 2, 0, 0,
561 0x83, 2, 0, 0,
562 0x8A, 1, 0,
563 0x86, 40
564 };
565 unsigned char *p = data;
566 size_t i;
567
568 if (data_len < sizeof(fcp)) {
569 ifd_debug(6, "data_len = %u", data_len);
570 return -1;
571 }
572 /* Tag 0x81 */
573 memcpy(fcp + 4, p, 2);
574 swap_pair(fcp + 4, 2);
575 /* Tag 0x80 */
576 memcpy(fcp + 8, p + 2, 2);
577 swap_pair(fcp + 8, 2);
578 /* Tag 0x82 */
579 memcpy(fcp + 12, p + 4, 2);
580 /* Tag 0x83 */
581 memcpy(fcp + 16, p + 6, 2);
582 swap_pair(fcp + 16, 2);
583 /* Tag 0x8A */
584 fcp[20] = p[8];
585
586 /* Tag 0x86 */
587 memcpy(fcp + 23, p + 17, 8);
588 for (i = 0; i < 7 && sizeof(fcp) > 23 + 8 + i * 4; ++i)
589 fcp[23 + 8 + i * 4] = p[17 + 8 + i];
590 ifd_debug(6, "fcp = %s", ct_hexdump(fcp, sizeof(fcp)));
591 memcpy(data, fcp, sizeof(fcp));
592 return sizeof(fcp);
593 }
594
rutoken_transparent(ifd_reader_t * reader,int dad,const void * sbuf,size_t slen,void * rbuf,size_t rlen)595 static int rutoken_transparent( ifd_reader_t * reader, int dad,
596 const void *sbuf, size_t slen,
597 void *rbuf, size_t rlen)
598 {
599 unsigned char sw[2], *send_buf_trn = NULL;
600 const void *send_buf = sbuf;
601 int len, rrecv = -1, iscase4 = 0;
602 ifd_iso_apdu_t iso;
603
604 ifd_debug(6, "buffer %s rlen = %d", ct_hexdump(sbuf, slen), rlen);
605 if ( ifd_iso_apdu_parse(sbuf, slen, &iso) < 0)
606 return -1;
607 ifd_debug(6, "iso.le = %d", iso.le);
608
609 if (iso.cla == 0 && slen > 5) {
610 send_buf_trn = malloc(slen);
611 if (!send_buf_trn) {
612 ifd_debug(5, "out of memory (slen = %u)", slen);
613 return IFD_ERROR_NO_MEMORY;
614 }
615 memcpy(send_buf_trn, sbuf, slen);
616 /* select file, delete file */
617 if (iso.ins == 0xa4 || iso.ins == 0xe4)
618 swap_pair(send_buf_trn + 5, slen - 5);
619 /* create file */
620 else if (iso.ins == 0xe0) {
621 len = convert_fcp_to_rtprot(send_buf_trn + 5, slen - 5);
622 ifd_debug(6, "convert_fcp_to_rtprot = %i", len);
623 if (len > 0) {
624 slen = len + 5;
625 send_buf_trn[4] = len; /* replace le */
626 }
627 }
628 /* create_do, key_gen */
629 else if (iso.ins == 0xda && iso.p1 == 1
630 && (iso.p2 == 0x65 || iso.p2 == 0x62)) {
631 len = convert_doinfo_to_rtprot(send_buf_trn + 5, slen - 5);
632 ifd_debug(6, "convert_doinfo_to_rtprot = %i", len);
633 if (len > 0) {
634 slen = len + 5;
635 send_buf_trn[4] = len; /* replace le */
636 }
637 }
638 ifd_debug(6, "le = %u", send_buf_trn[4]);
639 send_buf = send_buf_trn;
640 }
641 switch(iso.cse){
642 case IFD_APDU_CASE_2S:
643 case IFD_APDU_CASE_3S:
644 if (iso.cla == 0 && iso.ins == 0xa4)
645 iscase4 = 1; /* FIXME: */
646 case IFD_APDU_CASE_1:
647 rrecv = rutoken_send_tpducomand(reader, dad, send_buf, slen,
648 rbuf, rlen, iscase4);
649 break;
650 case IFD_APDU_CASE_4S:
651 // make send case 4 command
652 rrecv = rutoken_send_tpducomand(reader, dad, send_buf, slen-1,
653 rbuf, rlen, 1);
654 break;
655 default:
656 break;
657 }
658 if (send_buf_trn)
659 free(send_buf_trn);
660
661 if (rrecv > 0 && (size_t)rrecv >= sizeof(sw)) {
662 memcpy(sw, (unsigned char*)rbuf + rrecv - sizeof(sw), sizeof(sw));
663 if (sw[0] != 0x90 || sw[1] != 0)
664 /* do nothing */;
665 /* select file */
666 else if (iso.cla == 0 && iso.ins == 0xa4
667 && rrecv == sizeof(sw) + 32 /* size rtprot */) {
668 len = convert_rtprot_to_fcp(rbuf, rlen);
669 ifd_debug(6, "convert_rtprot_to_fcp = %i", len);
670 if (len > 0) {
671 rrecv = -1;
672 if (rlen >= len + sizeof(sw)) {
673 memcpy((unsigned char*)rbuf+len, sw, sizeof(sw));
674 rrecv = len + sizeof(sw);
675 }
676 }
677 }
678 /* get_do_info */
679 else if (iso.cla == 0x80 && iso.ins == 0x30
680 && (size_t)rrecv >= sizeof(sw) + 32 /* size rtprot */) {
681 len = convert_rtprot_to_doinfo(rbuf, rlen);
682 ifd_debug(6, "convert_rtprot_to_doinfo = %i", len);
683 if (len > 0) {
684 rrecv = -1;
685 if (rlen >= len + sizeof(sw)) {
686 memcpy((unsigned char*)rbuf+len, sw, sizeof(sw));
687 rrecv = len + sizeof(sw);
688 }
689 }
690 }
691 else if (iso.cla == 0 && iso.ins == 0xca && iso.p1 == 1) {
692 /* get_serial, get_free_mem */
693 if (iso.p2 == 0x81 || iso.p2 == 0x8a)
694 swap_four(rbuf, rrecv - sizeof(sw));
695 /* get_current_ef */
696 else if (iso.p2 == 0x11)
697 swap_pair(rbuf, rrecv - sizeof(sw));
698 }
699 }
700 return rrecv;
701 }
702
rutoken_get_eventfd(ifd_reader_t * reader,short * events)703 static int rutoken_get_eventfd(ifd_reader_t * reader, short *events)
704 {
705 ifd_debug(6, "called.");
706
707 return ifd_device_get_eventfd(reader->device, events);
708 }
709
rutoken_event(ifd_reader_t * reader,int * status,size_t status_size)710 static int rutoken_event(ifd_reader_t * reader, int *status, size_t status_size)
711 {
712 (void)reader;
713 (void)status;
714 (void)status_size;
715
716 ifd_debug(6, "called.");
717
718 return 0;
719 }
720
rutoken_error(ifd_reader_t * reader)721 static int rutoken_error(ifd_reader_t * reader)
722 {
723 (void)reader;
724
725 ifd_debug(6, "called.");
726
727 return IFD_ERROR_DEVICE_DISCONNECTED;
728 }
729
730 static struct ifd_driver_ops rutoken_driver;
731
ifd_rutoken_register(void)732 void ifd_rutoken_register(void)
733 {
734 rutoken_driver.open = rutoken_open;
735 rutoken_driver.activate = rutoken_activate;
736 rutoken_driver.deactivate = rutoken_deactivate;
737 rutoken_driver.card_reset = rutoken_card_reset;
738 rutoken_driver.card_status = rutoken_card_status;
739 rutoken_driver.set_protocol = rutoken_set_protocol;
740 rutoken_driver.transparent = rutoken_transparent;
741 rutoken_driver.get_eventfd = rutoken_get_eventfd;
742 rutoken_driver.event = rutoken_event;
743 rutoken_driver.error = rutoken_error;
744
745 ifd_driver_register("rutoken", &rutoken_driver);
746 }
747
748