* scdaemon.c: New options --print-atr and --reader-port
[gnupg.git] / scd / apdu.c
1 /* apdu.c - ISO 7816 APDU functions and low level I/O
2  *      Copyright (C) 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <dlfcn.h>
27
28 #include "scdaemon.h"
29 #include "apdu.h"
30
31 #define HAVE_CTAPI 1
32
33 #define MAX_READER 4 /* Number of readers we support concurrently. */
34 #define CARD_CONNECT_TIMEOUT 30 /* Number of seconds to wait for
35                                    insertion of the card. */
36
37
38
39 /* A global table to keep track of active readers. */
40 static struct {
41   int used;            /* True if slot is used. */
42   unsigned short port; /* port number0 = unused, 1 - dev/tty */
43   int status;
44   unsigned char atr[33];
45   size_t atrlen;
46 } reader_table[MAX_READER];                          
47
48
49 /* ct API function pointer. */
50 static char (*CT_init) (unsigned short ctn, unsigned short Pn);
51 static char (*CT_data) (unsigned short ctn, unsigned char *dad,
52                         unsigned char *sad, unsigned short lc,
53                         unsigned char *cmd, unsigned short *lr,
54                         unsigned char *rsp);
55 static char (*CT_close) (unsigned short ctn);
56
57
58
59
60 \f
61 /* 
62       Helper
63  */
64  
65
66 /* Find an unused reader slot for PORT and put it into the reader
67    table.  Return -1 on error or the index into the reader table. */
68 static int 
69 new_reader_slot (int port)    
70 {
71   int i, reader = -1;
72
73   if (port < 0 || port > 0xffff)
74     {
75       log_error ("new_reader_slot: invalid port %d requested\n", port);
76       return -1;
77     }
78
79   for (i=0; i < MAX_READER; i++)
80     {
81       if (reader_table[i].used && reader_table[i].port == port)
82         {
83           log_error ("new_reader_slot: requested port %d already in use\n",
84                      reader);
85           return -1; 
86         }
87       else if (!reader_table[i].used && reader == -1)
88         reader = i;
89     }
90   if (reader == -1)
91     {
92       log_error ("new_reader_slot: out of slots\n");
93       return -1;
94     }
95   reader_table[reader].used = 1;
96   reader_table[reader].port = port;
97   return reader;
98 }
99
100
101 static void
102 dump_reader_status (int reader)
103 {
104   log_info ("reader %d: %s\n", reader,
105             reader_table[reader].status == 1? "Processor ICC present" :
106             reader_table[reader].status == 0? "Memory ICC present" :
107                                               "ICC not present" );
108  
109   if (reader_table[reader].status != -1)
110     {
111       log_info ("reader %d: ATR=", reader);
112       log_printhex ("", reader_table[reader].atr,
113                     reader_table[reader].atrlen);
114     }
115 }
116
117
118 \f
119 #ifdef HAVE_CTAPI
120 /* 
121        ct API Interface 
122  */
123
124 static const char *
125 ct_error_string (int err)
126 {
127   switch (err)
128     {
129     case 0: return "okay";
130     case -1: return "invalid data";
131     case -8: return "ct error";
132     case -10: return "transmission error";
133     case -11: return "memory allocation error";
134     case -128: return "HTSI error";
135     default: return "unknown CT-API error";
136     }
137 }
138
139 /* Wait for the card in READER and activate it.  Return -1 on error or
140    0 on success. */
141 static int
142 ct_activate_card (int reader)
143 {
144   int rc, count;
145
146   for (count = 0; count < CARD_CONNECT_TIMEOUT; count++)
147     {
148       unsigned char dad[1], sad[1], cmd[11], buf[256];
149       unsigned short buflen;
150
151       /* Check whether card has been inserted. */
152       dad[0] = 1;     /* Destination address: CT. */    
153       sad[0] = 2;     /* Source address: Host. */
154
155       cmd[0] = 0x20;  /* Class byte. */
156       cmd[1] = 0x13;  /* Request status. */
157       cmd[2] = 0x00;  /* From kernel. */
158       cmd[3] = 0x80;  /* Return card's DO. */
159       cmd[4] = 0x00;
160
161       buflen = DIM(buf);
162
163       rc = CT_data (reader, dad, sad, 5, cmd, &buflen, buf);
164       if (rc || buflen < 2 || buf[buflen-2] != 0x90)
165         {
166           log_error ("ct_activate_card: can't get status of reader %d: %s\n",
167                      reader, ct_error_string (rc));
168           return -1;
169         }
170
171       if (buf[0] == 0x05)
172         { /* Connected, now activate the card. */           
173           dad[0] = 1;    /* Destination address: CT. */    
174           sad[0] = 2;    /* Source address: Host. */
175
176           cmd[0] = 0x20;  /* Class byte. */
177           cmd[1] = 0x12;  /* Request ICC. */
178           cmd[2] = 0x01;  /* From first interface. */
179           cmd[3] = 0x01;  /* Return card's ATR. */
180           cmd[4] = 0x00;
181
182           buflen = DIM(buf);
183
184           rc = CT_data (reader, dad, sad, 5, cmd, &buflen, buf);
185           if (rc || buflen < 2 || buf[buflen-2] != 0x90)
186             {
187               log_error ("ct_activate_card(%d): activation failed: %s\n",
188                          reader, ct_error_string (rc));
189               return -1;
190             }
191
192           /* Store the type and the ATR. */
193           if (buflen - 2 > DIM (reader_table[0].atr))
194             {
195               log_error ("ct_activate_card(%d): ATR too long\n", reader);
196               return -1;
197             }
198
199           reader_table[reader].status = buf[buflen - 1];
200           memcpy (reader_table[reader].atr, buf, buflen - 2);
201           reader_table[reader].atrlen = buflen - 2;
202           return 0;
203         }
204
205       sleep (1); /* FIXME: we should use a more reliable timer. */
206     }
207  
208   log_info ("ct_activate_card(%d): timeout waiting for card\n", reader);
209   return -1;
210 }
211
212
213 /* Open a reader and return an internal handle for it.  PORT is a
214    non-negative value with the port number of the reader. USB readers
215    do habe port numbers starting at 32769. */
216 static int
217 open_ct_reader (int port)
218 {
219   int rc, reader;
220
221   reader = new_reader_slot (port);
222   if (reader == -1)
223     return reader;
224
225   rc = CT_init (reader, (unsigned short)port);
226   if (rc)
227     {
228       log_error ("apdu_open_ct_reader failed on port %d: %s\n",
229                  port, ct_error_string (rc));
230       reader_table[reader].used = 0;
231       return -1;
232     }
233
234   rc = ct_activate_card (reader);
235   if (rc)
236     {
237       reader_table[reader].used = 0;
238       return -1;
239     }
240
241   dump_reader_status (reader);
242   return reader;
243 }
244
245
246 #endif /*HAVE_CTAPI*/
247
248 \f
249 #ifdef HAVE_PCSC
250 /* 
251        PC/SC Interface
252  */
253
254
255 #endif /*HAVE_PCSC*/
256
257 \f
258 /* 
259        Driver Access
260  */
261
262 /* Open the reader and return an internal slot number or -1 on
263    error. */
264 int
265 apdu_open_reader (int port)
266 {
267   static int ct_api_loaded;
268
269   if (!ct_api_loaded)
270     {
271       void *handle;
272
273       handle = dlopen ("libtowitoko.so", RTLD_LAZY);
274       if (!handle)
275         {
276           log_error ("apdu_open_reader: failed to open driver: %s",
277                      dlerror ());
278           return -1;
279         }
280       CT_init = dlsym (handle, "CT_init");
281       CT_data = dlsym (handle, "CT_data");
282       CT_close = dlsym (handle, "CT_close");
283       if (!CT_init || !CT_data || !CT_close)
284         {
285           log_error ("apdu_open_reader: invalid driver\n");
286           dlclose (handle);
287           return -1;
288         }
289       ct_api_loaded = 1;
290     }
291   return open_ct_reader (port);
292 }
293
294
295
296
297
298
299