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, &params) < 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