source: trunk/src/ifd/proto-t0.c @ 1185

Revision 1185, 6.5 KB checked in by aj, 2 years ago (diff)

Xiaoshuo Wu/Entersafe?:
make ePass3000 USB key work with OpenCT. We found out that new ePass3000
hardware returns data instead of 61XX(to indicates the number of response
bytes still available), so we modified OpenCT to handle it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Implementation of T=0
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7#include "internal.h"
8#include <sys/poll.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <string.h>
12
13typedef struct {
14        ifd_protocol_t base;
15
16        int state;
17        long timeout;
18        unsigned int block_oriented;
19        unsigned int max_nulls;
20} t0_state_t;
21
22enum {
23        IDLE, SENDING, RECEIVING, CONFUSED
24};
25
26static int t0_xcv(ifd_protocol_t *, const void *, size_t, void *, size_t);
27static int t0_send(ifd_protocol_t *, ct_buf_t *, int);
28static int t0_recv(ifd_protocol_t *, ct_buf_t *, int, long);
29static int t0_resynch(t0_state_t *);
30
31/*
32 * Set default T=1 protocol parameters
33 */
34static void t0_set_defaults(t0_state_t * t0)
35{
36        t0->state = IDLE;
37        t0->timeout = 2000;
38        t0->max_nulls = 800;
39}
40
41/*
42 * Attach t0 protocol
43 */
44static int t0_init(ifd_protocol_t * prot)
45{
46        t0_set_defaults((t0_state_t *) prot);
47        return 0;
48}
49
50/*
51 * Detach t0 protocol
52 */
53static void t0_release(ifd_protocol_t * prot)
54{
55        /* NOP */
56}
57
58/*
59 * Get/set parmaters for T1 protocol
60 */
61static int t0_set_param(ifd_protocol_t * prot, int type, long value)
62{
63        t0_state_t *t0 = (t0_state_t *) prot;
64
65        switch (type) {
66        case IFD_PROTOCOL_RECV_TIMEOUT:
67                t0->timeout = value;
68                break;
69        case IFD_PROTOCOL_BLOCK_ORIENTED:
70                t0->block_oriented = value;
71                break;
72        default:
73                ct_error("Unsupported parameter %d", type);
74                return -1;
75        }
76
77        return 0;
78}
79
80static int t0_get_param(ifd_protocol_t * prot, int type, long *result)
81{
82        t0_state_t *t0 = (t0_state_t *) prot;
83        long value;
84
85        switch (type) {
86        case IFD_PROTOCOL_RECV_TIMEOUT:
87                value = t0->timeout;
88                break;
89        case IFD_PROTOCOL_BLOCK_ORIENTED:
90                value = t0->block_oriented;
91                break;
92        default:
93                ct_error("Unsupported parameter %d", type);
94                return -1;
95        }
96
97        if (result)
98                *result = value;
99
100        return 0;
101}
102
103/*
104 * Send an APDU through T=0
105 */
106static int t0_transceive(ifd_protocol_t * prot, int dad, const void *sbuf,
107                         size_t slen, void *rbuf, size_t rlen)
108{
109        t0_state_t *t0 = (t0_state_t *) prot;
110        ifd_iso_apdu_t iso;
111        unsigned char sdata[5];
112        unsigned int cla, cse, lc, le;
113        int rc;
114
115        if (t0->state != IDLE) {
116                if (t0_resynch(t0) < 0)
117                        return -1;
118                t0->state = IDLE;
119        }
120
121        if (slen < 4 || rlen < 2)
122                return -1;
123
124        /* Check the APDU case etc */
125        if ((rc = ifd_iso_apdu_parse(sbuf, slen, &iso)) < 0)
126                return rc;
127
128        cse = iso.cse;
129        cla = iso.cla;
130        lc = iso.lc;
131        le = iso.le;
132
133        switch (cse) {
134        case IFD_APDU_CASE_1:
135                /* Include a NUL lc byte */
136                memcpy(sdata, sbuf, 4);
137                sdata[4] = 0;
138                sbuf = sdata;
139                slen = 5;
140                break;
141        case IFD_APDU_CASE_2S:
142        case IFD_APDU_CASE_3S:
143                break;
144        case IFD_APDU_CASE_4S:
145                /* Strip off the Le byte */
146                slen--;
147                break;
148        default:
149                /* We don't handle ext APDUs */
150                return -1;
151        }
152
153        /*
154           if (le + 2 > slen) {
155           ct_error("t0_transceive: recv buffer too small");
156           return -1;
157           }
158         */
159
160        if (lc) {
161                t0->state = SENDING;
162                if ((rc = t0_xcv(prot, sbuf, slen, rbuf, rlen)) < 0)
163                        return rc;
164
165                if( rc > 2 ) {
166                        //not 61XX but the data
167                        goto done;
168                }
169
170                /* Can this happen? */
171                if (rc != 2)
172                        return IFD_ERROR_COMM_ERROR;
173
174                /* Case 4 APDU - check whether we should
175                 * try to get the response */
176                if (cse == IFD_APDU_CASE_4S) {
177                        unsigned char *sw;
178
179                        sw = (unsigned char *)rbuf;
180
181                        if (sw[0] == 0x61) {
182                                /* additional length info */
183                                if (sw[1] != 0 && sw[1] < le)
184                                        le = sw[1];
185                        } else if ((sw[0] & 0xF0) == 0x60) {
186                                /* Command not accepted, do not
187                                 * retrieve response
188                                 */
189                                goto done;
190                        }
191
192                        /* Transmit a Get Response command */
193                        sdata[0] = cla;
194                        sdata[1] = 0xC0;
195                        sdata[2] = 0x00;
196                        sdata[3] = 0x00;
197                        sdata[4] = le;
198
199                        t0->state = RECEIVING;
200                        rc = t0_xcv(prot, sdata, 5, rbuf, le + 2);
201                }
202        } else {
203                t0->state = RECEIVING;
204                rc = t0_xcv(prot, sbuf, slen, rbuf, le + 2);
205        }
206
207      done:t0->state = IDLE;
208        return rc;
209}
210
211static int t0_xcv(ifd_protocol_t * prot, const void *sdata, size_t slen,
212                  void *rdata, size_t rlen)
213{
214        t0_state_t *t0 = (t0_state_t *) prot;
215        ct_buf_t sbuf, rbuf;
216        unsigned int null_count = 0;
217        unsigned int ins;
218
219        /* Let the driver handle any chunking etc */
220        if (t0->block_oriented) {
221                int rc;
222
223                if ((rc = ifd_send_command(prot, sdata, slen)) >= 0)
224                        rc = ifd_recv_response(prot, rdata, rlen, t0->timeout);
225                return rc;
226        }
227
228        /* Set up the send buffer */
229        ct_buf_set(&sbuf, (void *)sdata, slen);
230        ct_buf_init(&rbuf, rdata, rlen);
231
232        /* Get the INS */
233        ins = sbuf.base[1];
234
235        if (t0_send(prot, &sbuf, 5) < 0)
236                goto failed;
237
238        while (1) {
239                unsigned char byte;
240                int count;
241
242                if (ifd_recv_response(prot, &byte, 1, t0->timeout) < 0)
243                        goto failed;
244
245                /* Null byte to extend wait time */
246                if (byte == 0x60) {
247                        usleep(100000);
248                        if (++null_count > t0->max_nulls)
249                                goto failed;
250                        continue;
251                }
252
253                /* ICC sends SW1 SW2 */
254                if ((byte & 0xF0) == 0x60 || (byte & 0xF0) == 0x90) {
255                        /* Store SW1, then get SW2 and store it */
256                        if (ct_buf_put(&rbuf, &byte, 1) < 0
257                            || t0_recv(prot, &rbuf, 1, t0->timeout) < 0)
258                                goto failed;
259
260                        break;
261                }
262
263                /* Send/receive data.
264                 * ACK byte means transfer everything in one go,
265                 * ~ACK means do it octet by octet.
266                 * SCEZ masks off using 0xFE, but the Towitoko
267                 * driver uses 0x0E.
268                 * Do we need to make this configurable?
269                 */
270                if (((byte ^ ins) & 0xFE) == 0) {
271                        /* Send/recv as much as we can */
272                        count = -1;
273                } else if (((~byte ^ ins) & 0xFE) == 0) {
274                        count = 1;
275                } else {
276                        ifd_debug(2, "unexpected byte 0x%02x", byte);
277                        return -1;
278                }
279
280                if (t0->state == SENDING) {
281                        if (t0_send(prot, &sbuf, count) < 0)
282                                goto failed;
283                } else {
284                        if (t0_recv(prot, &rbuf, count, t0->timeout) < 0)
285                                goto failed;
286                        if (ct_buf_tailroom(&rbuf) == 0)
287                                break;
288                }
289        }
290
291        return ct_buf_avail(&rbuf);
292
293      failed:t0->state = CONFUSED;
294        return -1;
295}
296
297static int t0_send(ifd_protocol_t * prot, ct_buf_t * bp, int count)
298{
299        int n, avail;
300
301        avail = ct_buf_avail(bp);
302        if (count < 0)
303                count = avail;
304        if (count > avail || !avail)
305                return -1;
306        n = ifd_send_command(prot, ct_buf_head(bp), count);
307        if (n >= 0)
308                ct_buf_get(bp, NULL, count);
309        return n;
310}
311
312static int t0_recv(ifd_protocol_t * prot, ct_buf_t * bp, int count,
313                   long timeout)
314{
315        int n;
316
317        if (count < 0)
318                count = ct_buf_tailroom(bp);
319        n = ifd_recv_response(prot, ct_buf_tail(bp), count, timeout);
320        if (n >= 0)
321                ct_buf_put(bp, NULL, count);
322        return n;
323}
324
325static int t0_resynch(t0_state_t * t0)
326{
327        return -1;
328}
329
330/*
331 * Protocol struct
332 */
333struct ifd_protocol_ops ifd_protocol_t0 = {
334        IFD_PROTOCOL_T0,        /* id */
335        "T=0",                  /* name */
336        sizeof(t0_state_t),     /* size */
337        t0_init,                /* init */
338        t0_release,             /* release */
339        t0_set_param,           /* set_param */
340        t0_get_param,           /* get_param */
341        NULL,                   /* resynchronize */
342        t0_transceive,          /* transceive */
343        NULL,                   /* sync_read */
344        NULL,                   /* sync_write */
345};
Note: See TracBrowser for help on using the repository browser.