1 /* $MirOS: src/lib/libsectok/todos_atr.c,v 1.2 2005/03/06 20:29:22 tg Exp $ */
2 /* $Id: todos_atr.c,v 1.8 2001/07/20 15:51:45 rees Exp $ */
3
4 /*
5 copyright 1997, 1999, 2000
6 the regents of the university of michigan
7 all rights reserved
8
9 permission is granted to use, copy, create derivative works
10 and redistribute this software and such derivative works
11 for any purpose, so long as the name of the university of
12 michigan is not used in any advertising or publicity
13 pertaining to the use or distribution of this software
14 without specific, written prior authorization. if the
15 above copyright notice or any other identification of the
16 university of michigan is included in any copy of any
17 portion of this software, then the disclaimer below must
18 also be included.
19
20 this software is provided as is, without representation
21 from the university of michigan as to its fitness for any
22 purpose, and without warranty by the university of
23 michigan of any kind, either express or implied, including
24 without limitation the implied warranties of
25 merchantability and fitness for a particular purpose. the
26 regents of the university of michigan shall not be liable
27 for any damages, including special, indirect, incidental, or
28 consequential damages, with respect to any claim arising
29 out of or in connection with the use of the software, even
30 if it has been or is hereafter advised of the possibility of
31 such damages.
32 */
33
34 /*
35 * Parse smart card atr, return proto params
36 *
37 * Jim Rees, University of Michigan CITI
38 */
39
40 #ifdef __palmos__
41 #include <Common.h>
42 #include <System/SysAll.h>
43 #include <System/Unix/unix_stdio.h>
44 #include <System/Unix/unix_stdlib.h>
45 #include <System/Unix/unix_string.h>
46 #include <UI/UIAll.h>
47 #include "field.h"
48 typedef long int32_t;
49 #else
50 #include <stdio.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #endif
54
55 #include "sectok.h"
56 #include "sc7816.h"
57 #include "todos_scrw.h"
58
59 #ifdef __unix__
60 #define SCPPS
61 #endif
62
63 /*
64 * 7816 says ATR will appear within 40000 clocks (12 msec)
65 * BUT some cards violate the spec and require more time
66 */
67 #define ATRTIME 120
68 #define BYTETIME 1000
69
70 /* Global interface bytes */
71 #define TA1 (tpb[0][0])
72 #define TB1 (tpb[0][1])
73 #define TC1 (tpb[0][2])
74 #define TD1 (tpb[0][3])
75 #define TC2 (tpb[1][2])
76 #define TA2 (tpb[1][0])
77
78 static char dummyatr[] = {0x3b, 0x25, 0x00, 0x44, 0x55, 0x4d, 0x4d, 0x59};
79
80 /* Inversion table, for inverse convention */
81 unsigned char todos_scinvert[] = {
82 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
83 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
84 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
85 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
86 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
87 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
88 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
89 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
90 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
91 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
92 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
93 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
94 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
95 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
96 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
97 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
98 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
99 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
100 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
101 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
102 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
103 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
104 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
105 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
106 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
107 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
108 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
109 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
110 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
111 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
112 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
113 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00,
114 };
115
116 /* 7816-3 1997 Table 7, 8 */
117 static short Ftab[] = { 372, 372, 558, 744, 1116, 1488, 1860, -1,
118 -1, 512, 768, 1024, 1536, 2048, -1, -1 };
119 static short Dtab[] = { -1, 1, 2, 4, 8, 16, 32, -1, 12, 20, -1, -1, -1, -1, -1, -1 };
120
121 /*
122 * Table generated by mkFDtab.
123 */
124
125 static struct bps {
126 unsigned char Fi, Di;
127 int32_t bps;
128 } bps[] = {
129 { 0x01, 0x08, 115464 },
130 { 0x09, 0x05, 111856 },
131 { 0x0b, 0x06, 111840 },
132 { 0x03, 0x08, 57732 },
133 { 0x09, 0x04, 55928 },
134 { 0x0a, 0x08, 55920 },
135 { 0x0b, 0x05, 55920 },
136 { 0x0d, 0x06, 55904 },
137 { 0x03, 0x04, 38488 },
138 { 0x01, 0x03, 38488 },
139 { 0x04, 0x08, 38484 },
140 { 0x06, 0x09, 38480 },
141 { 0x05, 0x05, 38480 },
142 { 0x0a, 0x04, 37280 },
143 { 0x0c, 0x05, 37280 },
144 { 0x05, 0x08, 28860 },
145 { 0x09, 0x03, 27964 },
146 { 0x0c, 0x08, 27960 },
147 { 0x0b, 0x04, 27960 },
148 { 0x0d, 0x05, 27952 },
149 { 0x06, 0x08, 23088 },
150 { 0x01, 0x02, 19244 },
151 { 0x03, 0x03, 19244 },
152 { 0x05, 0x04, 19240 },
153 { 0x0a, 0x03, 18640 },
154 { 0x0c, 0x04, 18640 },
155 { 0x09, 0x02, 13982 },
156 { 0x0b, 0x03, 13980 },
157 { 0x0d, 0x04, 13976 },
158 { 0x02, 0x02, 12828 },
159 { 0x04, 0x03, 12828 },
160 { 0, 0, 0 }
161 };
162
163
164 #define SCGETC if (scgetc(ttyn, ap, (len ? BYTETIME : ATRTIME)) != SCEOK) goto timedout; else len++
165
166 int
todos_get_atr(int ttyn,int flags,unsigned char * atr,struct scparam * param)167 todos_get_atr(int ttyn, int flags, unsigned char *atr, struct scparam *param)
168 {
169 int len, i, t, ts, t0, tck, nhb, pbn;
170 int F, D, Fi, Di, N, etu, WI;
171 unsigned char *ap;
172 unsigned char tpb[8][4];
173 int hiproto = 0;
174
175 if (flags & STRFORCE) {
176 /* drain and ignore any atr bytes returned by the card */
177 while (scgetc(ttyn, atr, BYTETIME) == SCEOK)
178 ;
179 len = sizeof dummyatr;
180 memcpy(atr, dummyatr, len);
181 param->t = 0;
182 param->etu = 100;
183 param->n = 0;
184 param->cwt = 1000;
185 return len;
186 }
187
188 #ifndef DEBUG
189 flags &= ~STRV;
190 #endif
191
192 ap = atr;
193 len = 0;
194
195 /* TS */
196 SCGETC;
197 ts = *ap++;
198 if (ts == 0x3) {
199 if (flags & STRV)
200 printf("inverse conversion\n");
201 todos_scsetflags(ttyn, SCOINVRT, SCOINVRT);
202 ts = todos_scinvert[ts];
203 }
204 if (ts != 0x3b && ts != 0x3f) {
205 if (flags & STRV)
206 printf("TS=%02x (not default timing)\n", ts);
207 param->t = -1;
208 return 0;
209 }
210
211 /* T0 */
212 SCGETC;
213 t0 = *ap++;
214 nhb = t0 & 0xf;
215
216 /* Fill in defaults */
217 TA1 = 0x11;
218 TB1 = 0x4d;
219 TC1 = 0x00;
220 TC2 = 10;
221 TA2 = 0xff;
222 TD1 = 0;
223
224 Fi = 1;
225 Di = 1;
226
227 /* Get up to 8 sets of protocol bytes */
228 for (i = 0; i < 8; i++) {
229 tpb[i][3] = 0;
230 for (pbn = 0; pbn < 4; pbn++) {
231 /* If T0 (or TD(i)) indicates presence of proto byte, get it */
232 if (t0 & (1 << (4 + pbn))) {
233 SCGETC;
234 tpb[i][pbn] = *ap++;
235 }
236 }
237 t = tpb[i][3] & 0xf;
238 if (t > hiproto)
239 hiproto = t;
240
241 if (flags & STRV) {
242 printf("proto %d T=%d", i + 1, t);
243 for (pbn = 0; pbn < 4; pbn++)
244 if (t0 & (1 << (4 + pbn)))
245 printf(" T%c%d=%02x", 'A' + pbn, i + 1, tpb[i][pbn]);
246 printf("\n");
247 }
248
249 t0 = tpb[i][3];
250 if (!(t0 & 0xf0))
251 break;
252 }
253
254 /* Historical bytes */
255 if (nhb) {
256 for (i = 0; i < nhb; i++) {
257 SCGETC;
258 ap++;
259 }
260 if ((flags & STRV))
261 printf("%d historical bytes\n", nhb);
262 }
263
264 /* TCK */
265 if (hiproto > 0) {
266 SCGETC;
267 ap++;
268 tck = 0;
269 for (i = 1; i < len; i++)
270 tck ^= atr[i];
271 if (tck != 0 && (flags & STRV))
272 printf("Checksum failed, TCK=%x sum=%x\n", atr[len-1], tck);
273 }
274
275 /*
276 * I'm a little unclear on this. If TA2 is present, it indicates a specific mode.
277 * Else it's negotiable, and starts out with proto 1?
278 * 7816-3 6.6.1
279 */
280 if (TA2 != 0xff)
281 t = TA2 & 0xf;
282 else
283 t = TD1 & 0xf;
284
285 /* Todos reader won't do higher speeds */
286 if (!(flags & SCRTODOS)) {
287 for (i = 0; bps[i].bps; i++) {
288 if (((TA1 >> 4) & 0xf) >= bps[i].Fi && (TA1 & 0xf) >= bps[i].Di) {
289 #ifdef SCPPS
290 int j;
291 unsigned char c;
292 #endif
293 static unsigned char pps[4] = {0xff, 0x10, 0, 0};
294
295 pps[2] = (bps[i].Fi << 4) | bps[i].Di;
296 pps[3] = 0;
297
298 if (flags & STRV)
299 printf("speed %ld\n", (long) bps[i].bps);
300
301 #ifdef SCPPS
302 /* Compute checksum */
303 for (j = 0; j < 3; j++)
304 pps[3] ^= pps[j];
305
306 for (j = 0; j < 4; j++)
307 scputc(ttyn, pps[j]);
308 for (j = 0; j < 4; j++)
309 if (scgetc(ttyn, &c, 100) != SCEOK || c != pps[j])
310 break;
311 if (j != 4)
312 continue;
313 if (todos_scsetspeed(ttyn, bps[i].bps) < 0) {
314 /* We already sent the pps, can't back out now, so fail. */
315 if (flags & STRV)
316 printf("scsetspeed %ld failed\n", (long) bps[i].bps);
317 param->t = -1;
318 return len;
319 }
320 #endif
321 Fi = bps[i].Fi;
322 Di = bps[i].Di;
323 break;
324 }
325 }
326 }
327
328 F = Ftab[Fi];
329 D = Dtab[Di];
330 N = TC1;
331
332 /* 1/f = 1/3.579545 ~= 50/179; etu in microsec */
333 param->etu = etu = (F * 50L) / (D * 179L);
334 param->n = (N < 255) ? N : 0;
335
336 if (flags & STRV) {
337 printf("%d etu = %d F / %d D * 3.58 f\n", etu, F, D);
338 if (N)
339 printf("%d N\n", N);
340 }
341
342 if (t == 0) {
343 WI = TC2;
344
345 /* cwt is in milliseconds */
346 param->cwt = (960L * WI * F) / 3580L;
347 if ((flags & STRV) && WI != 10)
348 printf("%d cwt = (960 * %d WI * %d F) / 3.58 f / 1000\n",
349 param->cwt, WI, F);
350 } else if (t == 1) {
351 /* add 100 to each for engineering safety margin */
352 param->cwt = (11L + (1 << (TB1 & 0xf))) * etu / 1000 + 100;
353 param->bwt = (11L * etu / 1000L) + ((1 << ((TB1 >> 4) & 0xf)) * 100) + 100;
354 if (flags & STRV)
355 printf("%d cwt, %d bwt\n", param->cwt, param->bwt);
356 }
357 param->t = t;
358 return len;
359
360 timedout:
361 if (flags & STRV)
362 printf("timed out after %d atr bytes\n", len);
363 param->t = -1;
364 return 0;
365 }
366