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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5