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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5