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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5