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