* ccid-driver.c: More work, data can now actually be retrieved.
[gnupg.git] / scd / ccid-driver.c
1 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
2  *      Copyright (C) 2003 Free Software Foundation, Inc.
3  *      Written by Werner Koch.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  *
21  * ALTERNATIVELY, this file may be distributed under the terms of the
22  * following license, in which case the provisions of this license are
23  * required INSTEAD OF the GNU General Public License. If you wish to
24  * allow use of your version of this file only under the terms of the
25  * GNU General Public License, and not to allow others to use your
26  * version of this file under the terms of the following license,
27  * indicate your decision by deleting this paragraph and the license
28  * below.
29  *
30  * Redistribution and use in source and binary forms, with or without
31  * modification, are permitted provided that the following conditions
32  * are met:
33  * 1. Redistributions of source code must retain the above copyright
34  *    notice, and the entire permission notice in its entirety,
35  *    including the disclaimer of warranties.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. The name of the author may not be used to endorse or promote
40  *    products derived from this software without specific prior
41  *    written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
44  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
47  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
48  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
49  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
51  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
53  * OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55
56
57 /* CCID (ChipCardInterfaceDevices) is a specification for accessing
58    smartcard via a reader connected to the USB.  
59
60    This is a limited driver allowing to use some CCID drivers directly
61    without any other specila drivers. This is a fallback driver to be
62    used when nothing else works or the system should be kept minimal
63    for security reasons.  It makes use of the libusb library to gain
64    portable access to USB.
65
66    This driver has been tested with the SCM SCR335 smartcard reader
67    and requires that reader implements the TPDU level exchange and
68    does fully automatic initialization.
69 */
70
71 #ifdef HAVE_CONFIG_H
72 # include <config.h>
73 #endif
74
75 #if defined(HAVE_LIBUSB) || defined(TEST)
76
77 #include <errno.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include <assert.h>
82
83 #include <usb.h>
84
85 #include "ccid-driver.h"
86
87 #define DRVNAME "ccid-driver: "
88
89
90 #ifdef GNUPG_DEFAULT_SCDAEMON /* This source is used within the
91                                  gnupg>=1.9 source tree. */
92 # include "scdaemon.h"
93
94 # define DEBUGOUT(t)         do { if (DBG_CARD_IO) \
95                                   log_debug (DRVNAME t); } while (0)
96 # define DEBUGOUT_1(t,a)     do { if (DBG_CARD_IO) \
97                                   log_debug (DRVNAME t,(a)); } while (0)
98 # define DEBUGOUT_2(t,a,b)   do { if (DBG_CARD_IO) \
99                                   log_debug (DRVNAME t,(a),(b)); } while (0)
100 # define DEBUGOUT_3(t,a,b,c) do { if (DBG_CARD_IO) \
101                                   log_debug (DRVNAME t,(a),(b),(c));} while (0)
102 # define DEBUGOUT_CONT_1(t,a)  do { if (DBG_CARD_IO) \
103                                   log_printf (t,(a)); } while (0)
104 # define DEBUGOUT_CONT_3(t,a,b,c) do { if (DBG_CARD_IO) \
105                                   log_printf (t,(a),(b),(c)); } while (0)
106 # define DEBUGOUT_LF()       do { if (DBG_CARD_IO) \
107                                   log_printf ("\n"); } while (0)
108
109 #else /* Other usage of this source - don't use gnupg specifics. */
110
111 # define DEBUGOUT(t)          fprintf (stderr, DRVNAME t)
112 # define DEBUGOUT_1(t,a)      fprintf (stderr, DRVNAME t, (a))
113 # define DEBUGOUT_2(t,a,b)    fprintf (stderr, DRVNAME t, (a), (b))
114 # define DEBUGOUT_3(t,a,b,c)  fprintf (stderr, DRVNAME t, (a), (b), (c))
115 # define DEBUGOUT_CONT_1(t,a)      fprintf (stderr, t, (a))
116 # define DEBUGOUT_CONT_3(t,a,b,c)  fprintf (stderr, t, (a), (b), (c))
117 # define DEBUGOUT_LF()        putc ('\n', stderr)
118
119 #endif /* This source not used by scdaemon. */
120
121
122 enum {
123   RDR_to_PC_NotifySlotChange= 0x50,
124   RDR_to_PC_HardwareError   = 0x51,
125
126   PC_to_RDR_SetParameters   = 0x61,
127   PC_to_RDR_IccPowerOn      = 0x62,
128   PC_to_RDR_IccPowerOff     = 0x63,
129   PC_to_RDR_GetSlotStatus   = 0x65,
130   PC_to_RDR_Secure          = 0x69,
131   PC_to_RDR_T0APDU          = 0x6a,
132   PC_to_RDR_Escape          = 0x6b,
133   PC_to_RDR_GetParameters   = 0x6c,
134   PC_to_RDR_ResetParameters = 0x6d,
135   PC_to_RDR_IccClock        = 0x6e,
136   PC_to_RDR_XfrBlock        = 0x6f,
137   PC_to_RDR_Mechanical      = 0x71,
138   PC_to_RDR_Abort           = 0x72,
139   PC_to_RDR_SetDataRate     = 0x73,
140
141   RDR_to_PC_DataBlock       = 0x80,
142   RDR_to_PC_SlotStatus      = 0x81,
143   RDR_to_PC_Parameters      = 0x82,
144   RDR_to_PC_Escape          = 0x83,
145   RDR_to_PC_DataRate        = 0x84
146 };
147
148
149 /* Store information on the driver's state.  A pointer to such a
150    structure is used as handle for most functions. */
151 struct ccid_driver_s {
152   usb_dev_handle *idev;
153   int seqno;
154   unsigned char t1_ns;
155   unsigned char t1_nr;
156 };
157
158
159
160
161 /* Open the reader with the internal number READERNO and return a a
162    pointer to be used as handle in HANDLE.  Returns 0 on success. */
163 int 
164 ccid_open_reader (ccid_driver_t *handle, int readerno)
165 {
166   static int initialized;
167
168   int rc;
169   usb_match_handle *match = NULL;
170   struct usb_device *dev = NULL;
171   usb_dev_handle *idev = NULL;
172
173   *handle = NULL;
174   if (!initialized)
175     {
176       usb_init ();
177       initialized = 1;
178     }
179   
180   rc = usb_create_match (&match, -1, -1, 11, -1, -1);
181   if (rc)
182     {
183       DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
184       return -1;
185     }
186
187   while (usb_find_device(match, dev, &dev) >= 0) 
188     {
189       DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
190                   dev->descriptor->idVendor, dev->descriptor->idProduct);
191       if (!readerno)
192         {
193           rc = usb_open (dev, &idev);
194           if (rc)
195             {
196               DEBUGOUT_1 ("usb_open failed: %d\n", rc);
197               goto leave;
198             }
199
200           rc = usb_claim_interface (idev, 0);
201           if (rc)
202             {
203               DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
204               goto leave;
205             }
206
207           *handle = calloc (1, sizeof **handle);
208           if (!*handle)
209             {
210               DEBUGOUT ("out of memory\n");
211               rc = -1;
212               goto leave;
213             }
214           (*handle)->idev = idev;
215           idev = NULL;
216           break;
217         }
218       readerno--;
219     }
220
221
222  leave:
223   if (idev)
224     usb_close (idev);
225   /* fixme: Do we need to release dev or is it supposed to be a
226      shallow copy of the list created internally by usb_init ? */
227   usb_free_match (match);
228
229   return rc;
230 }
231
232
233 /* Return False if a card is present and powered. */
234 int
235 ccid_check_card_presence (ccid_driver_t handle)
236 {
237
238   return -1;
239 }
240
241
242 static void
243 set_msg_len (unsigned char *msg, unsigned int length)
244 {
245   msg[1] = length;
246   msg[2] = length >> 8;
247   msg[3] = length >> 16;
248   msg[4] = length >> 24;
249 }
250
251
252 /* Write a MSG of length MSGLEN to the designated bulk out endpoint.
253    Returns 0 on success. */
254 static int
255 bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
256 {
257   int rc;
258
259   rc = usb_bulk_write (handle->idev, 
260                        1, /*endpoint */
261                        msg, msglen,
262                        1000 /* ms timeout */);
263   if (rc == msglen)
264     return 0;
265
266   if (rc == -1)
267     DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
268   else
269     DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
270   return -1;
271 }
272
273
274 /* Read a maximum of LENGTH bytes from the bulk in endpoint into
275    BUFFER and return the actual read number if bytes in NREAD. SEQNO
276    is the sequence number used to send the request and EXPECTED_TYPE
277    the type of message we expect. Does checks on the ccid
278    header. Returns 0 on success. */
279 static int
280 bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
281          size_t *nread, int expected_type, int seqno)
282 {
283   int i, rc;
284   size_t msglen;
285
286   rc = usb_bulk_read (handle->idev, 
287                       0x82,
288                       buffer, length,
289                       1000 /* ms timeout */ );
290   if (rc < 0)
291     {
292       DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
293       return -1;
294     }
295
296   *nread = msglen = rc;
297
298   if (msglen < 10)
299     {
300       DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
301       return -1;
302     }
303   if (buffer[0] != expected_type)
304     {
305       DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
306       return -1;
307     }
308   if (buffer[5] != 0)    
309     {
310       DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
311       return -1;
312     }
313   if (buffer[6] != seqno)    
314     {
315       DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
316                   seqno, buffer[6]);
317       return -1;
318     }
319
320   DEBUGOUT_3 ("status: %02X  error: %02X clock-status: %02X\n"
321               "               data:",  buffer[7], buffer[8], buffer[9] );
322   for (i=10; i < msglen; i++)
323     DEBUGOUT_CONT_1 (" %02X", buffer[i]);
324   DEBUGOUT_LF ();
325
326   return 0;
327 }
328
329
330 /* experimental */
331 int
332 ccid_poll (ccid_driver_t handle)
333 {
334   int rc;
335   unsigned char msg[10];
336   size_t msglen;
337   int i, j;
338
339   rc = usb_bulk_read (handle->idev, 
340                       0x83,
341                       msg, sizeof msg,
342                       0 /* ms timeout */ );
343   if (rc < 0 && errno == ETIMEDOUT)
344     return 0;
345
346   if (rc < 0)
347     {
348       DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
349       return -1;
350     }
351
352   msglen = rc;
353   rc = 0;
354
355   if (msglen < 1)
356     {
357       DEBUGOUT ("intr-in msg too short\n");
358       return -1;
359     }
360
361   if (msg[0] == RDR_to_PC_NotifySlotChange)
362     {
363       DEBUGOUT ("notify slot change:");
364       for (i=1; i < msglen; i++)
365         for (j=0; j < 4; j++)
366           DEBUGOUT_CONT_3 (" %d:%c%c",
367                            (i-1)*4+j, 
368                            (msg[i] & (1<<(j*2)))? 'p':'-',
369                            (msg[i] & (2<<(j*2)))? '*':' ');
370       DEBUGOUT_LF ();
371     }
372   else if (msg[0] == RDR_to_PC_HardwareError)    
373     {
374       DEBUGOUT ("hardware error occured\n");
375     }
376   else
377     {
378       DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
379     }
380
381   return 0;
382 }
383
384
385
386 int 
387 ccid_slot_status (ccid_driver_t handle)
388 {
389   int rc;
390   unsigned char msg[100];
391   size_t msglen;
392   unsigned char seqno;
393
394   msg[0] = PC_to_RDR_GetSlotStatus;
395   msg[5] = 0; /* slot */
396   msg[6] = seqno = handle->seqno++;
397   msg[7] = 0; /* RFU */
398   msg[8] = 0; /* RFU */
399   msg[9] = 0; /* RFU */
400   set_msg_len (msg, 0);
401
402   rc = bulk_out (handle, msg, 10);
403   if (rc)
404     return rc;
405   rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
406   if (rc)
407     return rc;
408
409   return 0;
410 }
411
412
413 int 
414 ccid_get_atr (ccid_driver_t handle,
415               unsigned char *atr, size_t maxatrlen, size_t *atrlen)
416 {
417   int rc;
418   unsigned char msg[100];
419   size_t msglen;
420   unsigned char seqno;
421
422   msg[0] = PC_to_RDR_IccPowerOn;
423   msg[5] = 0; /* slot */
424   msg[6] = seqno = handle->seqno++;
425   msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
426   msg[8] = 0; /* RFU */
427   msg[9] = 0; /* RFU */
428   set_msg_len (msg, 0);
429   msglen = 10;
430
431   rc = bulk_out (handle, msg, msglen);
432   if (rc)
433     return rc;
434   rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
435   if (rc)
436     return rc;
437   
438   if (atr)
439     {
440       size_t n = msglen - 10;
441
442       if (n > maxatrlen)
443         n = maxatrlen;
444       memcpy (atr, msg+10, n);
445       *atrlen = n;
446     }
447
448   return 0;
449 }
450
451
452 \f
453 /*
454   Protocol T=1 overview
455
456   Block Structure:
457            Prologue Field:
458    1 byte     Node Address (NAD) 
459    1 byte     Protocol Control Byte (PCB)
460    1 byte     Length (LEN) 
461            Information Field:
462    0-254 byte APDU or Control Information (INF)
463            Epilogue Field:
464    1 byte     Error Detection Code (EDC)
465
466   NAD:  
467    bit 7     unused
468    bit 4..6  Destination Node Address (DAD)
469    bit 3     unused
470    bit 2..0  Source Node Address (SAD)
471
472    If node adresses are not used, SAD and DAD should be set to 0 on
473    the first block sent to the card.  If they are used they should
474    have different values (0 for one is okay); that first block sets up
475    the addresses of the nodes.
476
477   PCB:
478    Information Block (I-Block):
479       bit 7    0
480       bit 6    Sequence number (yep, that is modulo 2)
481       bit 5    Chaining flag 
482       bit 4..0 reserved
483    Received-Ready Block (R-Block):
484       bit 7    1
485       bit 6    0
486       bit 5    0
487       bit 4    Sequence number
488       bit 3..0  0 = no error
489                 1 = EDC or parity error
490                 2 = other error
491                 other values are reserved
492    Supervisory Block (S-Block):
493       bit 7    1
494       bit 6    1
495       bit 5    clear=request,set=response
496       bit 4..0  0 = resyncronisation request
497                 1 = information field size request
498                 2 = abort request
499                 3 = extension of BWT request
500                 4 = VPP error
501                 other values are reserved
502
503 */
504
505 int
506 ccid_transceive (ccid_driver_t handle,
507                  const unsigned char *apdu, size_t apdulen,
508                  unsigned char *resp, size_t maxresplen, size_t *nresp)
509 {
510   int rc;
511   unsigned char send_buffer[10+258], recv_buffer[10+258];
512   unsigned char *msg, *tpdu, *p;
513   size_t msglen, tpdulen, n;
514   unsigned char seqno;
515   int i;
516   unsigned char crc;
517   size_t dummy_nresp;
518   int sending = 1;
519
520   if (!nresp)
521     nresp = &dummy_nresp;
522
523   *nresp = 0;
524   
525   /* Construct an I-Block. */
526   if (apdulen > 254)
527     return -1; /* Invalid length. */
528
529   msg = send_buffer;
530
531   tpdu = msg+10;
532   tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
533   tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
534   tpdu[2] = apdulen;
535   memcpy (tpdu+3, apdu, apdulen);
536   crc = 0;
537   for (i=0,p=tpdu; i < apdulen+3; i++)
538     crc ^= *p++;
539   tpdu[3+apdulen] = crc;
540
541   tpdulen = apdulen + 4;
542
543   for (;;)
544     {
545       msg[0] = PC_to_RDR_XfrBlock;
546       msg[5] = 0; /* slot */
547       msg[6] = seqno = handle->seqno++;
548       msg[7] = 4; /* bBWI */
549       msg[8] = 0; /* RFU */
550       msg[9] = 0; /* RFU */
551       set_msg_len (msg, tpdulen);
552       msglen = 10 + tpdulen;
553
554       DEBUGOUT ("sending");
555       for (i=0; i < msglen; i++)
556         DEBUGOUT_CONT_1 (" %02X", msg[i]);
557       DEBUGOUT_LF ();
558       
559       fprintf (stderr, "T1: put %c-block seq=%d\n",
560                ((msg[11] & 0xc0) == 0x80)? 'R' :
561                (msg[11] & 0x80)? 'S' : 'I',
562         ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
563   
564       rc = bulk_out (handle, msg, msglen);
565       if (rc)
566         return rc;
567
568       msg = recv_buffer;
569       rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
570                     RDR_to_PC_DataBlock, seqno);
571       if (rc)
572         return rc;
573       
574       tpdu = msg + 10;
575       tpdulen = msglen - 10;
576       
577       if (tpdulen < 4) 
578         {
579           DEBUGOUT ("cannot yet handle short block!!\n");
580           return -1; 
581         }
582
583       fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
584                ((msg[11] & 0xc0) == 0x80)? 'R' :
585                (msg[11] & 0x80)? 'S' : 'I',
586         ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
587                ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
588                );
589
590       if (!(tpdu[1] & 0x80))
591         { /* This is an I-block. */
592           
593           if (sending)
594             { /* last block sent was successful. */
595               handle->t1_ns ^= 1;
596               sending = 0;
597             }
598
599           if (!!(tpdu[1] & 0x40) != handle->t1_nr)
600             { /* Reponse does not match our sequence number. */
601               msg = send_buffer;
602               tpdu = msg+10;
603               tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
604               tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4 | 2); /* R-block */
605               tpdu[2] = 0;
606               tpdulen = 3;
607               for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
608                 crc ^= *p++;
609               tpdu[tpdulen++] = crc;
610
611               continue;
612             }
613
614           handle->t1_nr ^= 1;
615
616           p = tpdu + 3; /* Skip the prologue field. */
617           n = tpdulen - 3 - 1; /* Strip the epilogue field. */
618           /* fixme: verify the checksum. */
619           if (resp)
620             {
621               if (n > maxresplen)
622                 {
623                   DEBUGOUT ("provided buffer too short for received data\n");
624                   return -1;
625                 }
626               
627               memcpy (resp, p, n); 
628               resp += n;
629               *nresp += n;
630               maxresplen -= n;
631             }
632           
633           if (!(tpdu[1] & 0x20))
634             return 0; /* No chaining requested - ready. */
635           
636           msg = send_buffer;
637           tpdu = msg+10;
638           tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
639           tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4); /* R-block */
640           tpdu[2] = 0;
641           tpdulen = 3;
642           for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
643             crc ^= *p++;
644           tpdu[tpdulen++] = crc;
645           
646         }
647       else if ((tpdu[1] & 0xc0) == 0x80)
648         { /* This is a R-block. */
649           if ( (tpdu[1] & 0x0f)) 
650             { /* Error: repeat last block */
651               msg = send_buffer;
652             }
653           else
654             {
655               DEBUGOUT ("unxpectec ACK R-block received\n");
656               return -1;
657             }
658         }
659       else 
660         { /* This is a S-block. */
661           DEBUGOUT_2 ("T1 S-block %s received cmd=%d\n",
662                       (tpdu[1] & 0x20)? "response": "request",
663                       (tpdu[1] & 0x1f));
664           if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
665             { /* Wait time extension request. */
666               unsigned char bwi = tpdu[3];
667               msg = send_buffer;
668               tpdu = msg+10;
669               tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
670               tpdu[1] = (0xc0 | 0x20 | 3); /* S-block response */
671               tpdu[2] = 1;
672               tpdu[3] = bwi;
673               tpdulen = 4;
674               for (crc=0,i=0,p=tpdu; i < tpdulen; i++)
675                 crc ^= *p++;
676               tpdu[tpdulen++] = crc;
677               DEBUGOUT_1 ("T1 waittime extension of bwi=%d\n", bwi);
678             }
679           else
680             return -1;
681         }
682     } /* end T=1 protocol loop. */
683
684   return 0;
685 }
686
687
688
689
690 #ifdef TEST
691 int
692 main (int argc, char **argv)
693 {
694   int rc;
695   ccid_driver_t ccid;
696
697   rc = ccid_open_reader (&ccid, 0);
698   if (rc)
699     return 1;
700
701   ccid_poll (ccid);
702   fputs ("getting ATR ...\n", stderr);
703   rc = ccid_get_atr (ccid, NULL, 0, NULL);
704   if (rc)
705     return 1;
706
707   ccid_poll (ccid);
708   fputs ("getting slot status ...\n", stderr);
709   rc = ccid_slot_status (ccid);
710   if (rc)
711     return 1;
712
713   ccid_poll (ccid);
714
715   {
716     static unsigned char apdu[] = {
717       0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01};
718   rc = ccid_transceive (ccid,
719                         apdu, sizeof apdu,
720                         NULL, 0, NULL);
721   }
722   ccid_poll (ccid);
723
724   {
725     static unsigned char apdu[] = {
726       0, 0xCA, 0, 0x65, 254 };
727   rc = ccid_transceive (ccid,
728                         apdu, sizeof apdu,
729                         NULL, 0, NULL);
730   }
731   ccid_poll (ccid);
732
733
734   return 0;
735 }
736
737 /*
738  * Local Variables:
739  *  compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
740  * End:
741  */
742 #endif /*TEST*/
743 #endif /*HAVE_LIBUSB*/