Better reset the PIN verification stati after changing the key attributes.
[gnupg.git] / scd / atr.c
blobf6efd8a9583490e442185110f16a43898626a177
1 /* atr.c - ISO 7816 ATR fucntions
2 * Copyright (C) 2003 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
27 #include "scdaemon.h"
28 #include "apdu.h"
29 #include "atr.h"
30 #include "dynload.h"
32 static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
33 -1, 512, 768, 1024, 1536, 2048, -1, -1 };
34 static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
35 0, -1, -2, -4, -8, -16, -32, -64};
38 /* Dump the ATR of the card at SLOT in a human readable format to
39 stream FP. */
40 int
41 atr_dump (int slot, FILE *fp)
43 unsigned char *atrbuffer, *atr;
44 size_t atrlen;
45 int have_ta, have_tb, have_tc, have_td;
46 int n_historical;
47 int idx, val;
48 unsigned char chksum;
50 atr = atrbuffer = apdu_get_atr (slot, &atrlen);
51 if (!atr)
52 return gpg_error (GPG_ERR_GENERAL);
54 fprintf (fp, "Info on ATR of length %u at slot %d\n",
55 (unsigned int)atrlen, slot);
56 if (!atrlen)
58 fprintf (fp, "error: empty ATR\n");
59 goto bailout;
63 if (*atr == 0x3b)
64 fputs ("direct convention\n", fp);
65 else if (*atr == 0x3f)
66 fputs ("inverse convention\n", fp);
67 else
68 fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
69 if (!--atrlen)
70 goto bailout;
71 atr++;
73 chksum = *atr;
74 for (idx=1; idx < atrlen-1; idx++)
75 chksum ^= atr[idx];
77 have_ta = !!(*atr & 0x10);
78 have_tb = !!(*atr & 0x20);
79 have_tc = !!(*atr & 0x40);
80 have_td = !!(*atr & 0x80);
81 n_historical = (*atr & 0x0f);
82 fprintf (fp, "%d historical characters indicated\n", n_historical);
84 if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
85 fputs ("error: ATR shorter than indicated by format character\n", fp);
86 if (!--atrlen)
87 goto bailout;
88 atr++;
90 if (have_ta)
92 fputs ("TA1: F=", fp);
93 val = fi_table[(*atr >> 4) & 0x0f];
94 if (!val)
95 fputs ("internal clock", fp);
96 else if (val == -1)
97 fputs ("RFU", fp);
98 else
99 fprintf (fp, "%d", val);
100 fputs (" D=", fp);
101 val = di_table[*atr & 0x0f];
102 if (!val)
103 fputs ("[impossible value]\n", fp);
104 else if (val == -1)
105 fputs ("RFU\n", fp);
106 else if (val < 0 )
107 fprintf (fp, "1/%d\n", val);
108 else
109 fprintf (fp, "%d\n", val);
111 if (!--atrlen)
112 goto bailout;
113 atr++;
116 if (have_tb)
118 fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
119 (*atr & 0x80)? " [high bit not cleared]":"");
120 if (!--atrlen)
121 goto bailout;
122 atr++;
125 if (have_tc)
127 if (*atr == 255)
128 fputs ("TC1: guard time shortened to 1 etu\n", fp);
129 else
130 fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
132 if (!--atrlen)
133 goto bailout;
134 atr++;
137 if (have_td)
139 have_ta = !!(*atr & 0x10);
140 have_tb = !!(*atr & 0x20);
141 have_tc = !!(*atr & 0x40);
142 have_td = !!(*atr & 0x80);
143 fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
145 if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
146 fputs ("error: ATR shorter than indicated by format character\n", fp);
148 if (!--atrlen)
149 goto bailout;
150 atr++;
152 else
153 have_ta = have_tb = have_tc = have_td = 0;
155 if (have_ta)
157 fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
158 (*atr & 0x80)? "no-":"",
159 (*atr & 0x10)? "im": "ex",
160 (*atr & 0x0f));
161 if ((*atr & 0x60))
162 fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
163 if (!--atrlen)
164 goto bailout;
165 atr++;
168 if (have_tb)
170 fprintf (fp, "TB2: PI2=%d\n", *atr);
171 if (!--atrlen)
172 goto bailout;
173 atr++;
176 if (have_tc)
178 fprintf (fp, "TC2: PWI=%d\n", *atr);
179 if (!--atrlen)
180 goto bailout;
181 atr++;
184 if (have_td)
186 have_ta = !!(*atr & 0x10);
187 have_tb = !!(*atr & 0x20);
188 have_tc = !!(*atr & 0x40);
189 have_td = !!(*atr & 0x80);
190 fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
192 if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
193 fputs ("error: ATR shorter than indicated by format character\n", fp);
195 if (!--atrlen)
196 goto bailout;
197 atr++;
199 else
200 have_ta = have_tb = have_tc = have_td = 0;
202 for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
204 if (have_ta)
206 fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
207 if (!--atrlen)
208 goto bailout;
209 atr++;
212 if (have_tb)
214 fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
215 idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
216 if (!--atrlen)
217 goto bailout;
218 atr++;
221 if (have_tc)
223 fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
224 if (!--atrlen)
225 goto bailout;
226 atr++;
229 if (have_td)
231 have_ta = !!(*atr & 0x10);
232 have_tb = !!(*atr & 0x20);
233 have_tc = !!(*atr & 0x40);
234 have_td = !!(*atr & 0x80);
235 fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
237 if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
238 fputs ("error: ATR shorter than indicated by format character\n",
239 fp);
241 if (!--atrlen)
242 goto bailout;
243 atr++;
245 else
246 have_ta = have_tb = have_tc = have_td = 0;
249 if (n_historical + 1 > atrlen)
250 fputs ("error: ATR shorter than required for historical bytes "
251 "and checksum\n", fp);
253 if (n_historical)
255 fputs ("Historical:", fp);
256 for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
257 fprintf (fp, " %02X", *atr);
258 putchar ('\n');
261 if (!atrlen)
262 fputs ("error: checksum missing\n", fp);
263 else if (*atr == chksum)
264 fprintf (fp, "TCK: %02X (good)\n", *atr);
265 else
266 fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
268 atrlen--;
269 if (atrlen)
270 fprintf (fp, "error: %u bytes garbage at end of ATR\n",
271 (unsigned int)atrlen );
273 bailout:
274 xfree (atrbuffer);
276 return 0;
280 /* Note: This code has not yet been tested! It shall return -1 on
281 error or the number of historical bytes and store them at
282 HISTORICAL. */
284 atr_get_historical (int slot, unsigned char historical[])
286 int result = -1;
287 unsigned char *atrbuffer = NULL;
288 unsigned char *atr;
289 size_t atrlen;
290 int have_ta, have_tb, have_tc, have_td;
291 int n_historical;
292 int idx;
293 unsigned char chksum;
295 atr = atrbuffer = apdu_get_atr (slot, &atrlen);
296 if (!atr || atrlen < 2)
297 goto leave;
298 atrlen--;
299 atr++;
301 chksum = *atr;
302 for (idx=1; idx < atrlen-1; idx++)
303 chksum ^= atr[idx];
305 have_ta = !!(*atr & 0x10);
306 have_tb = !!(*atr & 0x20);
307 have_tc = !!(*atr & 0x40);
308 have_td = !!(*atr & 0x80);
309 n_historical = (*atr & 0x0f);
311 if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
312 goto leave; /* ATR shorter than indicated by format character. */
313 atrlen--;
314 atr++;
316 if (have_ta + have_tb + have_tc >= atrlen)
317 goto leave;
318 atrlen -= have_ta + have_tb + have_tc;
319 atr += have_ta + have_tb + have_tc;
321 if (have_td)
323 have_ta = !!(*atr & 0x10);
324 have_tb = !!(*atr & 0x20);
325 have_tc = !!(*atr & 0x40);
326 have_td = !!(*atr & 0x80);
327 if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
328 goto leave; /* ATR shorter than indicated by format character. */
329 atrlen--;
330 atr++;
332 else
333 have_ta = have_tb = have_tc = have_td = 0;
335 if (have_ta + have_tb + have_tc >= atrlen)
336 goto leave;
337 atrlen -= have_ta + have_tb + have_tc;
338 atr += have_ta + have_tb + have_tc;
340 if (have_td)
342 have_ta = !!(*atr & 0x10);
343 have_tb = !!(*atr & 0x20);
344 have_tc = !!(*atr & 0x40);
345 have_td = !!(*atr & 0x80);
346 if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
347 goto leave; /* ATR shorter than indicated by format character. */
348 atrlen--;
349 atr++;
351 else
352 have_ta = have_tb = have_tc = have_td = 0;
354 for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
356 if (have_ta + have_tb + have_tc >= atrlen)
357 goto leave;
358 atrlen -= have_ta + have_tb + have_tc;
359 atr += have_ta + have_tb + have_tc;
361 if (have_td)
363 have_ta = !!(*atr & 0x10);
364 have_tb = !!(*atr & 0x20);
365 have_tc = !!(*atr & 0x40);
366 have_td = !!(*atr & 0x80);
367 if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
368 goto leave; /* ATR shorter than indicated by format character. */
369 atrlen--;
370 atr++;
372 else
373 have_ta = have_tb = have_tc = have_td = 0;
376 if (n_historical >= atrlen)
377 goto leave; /* ATR shorter than required for historical bytes. */
379 if (n_historical)
381 for (idx=0; n_historical && atrlen; n_historical--, atrlen--, atr++)
382 historical[idx] = *atr;
385 if (!atrlen || *atr != chksum)
386 goto leave;
388 /* Don't care about garbage at the end of the ATR. */
390 result = n_historical;
392 leave:
393 xfree (atrbuffer);
395 return result;