source: trunk/csctapi/protocol_t1.c@ 1

Last change on this file since 1 was 1, checked in by root, 14 years ago

initial import

File size: 11.7 KB
Line 
1/*
2 protocol_t1.c
3 Handling of ISO 7816 T=1 protocol
4
5 This file is part of the Unix driver for Towitoko smartcard readers
6 Copyright (C) 2000 Carlos Prados <cprados@yahoo.com>
7
8 This version is modified by doz21 to work in a special manner ;)
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*/
24
25#include "defines.h"
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "protocol_t1.h"
30#include "t1_block.h"
31
32/*
33 * Not exported constants definition
34 */
35#define PROTOCOL_T1_DEFAULT_IFSC 32
36#define PROTOCOL_T1_DEFAULT_IFSD 32
37#define PROTOCOL_T1_MAX_IFSC 251 /* Cannot send > 255 buffer */
38#define PROTOCOL_T1_DEFAULT_CWI 13
39#define PROTOCOL_T1_DEFAULT_BWI 4
40#define PROTOCOL_T1_EDC_LRC 0
41#define PROTOCOL_T1_EDC_CRC 1
42
43/*
44 * Not exported functions declaration
45 */
46
47static void
48Protocol_T1_Clear (Protocol_T1 * t1);
49
50static int
51Protocol_T1_SendBlock (Protocol_T1 * t1, T1_Block * block);
52
53static int
54Protocol_T1_ReceiveBlock (Protocol_T1 * t1, T1_Block ** block);
55
56static int
57Protocol_T1_UpdateBWT (Protocol_T1 * t1, unsigned short bwt);
58
59/*
60 * Exproted funtions definition
61 */
62
63Protocol_T1 *
64Protocol_T1_New (void)
65{
66 Protocol_T1 *t1;
67
68 t1 = (Protocol_T1 *) malloc (sizeof (Protocol_T1));
69
70 if (t1 != NULL)
71 Protocol_T1_Clear (t1);
72
73 return t1;
74}
75
76int
77Protocol_T1_Init (Protocol_T1 * t1, ICC_Async * icc, PPS_ProtocolParameters * params)
78{
79 ICC_Async_Timings timings;
80 BYTE ta, tb, tc, cwi, bwi;
81 unsigned long baudrate;
82 double work_etu;
83 ATR *atr;
84 int i;
85
86 /* Set ICC */
87 t1->icc = icc;
88
89 /* Get ATR of the card */
90 atr = ICC_Async_GetAtr (t1->icc);
91
92 /* Set IFSC */
93 if (ATR_GetInterfaceByte (atr, 3, ATR_INTERFACE_BYTE_TA, &ta) == ATR_NOT_FOUND)
94 t1->ifsc = PROTOCOL_T1_DEFAULT_IFSC;
95 else if ((ta != 0x00) && (ta != 0xFF))
96 t1->ifsc = ta;
97 else
98 t1->ifsc = PROTOCOL_T1_DEFAULT_IFSC;
99
100 /* Towitoko does not allow IFSC > 251 */
101 t1->ifsc = MIN (t1->ifsc, PROTOCOL_T1_MAX_IFSC);
102
103 /* Set IFSD */
104 t1->ifsd = PROTOCOL_T1_DEFAULT_IFSD;
105
106#ifndef PROTOCOL_T1_USE_DEFAULT_TIMINGS
107 /* Calculate CWI and BWI */
108 if (ATR_GetInterfaceByte (atr, 3, ATR_INTERFACE_BYTE_TB, &tb) == ATR_NOT_FOUND)
109 {
110#endif
111 cwi = PROTOCOL_T1_DEFAULT_CWI;
112 bwi = PROTOCOL_T1_DEFAULT_BWI;
113#ifndef PROTOCOL_T1_USE_DEFAULT_TIMINGS
114 }
115 else
116 {
117 cwi = tb & 0x0F;
118 bwi = (tb & 0xF0) >> 4;
119 }
120#endif
121
122 /* Work etu = (1000 / baudrate) milliseconds */
123 ICC_Async_GetBaudrate (t1->icc, &baudrate);
124 work_etu = 1000 / (double)baudrate;
125
126 /* Set CWT = (2^CWI + 11) work etu */
127 t1->cwt = 1;
128
129 for (i = 0; i < cwi ; i++)
130 t1->cwt *= 2;
131
132 t1->cwt = (unsigned short) ((t1->cwt + 11) * work_etu);
133
134 /* Set BWT = (2^BWI * 960 + 11) work etu */
135 t1->bwt = 1;
136 for (i = 0; i < bwi; i++)
137 t1->bwt *= 2;
138
139 t1->bwt = (unsigned short) ((t1->bwt * 960 + 11) * work_etu);
140
141 /* Set BGT = 22 * work etu */
142 t1->bgt = (unsigned short) (22 * work_etu);
143
144 /* Set the error detection code type */
145 if (ATR_GetInterfaceByte (atr, 3, ATR_INTERFACE_BYTE_TC, &tc) == ATR_NOT_FOUND)
146 t1->edc = PROTOCOL_T1_EDC_LRC;
147 else
148 t1->edc = tc & 0x01;
149
150 /* Set initial send sequence (NS) */
151 t1->ns = 1;
152
153 /* Set timings */
154 ICC_Async_GetTimings (t1->icc, &timings);
155
156 timings.block_timeout = t1->bwt;
157 timings.char_timeout = t1->cwt;
158 timings.block_delay = t1->bgt;
159
160 ICC_Async_SetTimings (t1->icc, &timings);
161
162#ifdef DEBUG_PROTOCOL
163 printf ("Protocol: T=1: IFSC=%d, IFSD=%d, CWT=%d, BWT=%d, BGT=%d, EDC=%s\n",
164 t1->ifsc, t1->ifsd, t1->cwt, t1->bwt, t1->bgt,
165 (t1->edc == PROTOCOL_T1_EDC_LRC) ? "LRC" : "CRC");
166#endif
167
168 return PROTOCOL_T1_OK;
169}
170
171int
172Protocol_T1_Command (Protocol_T1 * t1, APDU_Cmd * cmd, APDU_Rsp ** rsp)
173{
174 T1_Block *block;
175 BYTE *buffer, rsp_type, bytes, nr, wtx;
176 unsigned short counter;
177 int ret;
178 bool more;
179
180 /* Calculate the number of bytes to send */
181 counter = 0;
182 bytes = MIN (APDU_Cmd_RawLen (cmd), t1->ifsc);
183
184 /* See if chaining is needed */
185 more = (APDU_Cmd_RawLen (cmd) > t1->ifsc);
186
187 /* Increment ns */
188 t1->ns = (t1->ns + 1) %2;
189
190 /* Create an I-Block */
191 block = T1_Block_NewIBlock (bytes, APDU_Cmd_Raw (cmd), t1->ns, more);
192
193#ifdef DEBUG_PROTOCOL
194 printf ("Sending block I(%d,%d)\n", t1->ns, more);
195#endif
196
197 /* Send a block */
198 ret = Protocol_T1_SendBlock (t1, block);
199
200 /* Delete I-block */
201 T1_Block_Delete (block);
202
203 while ((ret == PROTOCOL_T1_OK) && more)
204 {
205 /* Receive a block */
206 ret = Protocol_T1_ReceiveBlock (t1, &block);
207
208 if (ret == PROTOCOL_T1_OK)
209 {
210 rsp_type = T1_Block_GetType (block);
211
212 /* Positive ACK R-Block received */
213 if (rsp_type == T1_BLOCK_R_OK)
214 {
215#ifdef DEBUG_PROTOCOL
216 printf ("Protocol: Received block R(%d)\n", T1_Block_GetNR (block));
217#endif
218 /* Delete block */
219 T1_Block_Delete (block);
220
221 /* Increment ns */
222 t1->ns = (t1->ns + 1) % 2;
223
224 /* Calculate the number of bytes to send */
225 counter += bytes;
226 bytes = MIN (APDU_Cmd_RawLen (cmd) - counter, t1->ifsc);
227
228 /* See if chaining is needed */
229 more = (APDU_Cmd_RawLen (cmd) - counter > t1->ifsc);
230
231 /* Create an I-Block */
232 block =
233 T1_Block_NewIBlock (bytes, APDU_Cmd_Raw (cmd) + counter,
234 t1->ns, more);
235#ifdef DEBUG_PROTOCOL
236 printf ("Protocol: Sending block I(%d,%d)\n", t1->ns, more);
237#endif
238 /* Send a block */
239 ret = Protocol_T1_SendBlock (t1, block);
240
241 /* Delete I-block */
242 T1_Block_Delete (block);
243 }
244
245 else
246 {
247 /* Delete block */
248 T1_Block_Delete (block);
249
250 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
251 }
252 }
253
254 else
255 {
256 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
257 }
258 }
259
260 /* Reset counter */
261 buffer = NULL;
262 counter = 0;
263 more = TRUE;
264 wtx = 0;
265
266 while ((ret == PROTOCOL_T1_OK) && more)
267 {
268 if (wtx > 1)
269 Protocol_T1_UpdateBWT (t1, wtx * (t1->bwt));
270
271 /* Receive a block */
272 ret = Protocol_T1_ReceiveBlock (t1, &block);
273
274 if (wtx > 1)
275 {
276 Protocol_T1_UpdateBWT (t1, t1->bwt);
277 wtx = 0;
278 }
279
280 if (ret == PROTOCOL_T1_OK)
281 {
282 rsp_type = T1_Block_GetType (block);
283
284 if (rsp_type == T1_BLOCK_I)
285 {
286#ifdef DEBUG_PROTOCOL
287 printf ("Protocol: Received block I(%d,%d)\n",
288 T1_Block_GetNS(block), T1_Block_GetMore (block));
289#endif
290 /* Calculate nr */
291 nr = (T1_Block_GetNS (block) + 1) % 2;
292
293 /* Save inf field */
294 bytes = T1_Block_GetLen (block);
295 buffer = (BYTE *) realloc(buffer, counter + bytes);
296 memcpy (buffer + counter, T1_Block_GetInf (block), bytes);
297 counter += bytes;
298
299 /* See if chaining is requested */
300 more = T1_Block_GetMore (block);
301
302 /* Delete block */
303 T1_Block_Delete (block);
304
305 if (more)
306 {
307 /* Create an R-Block */
308 block = T1_Block_NewRBlock (T1_BLOCK_R_OK, nr);
309#ifdef DEBUG_PROTOCOL
310 printf ("Protocol: Sending block R(%d)\n", nr);
311#endif
312 /* Send R-Block */
313 ret = Protocol_T1_SendBlock (t1, block);
314
315 /* Delete I-block */
316 T1_Block_Delete (block);
317 }
318 }
319
320 /* WTX Request S-Block received */
321 else if (rsp_type == T1_BLOCK_S_WTX_REQ)
322 {
323 /* Get wtx multiplier */
324 wtx = (*T1_Block_GetInf (block));
325#ifdef DEBUG_PROTOCOL
326 printf ("Protocol: Received block S(WTX request, %d)\n", wtx);
327#endif
328 /* Delete block */
329 T1_Block_Delete (block);
330
331 /* Create an WTX response S-Block */
332 block = T1_Block_NewSBlock (T1_BLOCK_S_WTX_RES, 1, &wtx);
333#ifdef DEBUG_PROTOCOL
334 printf ("Protocol: Sending block S(WTX response, %d)\n", wtx);
335#endif
336 /* Send WTX response */
337 ret = Protocol_T1_SendBlock (t1, block);
338
339 /* Delete block */
340 T1_Block_Delete (block);
341 }
342
343 else
344 {
345 ret = PROTOCOL_T1_NOT_IMPLEMENTED;
346 }
347 }
348 }
349
350 if (ret == PROTOCOL_T1_OK)
351 (*rsp) = APDU_Rsp_New (buffer, counter);
352
353 if (buffer != NULL)
354 free (buffer);
355
356 return ret;
357}
358
359int
360Protocol_T1_Close (Protocol_T1 * t1)
361{
362 Protocol_T1_Clear (t1);
363
364 return PROTOCOL_T1_OK;
365}
366
367void
368Protocol_T1_Delete (Protocol_T1 * t1)
369{
370 free (t1);
371}
372
373/*
374 * Not exported functions definition
375 */
376
377static int
378Protocol_T1_SendBlock (Protocol_T1 * t1, T1_Block * block)
379{
380 BYTE *buffer;
381 int length, ret;
382
383 /* Setup transmission */
384 if (ICC_Async_BeginTransmission (t1->icc) != ICC_ASYNC_OK)
385 ret = PROTOCOL_T1_ICC_ERROR;
386
387 else
388 {
389 /* Send T=1 block */
390 buffer = T1_Block_Raw (block);
391 length = T1_Block_RawLen (block);
392
393 if (ICC_Async_Transmit (t1->icc, length, buffer) != ICC_ASYNC_OK)
394 {
395 ICC_Async_EndTransmission (t1->icc);
396 ret = PROTOCOL_T1_ICC_ERROR;
397 }
398
399 else
400 ret = PROTOCOL_T1_OK;
401 }
402
403 return ret;
404}
405
406static int
407Protocol_T1_ReceiveBlock (Protocol_T1 * t1, T1_Block ** block)
408{
409 BYTE buffer[T1_BLOCK_MAX_SIZE];
410 int ret;
411
412 /* Receive four mandatory bytes */
413 if (ICC_Async_Receive (t1->icc, 4, buffer) != ICC_ASYNC_OK)
414 {
415 ret = PROTOCOL_T1_ICC_ERROR;
416 (*block) = NULL;
417 }
418
419 else
420 {
421 if (buffer[2] != 0x00)
422 {
423 /* Set timings to read the remaining block */
424 Protocol_T1_UpdateBWT (t1, t1->cwt);
425
426 /* Receive remaining bytes */
427 if (ICC_Async_Receive (t1->icc, buffer[2], buffer + 4) !=
428 ICC_ASYNC_OK)
429 {
430 (*block) = NULL;
431 ret = PROTOCOL_T1_ICC_ERROR;
432 }
433
434 else
435 {
436 (*block) = T1_Block_New (buffer, buffer[2] + 4);
437 ret = PROTOCOL_T1_OK;
438 }
439
440 /* Restore timings */
441 Protocol_T1_UpdateBWT (t1, t1->bwt);
442 }
443 else
444 {
445 ret = PROTOCOL_T1_OK;
446 (*block) = T1_Block_New (buffer, 4);
447 }
448 }
449
450 /* End of transmission */
451 if (ICC_Async_EndTransmission (t1->icc) != ICC_ASYNC_OK)
452 ret = PROTOCOL_T1_ICC_ERROR;
453
454 return ret;
455}
456
457static void
458Protocol_T1_Clear (Protocol_T1 * t1)
459{
460 t1->icc = NULL;
461 t1->ifsc = 0;
462 t1->ifsd = 0;
463 t1->bgt = 0;
464 t1->bwt = 0;
465 t1->cwt = 0;
466 t1->edc = 0;
467 t1->ns = 0;
468}
469
470static int
471Protocol_T1_UpdateBWT (Protocol_T1 * t1, unsigned short bwt)
472{
473 ICC_Async_Timings timings;
474
475 ICC_Async_GetTimings (t1->icc, &timings);
476
477 timings.block_timeout = bwt;
478
479 ICC_Async_SetTimings (t1->icc, &timings);
480
481 return PROTOCOL_T1_OK;
482}
Note: See TracBrowser for help on using the repository browser.