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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5