Line data Source code
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 0 : atr_dump (const void *buffer, size_t buflen)
43 : {
44 0 : const unsigned char *atr = buffer;
45 0 : 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 0 : fp = es_fopenmem (0, "rwb,samethread");
54 0 : if (!fp)
55 0 : return NULL;
56 :
57 0 : if (!atrlen)
58 : {
59 0 : es_fprintf (fp, "error: empty ATR\n");
60 0 : goto bailout;
61 : }
62 :
63 0 : for (idx=0; idx < atrlen ; idx++)
64 0 : es_fprintf (fp, "%s%02X", idx?" ":"", atr[idx]);
65 0 : es_putc ('\n', fp);
66 :
67 0 : if (*atr == 0x3b)
68 0 : es_fputs ("Direct convention\n", fp);
69 0 : else if (*atr == 0x3f)
70 0 : es_fputs ("Inverse convention\n", fp);
71 : else
72 0 : es_fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
73 0 : if (!--atrlen)
74 0 : goto bailout;
75 0 : atr++;
76 :
77 0 : chksum = *atr;
78 0 : for (idx=1; idx < atrlen-1; idx++)
79 0 : chksum ^= atr[idx];
80 :
81 0 : have_ta = !!(*atr & 0x10);
82 0 : have_tb = !!(*atr & 0x20);
83 0 : have_tc = !!(*atr & 0x40);
84 0 : have_td = !!(*atr & 0x80);
85 0 : n_historical = (*atr & 0x0f);
86 0 : es_fprintf (fp, "%d historical characters indicated\n", n_historical);
87 :
88 0 : if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
89 0 : es_fputs ("error: ATR shorter than indicated by format character\n", fp);
90 0 : if (!--atrlen)
91 0 : goto bailout;
92 0 : atr++;
93 :
94 0 : if (have_ta)
95 : {
96 0 : es_fputs ("TA1: F=", fp);
97 0 : val = fi_table[(*atr >> 4) & 0x0f];
98 0 : if (!val)
99 0 : es_fputs ("internal clock", fp);
100 0 : else if (val == -1)
101 0 : es_fputs ("RFU", fp);
102 : else
103 0 : es_fprintf (fp, "%d", val);
104 0 : es_fputs (" D=", fp);
105 0 : val = di_table[*atr & 0x0f];
106 0 : if (!val)
107 0 : es_fputs ("[impossible value]\n", fp);
108 0 : else if (val == -1)
109 0 : es_fputs ("RFU\n", fp);
110 0 : else if (val < 0 )
111 0 : es_fprintf (fp, "1/%d\n", val);
112 : else
113 0 : es_fprintf (fp, "%d\n", val);
114 :
115 0 : if (!--atrlen)
116 0 : goto bailout;
117 0 : atr++;
118 : }
119 :
120 0 : if (have_tb)
121 : {
122 0 : es_fprintf (fp, "TB1: II=%d PI1=%d%s\n",
123 0 : ((*atr >> 5) & 3), (*atr & 0x1f),
124 0 : (*atr & 0x80)? " [high bit not cleared]":"");
125 0 : if (!--atrlen)
126 0 : goto bailout;
127 0 : atr++;
128 : }
129 :
130 0 : if (have_tc)
131 : {
132 0 : if (*atr == 255)
133 0 : es_fputs ("TC1: guard time shortened to 1 etu\n", fp);
134 : else
135 0 : es_fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
136 :
137 0 : if (!--atrlen)
138 0 : goto bailout;
139 0 : atr++;
140 : }
141 :
142 0 : if (have_td)
143 : {
144 0 : have_ta = !!(*atr & 0x10);
145 0 : have_tb = !!(*atr & 0x20);
146 0 : have_tc = !!(*atr & 0x40);
147 0 : have_td = !!(*atr & 0x80);
148 0 : es_fprintf (fp, "TD1: protocol T%d supported\n", (*atr & 0x0f));
149 :
150 0 : if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
151 0 : es_fputs ("error: ATR shorter than indicated by format character\n",
152 : fp);
153 :
154 0 : if (!--atrlen)
155 0 : goto bailout;
156 0 : atr++;
157 : }
158 : else
159 0 : have_ta = have_tb = have_tc = have_td = 0;
160 :
161 0 : if (have_ta)
162 : {
163 0 : es_fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
164 0 : (*atr & 0x80)? "no-":"",
165 0 : (*atr & 0x10)? "im": "ex",
166 0 : (*atr & 0x0f));
167 0 : if ((*atr & 0x60))
168 0 : es_fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
169 0 : if (!--atrlen)
170 0 : goto bailout;
171 0 : atr++;
172 : }
173 :
174 0 : if (have_tb)
175 : {
176 0 : es_fprintf (fp, "TB2: PI2=%d\n", *atr);
177 0 : if (!--atrlen)
178 0 : goto bailout;
179 0 : atr++;
180 : }
181 :
182 0 : if (have_tc)
183 : {
184 0 : es_fprintf (fp, "TC2: PWI=%d\n", *atr);
185 0 : if (!--atrlen)
186 0 : goto bailout;
187 0 : atr++;
188 : }
189 :
190 0 : if (have_td)
191 : {
192 0 : have_ta = !!(*atr & 0x10);
193 0 : have_tb = !!(*atr & 0x20);
194 0 : have_tc = !!(*atr & 0x40);
195 0 : have_td = !!(*atr & 0x80);
196 0 : es_fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
197 :
198 0 : if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
199 0 : es_fputs ("error: ATR shorter than indicated by format character\n",
200 : fp);
201 :
202 0 : if (!--atrlen)
203 0 : goto bailout;
204 0 : atr++;
205 : }
206 : else
207 0 : have_ta = have_tb = have_tc = have_td = 0;
208 :
209 0 : for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
210 : {
211 0 : if (have_ta)
212 : {
213 0 : es_fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
214 0 : if (!--atrlen)
215 0 : goto bailout;
216 0 : atr++;
217 : }
218 :
219 0 : if (have_tb)
220 : {
221 0 : es_fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
222 0 : idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
223 0 : if (!--atrlen)
224 0 : goto bailout;
225 0 : atr++;
226 : }
227 :
228 0 : if (have_tc)
229 : {
230 0 : es_fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
231 0 : if (!--atrlen)
232 0 : goto bailout;
233 0 : atr++;
234 : }
235 :
236 0 : if (have_td)
237 : {
238 0 : have_ta = !!(*atr & 0x10);
239 0 : have_tb = !!(*atr & 0x20);
240 0 : have_tc = !!(*atr & 0x40);
241 0 : have_td = !!(*atr & 0x80);
242 0 : es_fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
243 :
244 0 : if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
245 0 : es_fputs ("error: "
246 : "ATR shorter than indicated by format character\n",
247 : fp);
248 :
249 0 : if (!--atrlen)
250 0 : goto bailout;
251 0 : atr++;
252 : }
253 : else
254 0 : have_ta = have_tb = have_tc = have_td = 0;
255 : }
256 :
257 0 : if (n_historical + 1 > atrlen)
258 0 : es_fputs ("error: ATR shorter than required for historical bytes "
259 : "and checksum\n", fp);
260 :
261 0 : if (n_historical)
262 : {
263 0 : es_fputs ("HCH:", fp);
264 0 : for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
265 0 : es_fprintf (fp, " %02X", *atr);
266 0 : es_putc ('\n', fp);
267 : }
268 :
269 0 : if (!atrlen)
270 0 : es_fputs ("error: checksum missing\n", fp);
271 0 : else if (*atr == chksum)
272 0 : es_fprintf (fp, "TCK: %02X (good)\n", *atr);
273 : else
274 0 : es_fprintf (fp, "TCK: %02X (bad; computed %02X)\n", *atr, chksum);
275 :
276 0 : atrlen--;
277 0 : if (atrlen)
278 0 : es_fprintf (fp, "error: %u bytes garbage at end of ATR\n",
279 : (unsigned int)atrlen );
280 :
281 : bailout:
282 0 : es_putc ('\0', fp); /* We want a string. */
283 0 : if (es_fclose_snatch (fp, (void**)&result, NULL))
284 : {
285 0 : log_error ("oops: es_fclose_snatch failed: %s\n", strerror (errno));
286 0 : return NULL;
287 : }
288 :
289 0 : return result;
290 : }
|