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