/[pcsclite]/trunk/Drivers/ccid/src/commands.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/src/commands.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1800 - (show annotations) (download)
Mon Jan 16 13:45:50 2006 UTC (7 years, 5 months ago) by rousseau
File MIME type: text/plain
File size: 32441 byte(s)
SecurePINVerify(): bug circumvention for the GemPC Pinpad
(bNumberMessage)
1 /*
2 commands.c: Commands sent to the card
3 Copyright (C) 2003-2004 Ludovic Rousseau
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * $Id$
22 */
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <pcsclite.h>
27 #include <ifdhandler.h>
28
29 #include "commands.h"
30 #include "openct/proto-t1.h"
31 #include "ccid.h"
32 #include "defs.h"
33 #include "ccid_ifdhandler.h"
34 #include "config.h"
35 #include "debug.h"
36
37 /* All the pinpad readers I used are more or less bogus
38 * I use code to change the user command and make the firmware happy */
39 #define BOGUS_PINPAD_FIRMWARE
40
41 #define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
42
43 /* internal functions */
44 static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
45 unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
46 unsigned char rx_buffer[]);
47
48 static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index, unsigned int
49 tx_length, unsigned char tx_buffer[], unsigned int *rx_length, unsigned
50 char rx_buffer[]);
51
52 static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
53 unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
54 unsigned char rx_buffer[]);
55
56 static void i2dw(int value, unsigned char *buffer);
57
58
59 /*****************************************************************************
60 *
61 * CmdPowerOn
62 *
63 ****************************************************************************/
64 RESPONSECODE CmdPowerOn(unsigned int reader_index, unsigned int * nlength,
65 unsigned char buffer[], int voltage)
66 {
67 unsigned char cmd[10];
68 status_t res;
69 int length, count = 1;
70 unsigned int atr_len;
71 RESPONSECODE return_value = IFD_SUCCESS;
72 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
73
74 /* store length of buffer[] */
75 length = *nlength;
76
77 if (ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_VOLTAGE)
78 voltage = 0; /* automatic voltage selection */
79
80 again:
81 cmd[0] = 0x62; /* IccPowerOn */
82 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
83 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
84 cmd[6] = (*ccid_descriptor->pbSeq)++;
85 cmd[7] = voltage;
86 cmd[8] = cmd[9] = 0; /* RFU */
87
88 res = WritePort(reader_index, sizeof(cmd), cmd);
89 if (res != STATUS_SUCCESS)
90 return IFD_COMMUNICATION_ERROR;
91
92 /* reset available buffer size */
93 /* needed if we go back after a switch to ISO mode */
94 *nlength = length;
95
96 res = ReadPort(reader_index, nlength, buffer);
97 if (res != STATUS_SUCCESS)
98 return IFD_COMMUNICATION_ERROR;
99
100 if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
101 {
102 ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
103
104 if (0xBB == buffer[ERROR_OFFSET] && /* Protocol error in EMV mode */
105 ((GEMPC433 == ccid_descriptor->readerID)
106 || (CHERRYXX33 == ccid_descriptor->readerID)))
107 {
108 unsigned char cmd[] = {0x1F, 0x01};
109 unsigned char res[1];
110 unsigned int res_length = sizeof(res);
111
112 if ((return_value = CmdEscape(reader_index, cmd, sizeof(cmd), res,
113 &res_length)) != IFD_SUCCESS)
114 return return_value;
115
116 /* avoid looping if we can't switch mode */
117 if (count--)
118 goto again;
119 else
120 DEBUG_CRITICAL("Can't set reader in ISO mode");
121 }
122
123 /* continue with 3 volts and 5 volts */
124 if (voltage > 1)
125 {
126 char *voltage_code[] = { "auto", "5V", "3V", "1.8V" };
127
128 DEBUG_INFO3("Power up with %s failed. Try with %s.",
129 voltage_code[voltage], voltage_code[voltage-1]);
130 voltage--;
131 goto again;
132 }
133
134 return IFD_COMMUNICATION_ERROR;
135 }
136
137 /* extract the ATR */
138 atr_len = dw2i(buffer, 1); /* ATR length */
139 if (atr_len > *nlength)
140 atr_len = *nlength;
141 else
142 *nlength = atr_len;
143
144 memmove(buffer, buffer+10, atr_len);
145
146 return return_value;
147 } /* CmdPowerOn */
148
149
150 /*****************************************************************************
151 *
152 * SecurePINVerify
153 *
154 ****************************************************************************/
155 RESPONSECODE SecurePINVerify(unsigned int reader_index,
156 unsigned char TxBuffer[], unsigned int TxLength,
157 unsigned char RxBuffer[], unsigned int *RxLength)
158 {
159 unsigned char cmd[11+14+CMD_BUF_SIZE];
160 unsigned int a, b;
161 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
162 int old_read_timeout;
163 RESPONSECODE ret;
164
165 cmd[0] = 0x69; /* Secure */
166 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
167 cmd[6] = (*ccid_descriptor->pbSeq)++;
168 cmd[7] = 0; /* bBWI */
169 cmd[8] = 0; /* wLevelParameter */
170 cmd[9] = 0;
171 cmd[10] = 0; /* bPINOperation: PIN Verification */
172
173 /* 19 is the size of the PCSCv2 PIN verify structure
174 * The equivalent CCID structure is only 14-bytes long */
175 if (TxLength > 19+CMD_BUF_SIZE) /* command too large? */
176 {
177 DEBUG_INFO3("Command too long: %d > %d", TxLength, 16+CMD_BUF_SIZE);
178 *RxLength = 0;
179 return IFD_NOT_SUPPORTED;
180 }
181
182 if (TxLength < 19+4 /* 4 = APDU size */) /* command too short? */
183 {
184 DEBUG_INFO3("Command too short: %d < %d", TxLength, 19+4);
185 *RxLength = 0;
186 return IFD_NOT_SUPPORTED;
187 }
188
189 if (dw2i(TxBuffer, 15) + 19 != TxLength) /* ulDataLength field coherency */
190 {
191 DEBUG_INFO3("Wrong lengths: %d %d", TxBuffer[15] + 19, TxLength);
192 *RxLength = 0;
193 return IFD_NOT_SUPPORTED;
194 }
195
196 #ifdef BOGUS_PINPAD_FIRMWARE
197 /* bug circumvention for the GemPC Pinpad */
198 if (GEMPCPINPAD == ccid_descriptor->readerID)
199 {
200 /* the firmware reject the cases: 00h No string and FFh default
201 * CCID message. The only value supported is 01h (display 1 message) */
202 if (0x01 != TxBuffer[8])
203 {
204 DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
205 TxBuffer[8]);
206 TxBuffer[8] = 0x01;
207 }
208 }
209 #endif
210
211 /* Build a CCID block from a PC/SC V2.1.2 Part 10 block */
212 for (a = 11, b = 0; b < TxLength; b++)
213 {
214 if (1 == b) /* bTimeOut2 field */
215 /* Ignore the second timeout as there's nothing we can do with
216 * it currently */
217 continue;
218
219 if ((b >= 15) && (b <= 18)) /* ulDataLength field (4 bytes) */
220 /* the ulDataLength field is not present in the CCID frame
221 * so do not copy */
222 continue;
223
224 /* copy the CCID block 'verbatim' */
225 cmd[a] = TxBuffer[b];
226 a++;
227 }
228
229 /* SPR532 and Case 1 APDU */
230 if ((SPR532 == ccid_descriptor->readerID) && (TxBuffer[15] == 4))
231 {
232 RESPONSECODE return_value;
233 unsigned char cmd[] = { 0x80, 0x02, 0x00 };
234 unsigned char res[1];
235 unsigned int res_length = sizeof(res);
236
237 /* the SPR532 will append the PIN code without any padding */
238 return_value = CmdEscape(reader_index, cmd, sizeof(cmd), res,
239 &res_length);
240 if (return_value != IFD_SUCCESS)
241 {
242 ccid_error(res[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);
243 return return_value;
244 }
245 }
246
247 i2dw(a - 10, cmd + 1); /* CCID message length */
248
249 old_read_timeout = ccid_descriptor -> readTimeout;
250 ccid_descriptor -> readTimeout = max(30, TxBuffer[0]); /* at least 30 seconds */
251
252 if (WritePort(reader_index, a, cmd) != STATUS_SUCCESS)
253 {
254 *RxLength = 0;
255 return IFD_COMMUNICATION_ERROR;
256 }
257
258 ret = CCID_Receive(reader_index, RxLength, RxBuffer);
259
260 ccid_descriptor -> readTimeout = old_read_timeout;
261 return ret;
262 } /* SecurePINVerify */
263
264
265 /*****************************************************************************
266 *
267 * SecurePINModify
268 *
269 ****************************************************************************/
270 RESPONSECODE SecurePINModify(unsigned int reader_index,
271 unsigned char TxBuffer[], unsigned int TxLength,
272 unsigned char RxBuffer[], unsigned int *RxLength)
273 {
274 unsigned char cmd[11+19+CMD_BUF_SIZE];
275 unsigned int a, b;
276 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
277 int old_read_timeout;
278 RESPONSECODE ret;
279
280 cmd[0] = 0x69; /* Secure */
281 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
282 cmd[6] = (*ccid_descriptor->pbSeq)++;
283 cmd[7] = 0; /* bBWI */
284 cmd[8] = 0; /* wLevelParameter */
285 cmd[9] = 0;
286 cmd[10] = 1; /* bPINOperation: PIN Modification */
287
288 /* 24 is the size of the PCSC PIN modify structure
289 * The equivalent CCID structure is only 18 or 19-bytes long */
290 if ((TxLength > 19+CMD_BUF_SIZE) /* command too large? */
291 || (TxLength < 18+4 /* 4 = APDU size */) /* command too short? */
292 || (TxBuffer[20] + 24 != TxLength)) /* ulDataLength field coherency */
293 {
294 *RxLength = 0;
295 return IFD_NOT_SUPPORTED;
296 }
297
298 /* Make sure in the beginning if bNumberMessage is valid or not */
299 if (TxBuffer[11] > 3)
300 {
301 *RxLength = 0;
302 return IFD_NOT_SUPPORTED;
303 }
304
305 #ifdef BOGUS_PINPAD_FIRMWARE
306 /* some firmwares are buggy so we try to "correct" the frame */
307 /*
308 * SPR 532 and Cherry ST 2000C has no display but requires _all_
309 * bMsgIndex fields with bNumberMessage set to 0.
310 */
311 if ((SPR532 == ccid_descriptor->readerID)
312 || (CHERRYST2000 == ccid_descriptor->readerID))
313 {
314 TxBuffer[11] = 0x03; /* set bNumberMessages to 3 so that
315 all bMsgIndex123 are filled */
316 TxBuffer[14] = TxBuffer[15] = TxBuffer[16] = 0; /* bMsgIndex123 */
317 }
318
319 /* bug circumvention for the GemPC Pinpad */
320 if (GEMPCPINPAD == ccid_descriptor->readerID)
321 {
322 /* The reader does not support, and actively reject, "max size reached"
323 * and "timeout occured" validation conditions */
324 if (0x02 != TxBuffer[10])
325 {
326 DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
327 TxBuffer[10]);
328 TxBuffer[10] = 0x02; /* validation key pressed */
329 }
330
331 /* the reader does not support any other value than 3 for the number
332 * of messages */
333 if (0x03 != TxBuffer[11])
334 {
335 DEBUG_INFO2("Correct bNumberMessages for GemPC Pinpad (was %d)",
336 TxBuffer[11]);
337 TxBuffer[11] = 0x03; /* 3 messages */
338 }
339 }
340 #endif
341
342 /* Build a CCID block from a PC/SC V2.1.2 Part 10 block */
343
344 /* Do adjustments as needed - CCID spec is not exact with some
345 * details in the format of the structure, per-reader adaptions
346 * might be needed.
347 */
348 for (a = 11, b = 0; b < TxLength; b++)
349 {
350 if (1 == b) /* bTimeOut2 */
351 /* Ignore the second timeout as there's nothing we can do with it
352 * currently */
353 continue;
354
355 if (15 == b) /* bMsgIndex2 */
356 {
357 /* in CCID the bMsgIndex2 is present only if bNumberMessage != 0 */
358 if (0 == TxBuffer[11])
359 continue;
360 }
361
362 if (16 == b) /* bMsgIndex3 */
363 {
364 /* in CCID the bMsgIndex3 is present only if bNumberMessage == 3 */
365 if (TxBuffer[11] < 3)
366 continue;
367 }
368
369 if ((b >= 20) && (b <= 23)) /* ulDataLength field (4 bytes) */
370 /* the ulDataLength field is not present in the CCID frame
371 * so do not copy */
372 continue;
373
374 /* copy to the CCID block 'verbatim' */
375 cmd[a] = TxBuffer[b];
376 a++;
377 }
378
379 #ifdef BOGUS_PINPAD_FIRMWARE
380 if ((SPR532 == ccid_descriptor->readerID)
381 || (CHERRYST2000 == ccid_descriptor->readerID))
382 {
383 cmd[21] = 0x00; /* set bNumberMessages to 0 */
384 }
385 #endif
386
387 /* We know the size of the CCID message now */
388 i2dw(a - 10, cmd + 1); /* command length (includes bPINOperation) */
389
390 old_read_timeout = ccid_descriptor -> readTimeout;
391 ccid_descriptor -> readTimeout = max(30, TxBuffer[0]); /* at least 30 seconds */
392
393 if (WritePort(reader_index, a, cmd) != STATUS_SUCCESS)
394 {
395 *RxLength = 0;
396 return IFD_COMMUNICATION_ERROR;
397 }
398
399 ret = CCID_Receive(reader_index, RxLength, RxBuffer);
400
401 ccid_descriptor -> readTimeout = old_read_timeout;
402 return ret;
403 } /* SecurePINModify */
404
405
406 /*****************************************************************************
407 *
408 * Escape
409 *
410 ****************************************************************************/
411 RESPONSECODE CmdEscape(unsigned int reader_index,
412 const unsigned char TxBuffer[], unsigned int TxLength,
413 unsigned char RxBuffer[], unsigned int *RxLength)
414 {
415 unsigned char *cmd_in, *cmd_out;
416 status_t res;
417 unsigned int length_in, length_out;
418 RESPONSECODE return_value = IFD_SUCCESS;
419 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
420
421 again:
422 /* allocate buffers */
423 length_in = 10 + TxLength;
424 if (NULL == (cmd_in = malloc(length_in)))
425 return IFD_COMMUNICATION_ERROR;
426
427 length_out = 10 + *RxLength;
428 if (NULL == (cmd_out = malloc(length_out)))
429 {
430 free(cmd_in);
431 return IFD_COMMUNICATION_ERROR;
432 }
433
434 cmd_in[0] = 0x6B; /* PC_to_RDR_Escape */
435 i2dw(length_in - 10, cmd_in+1); /* dwLength */
436 cmd_in[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
437 cmd_in[6] = (*ccid_descriptor->pbSeq)++;
438 cmd_in[7] = cmd_in[8] = cmd_in[9] = 0; /* RFU */
439
440 /* copy the command */
441 memcpy(&cmd_in[10], TxBuffer, TxLength);
442
443 res = WritePort(reader_index, length_in, cmd_in);
444 free(cmd_in);
445 if (res != STATUS_SUCCESS)
446 {
447 free(cmd_out);
448 return IFD_COMMUNICATION_ERROR;
449 }
450
451 res = ReadPort(reader_index, &length_out, cmd_out);
452
453 /* replay the command if NAK
454 * This (generally) happens only for the first command sent to the reader
455 * with the serial protocol so it is not really needed for all the other
456 * ReadPort() calls */
457 if (STATUS_COMM_NAK == res)
458 {
459 free(cmd_out);
460 goto again;
461 }
462
463 if (res != STATUS_SUCCESS)
464 {
465 free(cmd_out);
466 return IFD_COMMUNICATION_ERROR;
467 }
468
469 if (cmd_out[STATUS_OFFSET] & CCID_COMMAND_FAILED)
470 {
471 ccid_error(cmd_out[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
472 return_value = IFD_COMMUNICATION_ERROR;
473 }
474
475 /* copy the response */
476 length_out = dw2i(cmd_out, 1);
477 if (length_out > *RxLength)
478 length_out = *RxLength;
479 *RxLength = length_out;
480 memcpy(RxBuffer, &cmd_out[10], length_out);
481
482 free(cmd_out);
483
484 return return_value;
485 } /* Escape */
486
487
488 /*****************************************************************************
489 *
490 * CmdPowerOff
491 *
492 ****************************************************************************/
493 RESPONSECODE CmdPowerOff(unsigned int reader_index)
494 {
495 unsigned char cmd[10];
496 status_t res;
497 unsigned int length;
498 RESPONSECODE return_value = IFD_SUCCESS;
499 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
500
501 cmd[0] = 0x63; /* IccPowerOff */
502 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
503 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
504 cmd[6] = (*ccid_descriptor->pbSeq)++;
505 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
506
507 res = WritePort(reader_index, sizeof(cmd), cmd);
508 if (res != STATUS_SUCCESS)
509 return IFD_COMMUNICATION_ERROR;
510
511 length = sizeof(cmd);
512 res = ReadPort(reader_index, &length, cmd);
513 if (res != STATUS_SUCCESS)
514 return IFD_COMMUNICATION_ERROR;
515
516 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
517 {
518 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
519 return_value = IFD_COMMUNICATION_ERROR;
520 }
521
522 return return_value;
523 } /* CmdPowerOff */
524
525
526 /*****************************************************************************
527 *
528 * CmdGetSlotStatus
529 *
530 ****************************************************************************/
531 RESPONSECODE CmdGetSlotStatus(unsigned int reader_index, unsigned char buffer[])
532 {
533 unsigned char cmd[10];
534 status_t res;
535 unsigned int length;
536 RESPONSECODE return_value = IFD_SUCCESS;
537 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
538
539 cmd[0] = 0x65; /* GetSlotStatus */
540 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
541 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
542 cmd[6] = (*ccid_descriptor->pbSeq)++;
543 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
544
545 res = WritePort(reader_index, sizeof(cmd), cmd);
546 if (res != STATUS_SUCCESS)
547 return IFD_COMMUNICATION_ERROR;
548
549 length = SIZE_GET_SLOT_STATUS;
550 res = ReadPort(reader_index, &length, buffer);
551 if (res != STATUS_SUCCESS)
552 return IFD_COMMUNICATION_ERROR;
553
554 if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
555 {
556 ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
557
558 /* card absent or mute is not an communication error */
559 if (buffer[ERROR_OFFSET] != 0xFE)
560 return_value = IFD_COMMUNICATION_ERROR;
561 }
562
563 return return_value;
564 } /* CmdGetSlotStatus */
565
566
567 /*****************************************************************************
568 *
569 * CmdXfrBlock
570 *
571 ****************************************************************************/
572 RESPONSECODE CmdXfrBlock(unsigned int reader_index, unsigned int tx_length,
573 unsigned char tx_buffer[], unsigned int *rx_length,
574 unsigned char rx_buffer[], int protocol)
575 {
576 RESPONSECODE return_value = IFD_SUCCESS;
577 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
578
579 /* command length too big for CCID reader? */
580 if (tx_length > ccid_descriptor->dwMaxCCIDMessageLength)
581 {
582 DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
583 tx_length, ccid_descriptor->dwMaxCCIDMessageLength);
584 return_value = IFD_COMMUNICATION_ERROR;
585 goto clean_up_and_return;
586 }
587
588 /* command length too big for CCID driver? */
589 if (tx_length > CMD_BUF_SIZE)
590 {
591 DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
592 tx_length, CMD_BUF_SIZE);
593 return_value = IFD_COMMUNICATION_ERROR;
594 goto clean_up_and_return;
595 }
596
597 /* APDU or TPDU? */
598 switch (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)
599 {
600 case CCID_CLASS_TPDU:
601 if (protocol == T_0)
602 return_value = CmdXfrBlockTPDU_T0(reader_index,
603 tx_length, tx_buffer, rx_length, rx_buffer);
604 else
605 if (protocol == T_1)
606 return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
607 tx_buffer, rx_length, rx_buffer);
608 else
609 return_value = IFD_PROTOCOL_NOT_SUPPORTED;
610 break;
611
612 case CCID_CLASS_SHORT_APDU:
613 case CCID_CLASS_EXTENDED_APDU:
614 /* We only support extended APDU if the reader can support the
615 * command length. See test above */
616 return_value = CmdXfrBlockTPDU_T0(reader_index,
617 tx_length, tx_buffer, rx_length, rx_buffer);
618 break;
619
620 case CCID_CLASS_CHARACTER:
621 if (protocol == T_0)
622 return_value = CmdXfrBlockCHAR_T0(reader_index, tx_length,
623 tx_buffer, rx_length, rx_buffer);
624 else
625 if (protocol == T_1)
626 return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
627 tx_buffer, rx_length, rx_buffer);
628 else
629 return_value = IFD_PROTOCOL_NOT_SUPPORTED;
630 break;
631
632 default:
633 *rx_length = 0;
634 return_value = IFD_COMMUNICATION_ERROR;
635 }
636
637 clean_up_and_return:
638 return return_value;
639 } /* CmdXfrBlock */
640
641
642 /*****************************************************************************
643 *
644 * CCID_Transmit
645 *
646 ****************************************************************************/
647 RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
648 const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI)
649 {
650 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
651 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
652
653 cmd[0] = 0x6F; /* XfrBlock */
654 i2dw(tx_length, cmd+1); /* APDU length */
655 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
656 cmd[6] = (*ccid_descriptor->pbSeq)++;
657 cmd[7] = bBWI; /* extend block waiting timeout */
658 cmd[8] = rx_length & 0xFF; /* Expected length, in character mode only */
659 cmd[9] = (rx_length >> 8) & 0xFF;
660
661 /* check that the command is not too large */
662 if (tx_length > CMD_BUF_SIZE)
663 return IFD_NOT_SUPPORTED;
664
665 memcpy(cmd+10, tx_buffer, tx_length);
666
667 if (WritePort(reader_index, 10+tx_length, cmd) != STATUS_SUCCESS)
668 return IFD_COMMUNICATION_ERROR;
669
670 return IFD_SUCCESS;
671 } /* CCID_Transmit */
672
673
674 /*****************************************************************************
675 *
676 * CCID_Receive
677 *
678 ****************************************************************************/
679 RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
680 unsigned char rx_buffer[])
681 {
682 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
683 unsigned int length;
684
685 time_request:
686 length = sizeof(cmd);
687 if (ReadPort(reader_index, &length, cmd) != STATUS_SUCCESS)
688 {
689 *rx_length = 0;
690 return IFD_COMMUNICATION_ERROR;
691 }
692
693 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
694 {
695 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
696 switch (cmd[ERROR_OFFSET])
697 {
698 case 0xEF: /* cancel */
699 if (*rx_length < 2)
700 return IFD_COMMUNICATION_ERROR;
701 rx_buffer[0]= 0x64;
702 rx_buffer[1]= 0x01;
703 *rx_length = 2;
704 return IFD_SUCCESS;
705
706 case 0xF0: /* timeout */
707 if (*rx_length < 2)
708 return IFD_COMMUNICATION_ERROR;
709 rx_buffer[0]= 0x64;
710 rx_buffer[1]= 0x00;
711 *rx_length = 2;
712 return IFD_SUCCESS;
713
714 case 0xFD: /* Parity error during exchange */
715 *rx_length = 0; /* nothing received */
716 return IFD_PARITY_ERROR;
717
718 default:
719 *rx_length = 0; /* nothing received */
720 return IFD_COMMUNICATION_ERROR;
721 }
722 }
723
724 if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
725 {
726 DEBUG_COMM2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
727 goto time_request;
728 }
729
730 length = dw2i(cmd, 1);
731 if (length < *rx_length)
732 *rx_length = length;
733 else
734 length = *rx_length;
735 memcpy(rx_buffer, cmd+10, length);
736
737 return IFD_SUCCESS;
738 } /* CCID_Receive */
739
740
741 /*****************************************************************************
742 *
743 * CmdXfrBlockTPDU_T0
744 *
745 ****************************************************************************/
746 static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
747 unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
748 unsigned char rx_buffer[])
749 {
750 RESPONSECODE return_value = IFD_SUCCESS;
751
752 DEBUG_COMM2("T=0: %d bytes", tx_length);
753
754 return_value = CCID_Transmit(reader_index, tx_length, tx_buffer, 0, 0);
755 if (return_value != IFD_SUCCESS)
756 return return_value;
757
758 return CCID_Receive(reader_index, rx_length, rx_buffer);
759 } /* CmdXfrBlockTPDU_T0 */
760
761
762 /*****************************************************************************
763 *
764 * T0CmdParsing
765 *
766 ****************************************************************************/
767 static RESPONSECODE T0CmdParsing(unsigned char *cmd, unsigned int cmd_len,
768 unsigned int *exp_len)
769 {
770 *exp_len = 0;
771
772 /* Ref: 7816-4 Annex A */
773 switch (cmd_len)
774 {
775 case 4: /* Case 1 */
776 *exp_len = 2; /* SW1 and SW2 only */
777 break;
778
779 case 5: /* Case 2 */
780 if (cmd[4] != 0)
781 *exp_len = cmd[4] + 2;
782 else
783 *exp_len = 256 + 2;
784 break;
785
786 default: /* Case 3 */
787 if (cmd_len > 5 && cmd_len == (unsigned int)(cmd[4] + 5))
788 *exp_len = 2; /* SW1 and SW2 only */
789 else
790 return IFD_COMMUNICATION_ERROR; /* situation not supported */
791 break;
792 }
793
794 return IFD_SUCCESS;
795 } /* T0CmdParsing */
796
797
798 /*****************************************************************************
799 *
800 * T0ProcACK
801 *
802 ****************************************************************************/
803 static RESPONSECODE T0ProcACK(unsigned int reader_index,
804 unsigned char **snd_buf, unsigned int *snd_len,
805 unsigned char **rcv_buf, unsigned int *rcv_len,
806 unsigned char **in_buf, unsigned int *in_len,
807 unsigned int proc_len, int is_rcv)
808 {
809 RESPONSECODE return_value;
810 unsigned int remain_len;
811 unsigned char tmp_buf[512];
812 unsigned int ret_len;
813
814 DEBUG_COMM2("Enter, is_rcv = %d", is_rcv);
815
816 if (is_rcv == 1)
817 { /* Receiving mode */
818 if (*in_len > 0)
819 { /* There are still available data in our buffer */
820 if (*in_len >= proc_len)
821 {
822 /* We only need to get the data from our buffer */
823 memcpy(*rcv_buf, *in_buf, proc_len);
824 *rcv_buf += proc_len;
825 *in_buf += proc_len;
826 *rcv_len += proc_len;
827 *in_len -= proc_len;
828
829 return IFD_SUCCESS;
830 }
831 else
832 {
833 /* Move all data in the input buffer to the reply buffer */
834 remain_len = proc_len - *in_len;
835 memcpy(*rcv_buf, *in_buf, *in_len);
836 *rcv_buf += *in_len;
837 *in_buf += *in_len;
838 *rcv_len += *in_len;
839 *in_len = 0;
840 }
841 }
842 else
843 /* There is no data in our tmp_buf,
844 * we have to read all data we needed */
845 remain_len = proc_len;
846
847 /* Read the expected data from the smartcard */
848 if (*in_len != 0)
849 {
850 DEBUG_CRITICAL("*in_len != 0");
851 return IFD_COMMUNICATION_ERROR;
852 }
853
854 memset(tmp_buf, 0, sizeof(tmp_buf));
855
856 ret_len = remain_len;
857 return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
858 if (return_value != IFD_SUCCESS)
859 return return_value;
860
861 return_value = CCID_Receive(reader_index, &ret_len, tmp_buf);
862 if (return_value != IFD_SUCCESS)
863 return return_value;
864
865 memcpy(*rcv_buf, tmp_buf, remain_len);
866 *rcv_buf += remain_len, *rcv_len += remain_len;
867
868 /* If ret_len != remain_len, our logic is erroneous */
869 if (ret_len != remain_len)
870 {
871 DEBUG_CRITICAL("ret_len != remain_len");
872 return IFD_COMMUNICATION_ERROR;
873 }
874 }
875 else
876 { /* Sending mode */
877
878 return_value = CCID_Transmit(reader_index, proc_len, *snd_buf, 1, 0);
879 if (return_value != IFD_SUCCESS)
880 return return_value;
881
882 *snd_len -= proc_len;
883 *snd_buf += proc_len;
884 }
885
886 DEBUG_COMM("Exit");
887
888 return IFD_SUCCESS;
889 } /* T0ProcACK */
890
891
892 /*****************************************************************************
893 *
894 * T0ProcSW1
895 *
896 ****************************************************************************/
897 static RESPONSECODE T0ProcSW1(unsigned int reader_index,
898 unsigned char *rcv_buf, unsigned int *rcv_len,
899 unsigned char *in_buf, unsigned int in_len)
900 {
901 RESPONSECODE return_value = IFD_SUCCESS;
902 UCHAR tmp_buf[512];
903 unsigned char *rcv_buf_tmp = rcv_buf;
904 const unsigned int rcv_len_tmp = *rcv_len;
905 unsigned char sw1, sw2;
906
907 /* store the SW1 */
908 sw1 = *rcv_buf = *in_buf;
909 rcv_buf++;
910 in_buf++;
911 in_len--;
912 (*rcv_len)++;
913
914 /* store the SW2 */
915 if (0 == in_len)
916 {
917 return_value = CCID_Transmit(reader_index, 0, rcv_buf, 1, 0);
918 if (return_value != IFD_SUCCESS)
919 return return_value;
920
921 in_len = 1;
922
923 return_value = CCID_Receive(reader_index, &in_len, tmp_buf);
924 if (return_value != IFD_SUCCESS)
925 return return_value;
926
927 in_buf = tmp_buf;
928 }
929 sw2 = *rcv_buf = *in_buf;
930 rcv_buf++;
931 in_buf++;
932 in_len--;
933 (*rcv_len)++;
934
935 if (return_value != IFD_SUCCESS)
936 {
937 rcv_buf_tmp[0] = rcv_buf_tmp[1] = 0;
938 *rcv_len = rcv_len_tmp;
939 }
940
941 DEBUG_COMM3("Exit: SW=%02X %02X", sw1, sw2);
942
943 return return_value;
944 } /* T0ProcSW1 */
945
946
947 /*****************************************************************************
948 *
949 * CmdXfrBlockCHAR_T0
950 *
951 ****************************************************************************/
952 static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index,
953 unsigned int snd_len, unsigned char snd_buf[], unsigned int *rcv_len,
954 unsigned char rcv_buf[])
955 {
956 int is_rcv;
957 unsigned char cmd[5];
958 unsigned char tmp_buf[512];
959 unsigned int exp_len, in_len;
960 unsigned char ins, *in_buf;
961 RESPONSECODE return_value = IFD_SUCCESS;
962
963 DEBUG_COMM2("T=0: %d bytes", snd_len);
964
965 in_buf = tmp_buf;
966 in_len = 0;
967 *rcv_len = 0;
968
969 return_value = T0CmdParsing(snd_buf, snd_len, &exp_len);
970 if (return_value != IFD_SUCCESS)
971 {
972 DEBUG_CRITICAL("T0CmdParsing failed");
973 return IFD_COMMUNICATION_ERROR;
974 }
975
976 if (snd_len == 5 || snd_len == 4)
977 is_rcv = 1;
978 else
979 is_rcv = 0;
980
981 /* Command to send to the smart card (must be 5 bytes, from 7816 p.15) */
982 memset(cmd, 0, sizeof(cmd));
983 if (snd_len == 4)
984 {
985 memcpy(cmd, snd_buf, 4);
986 snd_buf += 4;
987 snd_len -= 4;
988 }
989 else
990 {
991 memcpy(cmd, snd_buf, 5);
992 snd_buf += 5;
993 snd_len -= 5;
994 }
995
996 /* Make sure this is a valid command by checking the INS field */
997 ins = cmd[1];
998 if ((ins & 0xF0) == 0x60 || /* 7816-3 8.3.2 */
999 (ins & 0xF0) == 0x90)
1000 {
1001 DEBUG_CRITICAL2("fatal: INS (0x%02X) = 0x6X or 0x9X", ins);
1002 return IFD_COMMUNICATION_ERROR;
1003 }
1004
1005 return_value = CCID_Transmit(reader_index, 5, cmd, 1, 0);
1006 if (return_value != IFD_SUCCESS)
1007 return return_value;
1008
1009 while (1)
1010 {
1011 if (in_len == 0)
1012 {
1013 in_len = 1;
1014 return_value = CCID_Receive(reader_index, &in_len, tmp_buf);
1015 if (return_value != IFD_SUCCESS)
1016 {
1017 DEBUG_CRITICAL("CCID_Receive failed");
1018 return return_value;
1019 }
1020 in_buf = tmp_buf;
1021 }
1022 if (in_len == 0)
1023 {
1024 /* Suppose we should be able to get data.
1025 * If not, error. Set the time-out error */
1026 DEBUG_CRITICAL("error: in_len = 0");
1027 return IFD_RESPONSE_TIMEOUT;
1028 }
1029
1030 /* Start to process the procedure bytes */
1031 if (*in_buf == 0x60)
1032 {
1033 in_len = 0;
1034 return_value = CCID_Transmit(reader_index, 0, cmd, 1, 0);
1035
1036 if (return_value != IFD_SUCCESS)
1037 return return_value;
1038
1039 continue;
1040 }
1041 else if (*in_buf == ins || *in_buf == (ins ^ 0x01))
1042 {
1043 /* ACK => To transfer all remaining data bytes */
1044 in_buf++, in_len--;
1045 if (is_rcv)
1046 return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
1047 &rcv_buf, rcv_len, &in_buf, &in_len, exp_len - *rcv_len, 1);
1048 else
1049 return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
1050 &rcv_buf, rcv_len, &in_buf, &in_len, snd_len, 0);
1051
1052 if (*rcv_len == exp_len)
1053 return return_value;
1054
1055 continue;
1056 }
1057 else if (*in_buf == (ins ^ 0xFF) || *in_buf == (ins ^ 0xFE))
1058 {
1059 /* ACK => To transfer 1 remaining bytes */
1060 in_buf++, in_len--;
1061 return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
1062 &rcv_buf, rcv_len, &in_buf, &in_len, 1, is_rcv);
1063
1064 if (return_value != IFD_SUCCESS)
1065 return return_value;
1066
1067 continue;
1068 }
1069 else if ((*in_buf & 0xF0) == 0x60 || (*in_buf & 0xF0) == 0x90)
1070 /* SW1 */
1071 return T0ProcSW1(reader_index, rcv_buf, rcv_len, in_buf, in_len);
1072
1073 /* Error, unrecognized situation found */
1074 DEBUG_CRITICAL2("Unrecognized Procedure byte (0x%02X) found!", *in_buf);
1075 return return_value;
1076 }
1077
1078 return return_value;
1079 } /* CmdXfrBlockCHAR_T0 */
1080
1081
1082 /*****************************************************************************
1083 *
1084 * CmdXfrBlockTPDU_T1
1085 *
1086 ****************************************************************************/
1087 static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
1088 unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
1089 unsigned char rx_buffer[])
1090 {
1091 RESPONSECODE return_value = IFD_SUCCESS;
1092 int ret;
1093
1094 DEBUG_COMM2("T=1: %d bytes", tx_length);
1095
1096 ret = t1_transceive(&((get_ccid_slot(reader_index)) -> t1), 0,
1097 tx_buffer, tx_length, rx_buffer, *rx_length);
1098
1099 if (ret < 0)
1100 {
1101 *rx_length = 0;
1102 return_value = IFD_COMMUNICATION_ERROR;
1103 }
1104 else
1105 *rx_length = ret;
1106
1107 return return_value;
1108 } /* CmdXfrBlockTPDU_T1 */
1109
1110
1111 /*****************************************************************************
1112 *
1113 * SetParameters
1114 *
1115 ****************************************************************************/
1116 RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
1117 unsigned int length, unsigned char buffer[])
1118 {
1119 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
1120 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
1121
1122 DEBUG_COMM2("length: %d bytes", length);
1123
1124 cmd[0] = 0x61; /* SetParameters */
1125 i2dw(length, cmd+1); /* APDU length */
1126 cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
1127 cmd[6] = (*ccid_descriptor->pbSeq)++;
1128 cmd[7] = protocol; /* bProtocolNum */
1129 cmd[8] = cmd[9] = 0; /* RFU */
1130
1131 /* check that the command is not too large */
1132 if (length > CMD_BUF_SIZE)
1133 return IFD_NOT_SUPPORTED;
1134
1135 memcpy(cmd+10, buffer, length);
1136
1137 if (WritePort(reader_index, 10+length, cmd) != STATUS_SUCCESS)
1138 return IFD_COMMUNICATION_ERROR;
1139
1140 length = sizeof(cmd);
1141 if (ReadPort(reader_index, &length, cmd) != STATUS_SUCCESS)
1142 return IFD_COMMUNICATION_ERROR;
1143
1144 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
1145 {
1146 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
1147 if (0x00 == cmd[ERROR_OFFSET]) /* command not supported */
1148 return IFD_NOT_SUPPORTED;
1149 else
1150 return IFD_COMMUNICATION_ERROR;
1151 }
1152
1153 return IFD_SUCCESS;
1154 } /* SetParameters */
1155
1156
1157 /*****************************************************************************
1158 *
1159 * isCharLevel
1160 *
1161 ****************************************************************************/
1162 int isCharLevel(int reader_index)
1163 {
1164 return CCID_CLASS_CHARACTER == (get_ccid_descriptor(reader_index)->dwFeatures & CCID_CLASS_EXCHANGE_MASK);
1165 } /* isCharLevel */
1166
1167
1168 /*****************************************************************************
1169 *
1170 * i2dw
1171 *
1172 ****************************************************************************/
1173 static void i2dw(int value, unsigned char buffer[])
1174 {
1175 buffer[0] = value & 0xFF;
1176 buffer[1] = (value >> 8) & 0xFF;
1177 buffer[2] = (value >> 16) & 0xFF;
1178 buffer[3] = (value >> 24) & 0xFF;
1179 } /* i2dw */
1180

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5