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/>.
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
41 atr_dump (int slot
, FILE *fp
)
43 unsigned char *atrbuffer
, *atr
;
45 int have_ta
, have_tb
, have_tc
, have_td
;
50 atr
= atrbuffer
= apdu_get_atr (slot
, &atrlen
);
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
);
58 fprintf (fp
, "error: empty ATR\n");
64 fputs ("direct convention\n", fp
);
65 else if (*atr
== 0x3f)
66 fputs ("inverse convention\n", fp
);
68 fprintf (fp
,"error: invalid TS character 0x%02x\n", *atr
);
74 for (idx
=1; idx
< atrlen
-1; 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
);
92 fputs ("TA1: F=", fp
);
93 val
= fi_table
[(*atr
>> 4) & 0x0f];
95 fputs ("internal clock", fp
);
99 fprintf (fp
, "%d", val
);
101 val
= di_table
[*atr
& 0x0f];
103 fputs ("[impossible value]\n", fp
);
107 fprintf (fp
, "1/%d\n", val
);
109 fprintf (fp
, "%d\n", val
);
118 fprintf (fp
, "TB1: II=%d PI1=%d%s\n", (*atr
>> 5) & 3, *atr
& 0x1f,
119 (*atr
& 0x80)? " [high bit not cleared]":"");
128 fputs ("TC1: guard time shortened to 1 etu\n", fp
);
130 fprintf (fp
, "TC1: (extra guard time) N=%d\n", *atr
);
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
);
153 have_ta
= have_tb
= have_tc
= have_td
= 0;
157 fprintf (fp
, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
158 (*atr
& 0x80)? "no-":"",
159 (*atr
& 0x10)? "im": "ex",
162 fprintf (fp
, "note: reserved bits are set (TA2=0x%02X)\n", *atr
);
170 fprintf (fp
, "TB2: PI2=%d\n", *atr
);
178 fprintf (fp
, "TC2: PWI=%d\n", *atr
);
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
);
200 have_ta
= have_tb
= have_tc
= have_td
= 0;
202 for (idx
= 3; have_ta
|| have_tb
|| have_tc
|| have_td
; idx
++)
206 fprintf (fp
, "TA%d: IFSC=%d\n", idx
, *atr
);
214 fprintf (fp
, "TB%d: BWI=%d CWI=%d\n",
215 idx
, (*atr
>> 4) & 0x0f, *atr
& 0x0f);
223 fprintf (fp
, "TC%d: 0x%02X\n", idx
, *atr
);
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",
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
);
255 fputs ("Historical:", fp
);
256 for (; n_historical
&& atrlen
; n_historical
--, atrlen
--, atr
++)
257 fprintf (fp
, " %02X", *atr
);
262 fputs ("error: checksum missing\n", fp
);
263 else if (*atr
== chksum
)
264 fprintf (fp
, "TCK: %02X (good)\n", *atr
);
266 fprintf (fp
, "TCK: %02X (bad; calculated %02X)\n", *atr
, chksum
);
270 fprintf (fp
, "error: %u bytes garbage at end of ATR\n",
271 (unsigned int)atrlen
);
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
284 atr_get_historical (int slot
, unsigned char historical
[])
287 unsigned char *atrbuffer
= NULL
;
290 int have_ta
, have_tb
, have_tc
, have_td
;
293 unsigned char chksum
;
295 atr
= atrbuffer
= apdu_get_atr (slot
, &atrlen
);
296 if (!atr
|| atrlen
< 2)
302 for (idx
=1; idx
< atrlen
-1; 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. */
316 if (have_ta
+ have_tb
+ have_tc
>= atrlen
)
318 atrlen
-= have_ta
+ have_tb
+ have_tc
;
319 atr
+= have_ta
+ have_tb
+ have_tc
;
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. */
333 have_ta
= have_tb
= have_tc
= have_td
= 0;
335 if (have_ta
+ have_tb
+ have_tc
>= atrlen
)
337 atrlen
-= have_ta
+ have_tb
+ have_tc
;
338 atr
+= have_ta
+ have_tb
+ have_tc
;
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. */
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
)
358 atrlen
-= have_ta
+ have_tb
+ have_tc
;
359 atr
+= have_ta
+ have_tb
+ have_tc
;
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. */
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. */
381 for (idx
=0; n_historical
&& atrlen
; n_historical
--, atrlen
--, atr
++)
382 historical
[idx
] = *atr
;
385 if (!atrlen
|| *atr
!= chksum
)
388 /* Don't care about garbage at the end of the ATR. */
390 result
= n_historical
;