Updated FSF's address.
[gnupg.git] / scd / atr.c
1 /* atr.c - ISO 7816 ATR fucntions
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "scdaemon.h"
30 #include "apdu.h"
31 #include "atr.h"
32 #include "dynload.h"
33
34 static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
35                                   -1, 512, 768, 1024, 1536, 2048, -1, -1 };
36 static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
37                                   0, -1, -2, -4, -8, -16, -32, -64};
38                                   
39
40 /* Dump the ATR of the card at SLOT in a human readable format to
41    stream FP.  */
42 int
43 atr_dump (int slot, FILE *fp)
44 {
45   unsigned char *atrbuffer, *atr;
46   size_t atrlen;
47   int have_ta, have_tb, have_tc, have_td;
48   int n_historical;
49   int idx, val;
50   unsigned char chksum;
51
52   atr = atrbuffer = apdu_get_atr (slot, &atrlen);
53   if (!atr)
54     return gpg_error (GPG_ERR_GENERAL);
55   
56   fprintf (fp, "Info on ATR of length %u at slot %d\n",
57            (unsigned int)atrlen, slot);
58   if (!atrlen)
59     {
60       fprintf (fp, "error: empty ATR\n");
61       goto bailout;
62     }
63
64   
65   if (*atr == 0x3b)
66     fputs ("direct convention\n", fp);
67   else if (*atr == 0x3f)
68     fputs ("inverse convention\n", fp);
69   else
70     fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
71   if (!--atrlen)
72     goto bailout;
73   atr++;
74
75   chksum = *atr;
76   for (idx=1; idx < atrlen-1; idx++)
77     chksum ^= atr[idx];
78
79   have_ta = !!(*atr & 0x10);
80   have_tb = !!(*atr & 0x20);
81   have_tc = !!(*atr & 0x40);
82   have_td = !!(*atr & 0x80);
83   n_historical = (*atr & 0x0f);
84   fprintf (fp, "%d historical characters indicated\n", n_historical);
85
86   if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
87     fputs ("error: ATR shorter than indicated by format character\n", fp);
88   if (!--atrlen)
89     goto bailout;
90   atr++;
91
92   if (have_ta)
93     {
94       fputs ("TA1: F=", fp);
95       val = fi_table[(*atr >> 4) & 0x0f];
96       if (!val)
97         fputs ("internal clock", fp);
98       else if (val == -1)
99         fputs ("RFU", fp);
100       else
101         fprintf (fp, "%d", val);
102       fputs (" D=", fp);
103       val = di_table[*atr & 0x0f]; 
104       if (!val)
105         fputs ("[impossible value]\n", fp);
106       else if (val == -1)
107         fputs ("RFU\n", fp);
108       else if (val < 0 )
109         fprintf (fp, "1/%d\n", val);
110       else 
111         fprintf (fp, "%d\n", val);
112       
113       if (!--atrlen)
114         goto bailout;
115       atr++;
116     }
117      
118   if (have_tb)
119     {
120       fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
121                (*atr & 0x80)? " [high bit not cleared]":"");
122       if (!--atrlen)
123         goto bailout;
124       atr++;
125     }
126
127   if (have_tc)
128     {
129       if (*atr == 255)
130         fputs ("TC1: guard time shortened to 1 etu\n", fp);
131       else
132         fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
133
134       if (!--atrlen)
135         goto bailout;
136       atr++;
137     }
138
139   if (have_td)
140     {
141       have_ta = !!(*atr & 0x10);
142       have_tb = !!(*atr & 0x20);
143       have_tc = !!(*atr & 0x40);
144       have_td = !!(*atr & 0x80);
145       fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
146
147       if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
148         fputs ("error: ATR shorter than indicated by format character\n", fp);
149
150       if (!--atrlen)
151         goto bailout;
152       atr++;
153     }
154   else
155     have_ta = have_tb = have_tc = have_td = 0;
156
157   if (have_ta)
158     {
159       fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
160                (*atr & 0x80)? "no-":"",
161                (*atr & 0x10)? "im": "ex",
162                (*atr & 0x0f));
163       if ((*atr & 0x60))
164         fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
165       if (!--atrlen)
166         goto bailout;
167       atr++;
168     }
169
170   if (have_tb)
171     {
172       fprintf (fp, "TB2: PI2=%d\n", *atr);
173       if (!--atrlen)
174         goto bailout;
175       atr++;
176     }
177
178   if (have_tc)
179     {
180       fprintf (fp, "TC2: PWI=%d\n", *atr);
181       if (!--atrlen)
182         goto bailout;
183       atr++;
184     }
185
186   if (have_td)
187     {
188       have_ta = !!(*atr & 0x10);
189       have_tb = !!(*atr & 0x20);
190       have_tc = !!(*atr & 0x40);
191       have_td = !!(*atr & 0x80);
192       fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
193
194       if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
195         fputs ("error: ATR shorter than indicated by format character\n", fp);
196
197       if (!--atrlen)
198         goto bailout;
199       atr++;
200     }
201   else
202     have_ta = have_tb = have_tc = have_td = 0;
203
204   for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
205     {
206       if (have_ta)
207         {
208           fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
209           if (!--atrlen)
210             goto bailout;
211           atr++;
212         }
213
214       if (have_tb)
215         {
216           fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
217                    idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
218           if (!--atrlen)
219             goto bailout;
220           atr++;
221         }
222
223       if (have_tc)
224         {
225           fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
226           if (!--atrlen)
227             goto bailout;
228           atr++;
229         }
230
231       if (have_td)
232         {
233           have_ta = !!(*atr & 0x10);
234           have_tb = !!(*atr & 0x20);
235           have_tc = !!(*atr & 0x40);
236           have_td = !!(*atr & 0x80);
237           fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
238
239           if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
240             fputs ("error: ATR shorter than indicated by format character\n",
241                    fp);
242
243           if (!--atrlen)
244             goto bailout;
245           atr++;
246         }
247       else
248         have_ta = have_tb = have_tc = have_td = 0;
249     }
250
251   if (n_historical + 1 > atrlen)
252     fputs ("error: ATR shorter than required for historical bytes "
253            "and checksum\n", fp);
254   
255   if (n_historical)
256     {
257       fputs ("Historical:", fp);
258       for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
259         fprintf (fp, " %02X", *atr);
260       putchar ('\n');
261     }
262
263   if (!atrlen)
264     fputs ("error: checksum missing\n", fp);
265   else if (*atr == chksum)
266     fprintf (fp, "TCK: %02X (good)\n", *atr);
267   else
268     fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
269
270   atrlen--;
271   if (atrlen)
272     fprintf (fp, "error: %u bytes garbage at end of ATR\n",
273              (unsigned int)atrlen );
274
275  bailout:
276   xfree (atrbuffer);
277
278   return 0;
279 }
280
281
282
283
284
285
286
287
288