source: trunk/csctapi/protocol_t0.c@ 3181

Last change on this file since 3181 was 3181, checked in by dingo35, 10 years ago

Adding threadsafety FIXMEs, feel free to join checking..

File size: 15.6 KB
Line 
1//FIXME Not checked on threadsafety yet; after checking please remove this line
2/*
3 protocol_t0.c
4 Handling of ISO 7816 T=0 protocol
5
6 This file is part of the Unix driver for Towitoko smartcard readers
7 Copyright (C) 2000 Carlos Prados <cprados@yahoo.com>
8
9 This version is modified by doz21 to work in a special manner ;)
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24*/
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30
31#include "../globals.h"
32#include "defines.h"
33
34#include "protocol_t0.h"
35#include "atr.h"
36/*
37 * Not exported constants definition
38 */
39
40#define PROTOCOL_T0_MAX_NULLS 200
41#define PROTOCOL_T0_DEFAULT_WI 10
42#define PROTOCOL_T0_MAX_SHORT_COMMAND 260
43#define PROTOCOL_T0_MAX_SHORT_RESPONSE 258
44
45#define PROTOCOL_T14_MAX_NULLS 200
46#define PROTOCOL_T14_DEFAULT_WI 10
47#define PROTOCOL_T14_MAX_SHORT_COMMAND 260
48#define PROTOCOL_T14_MAX_SHORT_RESPONSE 258
49
50/* Types of APDU's */
51#define APDU_CASE_1 0x0001 /* Nor send neither receive data */
52#define APDU_CASE_2S 0x0002 /* Receive data (1..256) */
53#define APDU_CASE_3S 0x0003 /* Send data (1..255) */
54#define APDU_CASE_4S 0x0004 /* Send data (1..255) and receive data (1..256) */
55#define APDU_CASE_2E 0x0102 /* Receive data (1..65536) */
56#define APDU_CASE_3E 0x0103 /* Send data (1..65535) */
57#define APDU_CASE_4E 0x0104 /* Send data (1..65535) and receive data (1..65536) */
58#define APDU_MALFORMED 5 /* Malformed APDU */
59
60/* Timings in ATR are not used in T=0 cards */
61/* #undef PROTOCOL_T0_USE_DEFAULT_TIMINGS */
62
63/*
64 * Not exported functions declaration
65 */
66
67static int Protocol_T0_Case2E (struct s_reader * reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr);
68
69static int Protocol_T0_Case3E (struct s_reader * reader, unsigned char * command, unsigned char * rsp, unsigned short * lr);
70
71static int Protocol_T0_Case4E (struct s_reader * reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr);
72
73static int Protocol_T0_ExchangeTPDU (struct s_reader *reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr);
74
75static int APDU_Cmd_Case (unsigned char * command, unsigned short command_len)
76{
77 BYTE B1;
78 ushort B2B3;
79 ulong L;
80 int res;
81
82 /* Calculate length of body */
83 L = MAX(command_len - 4, 0);
84
85 /* Case 1 */
86 if (L == 0)
87 res = APDU_CASE_1;
88 else {
89 /* Get first byte of body */
90 B1 = command[4];
91
92 if ((B1 != 0) && (L == (ulong)B1 + 1))
93 res = APDU_CASE_2S;
94 else if (L == 1)
95 res = APDU_CASE_3S;
96 else if ((B1 != 0) && (L == (ulong)B1 + 2))
97 res = APDU_CASE_4S;
98 else if ((B1 == 0) && (L>2)) {
99 /* Get second and third byte of body */
100 B2B3 = (((ushort)(command[5]) << 8) | command[6]);
101
102 if ((B2B3 != 0) && (L == (ulong)B2B3 + 3))
103 res = APDU_CASE_2E;
104 else if (L == 3)
105 res = APDU_CASE_3E;
106 else if ((B2B3 != 0) && (L == (ulong)B2B3 + 5))
107 res = APDU_CASE_4E;
108 else
109 res = APDU_MALFORMED;
110 }
111 else
112 res = APDU_MALFORMED;
113 }
114 return res;
115}
116
117/*
118 * Exported funtions definition
119 */
120
121int Protocol_T0_Command (struct s_reader * reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr)
122{
123 *lr = 0; //will be returned in case of error
124 if (command_len < 5) //APDU_CASE_1 or malformed
125 return ERROR;
126 int cmd_case = APDU_Cmd_Case (command, command_len);
127 switch (cmd_case) {
128 case APDU_CASE_2E:
129 return Protocol_T0_Case2E (reader, command, command_len, rsp, lr);
130 case APDU_CASE_3E:
131 return Protocol_T0_Case3E (reader, command, rsp, lr);
132 case APDU_CASE_4E:
133 return Protocol_T0_Case4E (reader, command, command_len, rsp, lr);
134 case APDU_CASE_4S:
135 command_len--; //FIXME this should change 4S to 2S/3S command
136 case APDU_CASE_2S:
137 case APDU_CASE_3S:
138 return Protocol_T0_ExchangeTPDU(reader, command, command_len, rsp, lr);
139 default:
140 cs_debug_mask (D_IFD,"Protocol: T=0: Invalid APDU\n");
141 return ERROR;
142 }
143}
144
145/*
146 * Not exported functions definition
147 */
148
149
150static int Protocol_T0_Case2E (struct s_reader * reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr)
151{
152 BYTE buffer[PROTOCOL_T0_MAX_SHORT_COMMAND];
153 unsigned char tpdu_rsp[CTA_RES_LEN];
154 unsigned short * tpdu_lr = 0;
155 ulong i;
156
157 unsigned long Lc = (((unsigned long)(command[5]) << 8) | command[6]);
158 if (Lc < 256)
159 {
160 /* MAP APDU onto command TPDU */
161 memcpy(buffer, command, 4);
162 buffer[4] = (BYTE) Lc;
163 memcpy (buffer + 5, command + 7, buffer[4]);
164 return Protocol_T0_ExchangeTPDU(reader, buffer, buffer[4] + 5, rsp, lr);
165 }
166
167 /* Prepare envelope TPDU */
168 buffer[0] = command[0];
169 buffer[1] = 0xC2;
170 buffer[2] = 0x00;
171 buffer[3] = 0x00;
172
173 for (i = 0; i < command_len; i += buffer[4])
174 {
175 /* Create envelope command TPDU */
176 buffer[4] = MIN (255, command_len - i);
177 memcpy (buffer + 5, command + i, buffer[4]);
178 call (Protocol_T0_ExchangeTPDU(reader, buffer, buffer[4] + 5, tpdu_rsp, tpdu_lr));
179 /* Card does support envelope command */
180 if (tpdu_rsp[*tpdu_lr - 2] == 0x90)
181 {
182 /* This is not the last segment */
183 if (buffer[4] + i < command_len)
184 *tpdu_lr = 0;
185 else {
186 memcpy(rsp, tpdu_rsp, *tpdu_lr); // Map response TPDU onto APDU
187 *lr = *tpdu_lr;
188 }
189 }
190 else /* Card does not support envelope command or error */
191 {
192 memcpy(rsp, tpdu_rsp, *tpdu_lr); // Map response TPDU onto APDU
193 *lr = *tpdu_lr;
194 break;
195 }
196 }
197 return OK;
198}
199
200
201static int Protocol_T0_Case3E (struct s_reader * reader, unsigned char * command, unsigned char * rsp, unsigned short * lr)
202{
203 int ret;
204 BYTE buffer[5];
205 unsigned char tpdu_rsp[CTA_RES_LEN];
206 unsigned short * tpdu_lr = 0;
207 long Lm, Lx;
208
209 unsigned long Le = ((((unsigned long)(command[5]) << 8) | command[6]) == 0 ? 65536 : (((unsigned long)(command[5]) << 8) | command[6]));
210 memcpy(buffer, command, 4);//Map APDU command onto TPDU
211
212 if (Le <= 256)
213 {
214 buffer[4] = (BYTE)Le;
215 return Protocol_T0_ExchangeTPDU(reader, buffer, 5, rsp, lr); //this was Case3S !!!
216 }
217
218 /* Map APDU onto command TPDU */
219 buffer[4] = 0x00;
220 call (Protocol_T0_ExchangeTPDU(reader, buffer, 5 , tpdu_rsp, tpdu_lr));
221
222 if (tpdu_rsp[*tpdu_lr - 2] == 0x6C) {/* Le not accepted, La indicated */
223 /* Map command APDU onto TPDU */
224 memcpy (buffer, command, 4);
225 buffer[4] = tpdu_rsp[*tpdu_lr - 1];
226
227 /* Delete response TPDU */
228 *tpdu_lr = 0;
229
230 return Protocol_T0_ExchangeTPDU(reader, buffer, 5, rsp, lr); //Reissue command
231 }
232
233 memcpy(rsp, tpdu_rsp, *tpdu_lr);//Map response TPDU onto APDU without change , also for SW1 = 0x67
234 *lr = *tpdu_lr;
235 ret = OK;
236 if (tpdu_rsp[*tpdu_lr - 2] == 0x61) {/* Command processed, Lx indicated */
237 Lx = (tpdu_rsp[*tpdu_lr - 1] == 0x00) ? 256 : tpdu_rsp[*tpdu_lr - 1];
238 Lm = Le - (*lr - 2);
239
240 /* Prepare Get Response TPDU */
241 buffer[0] = command[0];
242 buffer[1] = 0xC0;
243 buffer[2] = 0x00;
244 buffer[3] = 0x00;
245
246 while (Lm > 0)
247 {
248 buffer[4] = (BYTE) MIN (Lm, Lx);
249 call (Protocol_T0_ExchangeTPDU(reader, buffer, 5, tpdu_rsp, tpdu_lr));
250
251 /* Append response TPDU to APDU */
252 if ((*lr + *tpdu_lr) > CTA_RES_LEN) {
253 cs_log("TPDU Append error, new length %i exceeds max length %i", *lr + *tpdu_lr, CTA_RES_LEN);
254 return ERROR;
255 }
256 memcpy (rsp + (*lr - 2), tpdu_rsp, *tpdu_lr);
257 *lr += *tpdu_lr;
258
259 /* Delete response TPDU */
260 *tpdu_lr = 0;
261
262 Lm = Le - (*lr - 2);
263 }/* Lm == 0 */
264 }
265 return ret;
266}
267
268
269static int Protocol_T0_Case4E (struct s_reader * reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr)
270{
271 int ret;
272 BYTE buffer[PROTOCOL_T0_MAX_SHORT_COMMAND];
273 unsigned char tpdu_rsp[CTA_RES_LEN];
274 unsigned short * tpdu_lr = 0;
275 long Le;
276
277 unsigned long Lc = (((unsigned long)(command[5]) << 8) | command[6]);
278 /* 4E1 */
279 if (Lc < 256) {
280 /* Map APDU onto command TPDU */
281 memcpy(buffer,command,4);
282 buffer[4] = (BYTE) Lc;
283 memcpy (buffer + 5, command, buffer[4]);
284 ret = Protocol_T0_ExchangeTPDU(reader, buffer, buffer[4] + 5, tpdu_rsp, tpdu_lr);
285 }
286 else /* 4E2 */
287 ret = Protocol_T0_Case2E (reader, command, command_len, tpdu_rsp, tpdu_lr);
288
289 /* 4E1 a) b) and c) */
290 if (ret == OK)
291 {
292 Le = ((((unsigned long)(command[command_len - 2]) << 8) | command[command_len - 1]) == 0 ? 65536 : (((unsigned long)(command[command_len - 2]) << 8) | command[command_len - 1]));
293 if (tpdu_rsp[*tpdu_lr - 2] == 0x61)
294 {
295 /* Lm == (Le - APDU_Rsp_RawLen (tpdu_rsp)) == 0 */
296 if (tpdu_rsp[*tpdu_lr - 1] != 0x00)
297 Le = MIN(tpdu_rsp[*tpdu_lr - 1], Le);
298
299 /* Delete response TPDU */
300 *tpdu_lr = 0;
301
302 /* Prepare extended Get Response APDU command */
303 buffer[0] = command[0];
304 buffer[1] = 0xC0;
305 buffer[2] = 0x00;
306 buffer[3] = 0x00;
307 buffer[4] = 0x00; /* B1 = 0x00 */
308 buffer[5] = (BYTE) (Le >> 8); /* B2 = BL-1 */
309 buffer[6] = (BYTE) (Le & 0x00FF); /* B3 = BL */
310 ret = Protocol_T0_Case3E (reader, buffer, rsp, lr);
311 }
312 else if ((tpdu_rsp[*tpdu_lr - 2] & 0xF0) == 0x60)
313 {
314 /* Map response TPDU onto APDU without change */
315 memcpy(rsp, tpdu_rsp, *tpdu_lr);
316 *lr = *tpdu_lr;
317 }
318 else
319 {
320 /* Delete response TPDU */
321 *tpdu_lr = 0;
322
323 /* Prepare extended Get Response APDU command */
324 buffer[0] = command[0];
325 buffer[1] = 0xC0;
326 buffer[2] = 0x00;
327 buffer[3] = 0x00;
328 buffer[4] = 0x00; /* B1 = 0x00 */
329 buffer[5] = (BYTE) Le >> 8; /* B2 = BL-1 */
330 buffer[6] = (BYTE) Le & 0x00FF; /* B3 = BL */
331 ret = Protocol_T0_Case3E (reader, buffer, rsp, lr);
332 }
333 }
334 return ret;
335}
336
337
338static int Protocol_T0_ExchangeTPDU (struct s_reader *reader, unsigned char * command, unsigned short command_len, unsigned char * rsp, unsigned short * lr)
339{
340 BYTE buffer[PROTOCOL_T0_MAX_SHORT_RESPONSE];
341 BYTE *data;
342 long Lc, Le, sent, recv;
343 int ret = OK, nulls, cmd_case;
344 *lr = 0; //in case of error this will be returned
345
346 cmd_case = APDU_Cmd_Case (command, command_len);
347 switch (cmd_case) {
348 case APDU_CASE_2S:
349 Lc = command[4];
350 Le = 0;
351 data = command + 5;
352 break;
353 case APDU_CASE_3S:
354 Lc = 0;
355 Le = command[4];
356 data = NULL;
357 break;
358 default:
359 cs_debug_mask(D_TRACE, "ERROR: invalid cmd_case = %i in Protocol_T0_ExchangeTPDU",cmd_case);
360 return ERROR;
361 }
362 call (ICC_Async_Transmit (reader, 5, command)); //Send header bytes
363
364 /* Initialise counters */
365 nulls = 0;
366 sent = 0;
367 recv = 0;
368
369 /*
370 * Let's be a bit paranoid with buffer sizes within this loop
371 * so it doesn't overflow reception and transmission buffers
372 * if card does not strictly respect the protocol
373 */
374
375 while (recv < PROTOCOL_T0_MAX_SHORT_RESPONSE)
376 {
377 call (ICC_Async_Receive (reader, 1, buffer + recv)); //Read one procedure byte
378
379 /* NULL byte received */
380 if (buffer[recv] == 0x60) {
381 nulls++;
382 if (nulls >= PROTOCOL_T0_MAX_NULLS) { //Maximum number of nulls reached
383 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU: Maximum number of nulls reached:%i",nulls);
384 return ERROR;
385 }
386 }
387 else if ((buffer[recv] & 0xF0) == 0x60 || (buffer[recv] & 0xF0) == 0x90) /* SW1 byte received */
388 {//printf("sw1\n");
389 recv++;
390 if (recv >= PROTOCOL_T0_MAX_SHORT_RESPONSE) {
391 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU: Maximum short response exceeded:%li",recv);
392 return ERROR;
393 }
394 call (ICC_Async_Receive (reader, 1, buffer + recv)); //Read SW2 byte
395 recv++;
396 ret = OK;
397 break;
398 }
399 else if ((buffer[recv] & 0x0E) == (command[1] & 0x0E)) /* ACK byte received */
400 {//printf("ack\n");
401 /* Reset null's counter */
402 nulls = 0;
403
404 /* Case 2 command: send data */
405 if (cmd_case == APDU_CASE_2S) {
406 if (sent >= Lc) {
407 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU ACK byte: sent=%li exceeds Lc=%li",sent, Lc);
408 return ERROR;
409 }
410 call (ICC_Async_Transmit(reader, MAX (Lc - sent, 0), data + sent)); /* Send remaining data bytes */
411 sent = Lc;
412 continue;
413 }
414 else /* Case 3 command: receive data */
415 {
416 if (recv >= PROTOCOL_T0_MAX_SHORT_RESPONSE) {
417 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU: Case 3 ACK - maximum short response exceeded:%li",recv);
418 return ERROR;
419 }
420
421 /*
422 * Le <= PROTOCOL_T0_MAX_SHORT_RESPONSE - 2 for short commands
423 */
424
425 /* Read remaining data bytes */
426 call (ICC_Async_Receive(reader, MAX (Le - recv, 0), buffer + recv));
427 recv = Le;
428 continue;
429 }
430 }
431 else if ((buffer[recv] & 0x0E) == ((~command[1]) & 0x0E)) /* ~ACK byte received */
432 {//printf("~ack\n");
433 nulls = 0; //Reset null's counter
434
435 /* Case 2 command: send data */
436 if (cmd_case == APDU_CASE_2S) {
437 if (sent >= Lc) {
438 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU ~ACK byte: sent=%li exceeds Lc=%li",sent, Lc);
439 return ERROR;
440 }
441 call (ICC_Async_Transmit (reader, 1, data + sent)); //Send next data byte
442 sent++;
443 continue;
444 }
445 else {/* Case 3 command: receive data */
446 if (recv >= PROTOCOL_T0_MAX_SHORT_RESPONSE) {
447 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU: Case 3 ~ACK - maximum short response exceeded:%li",recv);
448 return ERROR;
449 }
450 call (ICC_Async_Receive (reader, 1, buffer + recv)); //Read next data byte
451 recv++;
452 continue;
453 }
454 }
455 else { /* Anything else received */
456 cs_debug_mask(D_TRACE, "ERROR Protocol_T0_ExchangeTPDU: Received unexpected character %02X", buffer[recv]);
457 return ERROR;
458 }
459 }//while
460
461 memcpy(rsp, buffer, recv);
462 *lr = recv;
463 return OK;
464}
465
466int Protocol_T14_ExchangeTPDU (struct s_reader *reader, unsigned char * cmd_raw, unsigned short command_len, unsigned char * rsp, unsigned short * lr)
467{
468 BYTE buffer[PROTOCOL_T14_MAX_SHORT_RESPONSE];
469 long recv;
470 int cmd_case;
471 BYTE ixor = 0x3E;
472 BYTE ixor1 = 0x3F;
473 BYTE b1 = 0x01;
474 int i;
475 long cmd_len = (long) command_len;
476 *lr = 0; //in case of error this is returned
477
478 /* Parse APDU */
479 cmd_case = APDU_Cmd_Case (cmd_raw, cmd_len);
480 for(i=0; i<cmd_len; i++)
481 ixor^=cmd_raw[i];
482
483 /* Check case of command */
484 if ((cmd_case != APDU_CASE_2S) && (cmd_case != APDU_CASE_3S)) {
485 cs_debug_mask(D_TRACE, "ERROR: invalid cmd_case = %i in Protocol_T14_ExchangeTPDU",cmd_case);
486 return ERROR;
487 }
488
489 if (reader->typ <= R_MOUSE) {
490 call (ICC_Async_Transmit (reader, 1, &b1)); //send 0x01 byte
491 call (ICC_Async_Transmit (reader, cmd_len, cmd_raw)); //send apdu
492 call (ICC_Async_Transmit (reader, 1, &ixor)); //Send xor byte
493 }
494 else {
495 buffer[0] = 0x01;
496 memcpy(buffer+1, cmd_raw, cmd_len);
497 buffer[cmd_len+1] = ixor;
498
499 /* Send apdu */
500 call (ICC_Async_Transmit (reader, cmd_len+2, buffer));//send apdu
501 }
502
503 if(cmd_raw[0] == 0x02 && cmd_raw[1] == 0x09)
504 cs_sleepms(2500); //FIXME why wait?
505 call (ICC_Async_Receive (reader, 8, buffer)); //Read one procedure byte
506 recv = (long)buffer[7];
507 if(recv)
508 call (ICC_Async_Receive (reader, recv, buffer + 8));
509 call (ICC_Async_Receive (reader, 1, &ixor));
510 for(i=0; i<8+recv; i++)
511 ixor1^=buffer[i];
512 if(ixor1 != ixor) {
513 cs_debug_mask(D_TRACE, "ERROR: invalid checksum = %02X expected %02X", ixor1, ixor);
514 return ERROR;
515 }
516 memcpy(buffer + 8 + recv, buffer + 2, 2);
517 *lr = recv + 2;
518 memcpy(rsp, buffer + 8, *lr);
519 return OK;
520}
Note: See TracBrowser for help on using the repository browser.