source: trunk/src/ifd/ifd-eutron.c @ 1065

Revision 1065, 7.9 KB checked in by aj, 4 years ago (diff)

Chaskiel Grundman:
This uncovered an issue in openct. namely, that eutron_recv doesn't wait
long enough. (my device sent a wtx request after 23 loops, but we abort
after 20). Also, eutron_recv returns short writes to its caller, even
though t1_xcv cannot deal with that at all.

This patch fixes those things, as well as changes a memcpy of overlapping
memory areas to a memmove.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Eutron Crypto Idendity IT-Sec driver
3 *
4 * Copyright (C) 2003, Andreas Jellinghaus <aj@dungeon.inka.de>
5 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
6 * Copyright 2006, Chaskiel Grundman <cg2v@andrew.cmu.edu>
7 */
8
9#include "internal.h"
10#include "atr.h"
11#include "usb-descriptors.h"
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15#include <errno.h>
16
17#define EUTRON_OUT IFD_USB_ENDPOINT_OUT | IFD_USB_TYPE_VENDOR | IFD_USB_RECIP_ENDPOINT
18#define EUTRON_IN IFD_USB_ENDPOINT_IN | IFD_USB_TYPE_VENDOR | IFD_USB_RECIP_ENDPOINT
19
20#define EUTRON_CMD_WRITE 0x1
21#define EUTRON_CMD_READ 0x2
22#define EUTRON_CMD_ATR 0x9
23#define EUTRON_CMD_SETPARAM 0x65
24
25typedef struct eut_priv {
26        unsigned char readbuffer[500];
27        int head;
28        int tail;
29} eut_priv_t;
30/*
31 * Initialize the device
32 */
33static int eutron_open(ifd_reader_t * reader, const char *device_name)
34{
35        ifd_device_t *dev;
36        eut_priv_t *priv;
37        ifd_device_params_t params;
38
39        reader->name = "Eutron CryptoIdendity";
40        reader->nslots = 1;
41        if (!(dev = ifd_device_open(device_name)))
42                return -1;
43        if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
44                ct_error("eutron: device %s is not a USB device", device_name);
45                ifd_device_close(dev);
46                return -1;
47        }
48
49        params = dev->settings;
50        params.usb.interface = 0;
51        if (ifd_device_set_parameters(dev, &params) < 0) {
52                ct_error("eutron: setting parameters failed", device_name);
53                ifd_device_close(dev);
54                return -1;
55        }
56
57        priv = (eut_priv_t *) calloc(1, sizeof(eut_priv_t));
58        if (!priv) {
59                ct_error("out of memory");
60                ifd_device_close(dev);
61                return IFD_ERROR_NO_MEMORY;
62        }
63
64        reader->driver_data = priv;
65
66        reader->device = dev;
67
68        return 0;
69}
70
71/*
72 * Power up the reader
73 */
74static int eutron_activate(ifd_reader_t * reader)
75{
76        return 0;
77}
78
79static int eutron_deactivate(ifd_reader_t * reader)
80{
81        return -1;
82}
83
84/*
85 * Card status - always present
86 */
87static int eutron_card_status(ifd_reader_t * reader, int slot, int *status)
88{
89        *status = IFD_CARD_PRESENT;
90        return 0;
91}
92
93/*
94 * Reset - nothing to be done?
95 * We should do something to make it come back with all state zapped
96 */
97static int eutron_card_reset(ifd_reader_t * reader, int slot, void *atr,
98                             size_t size)
99{
100        ifd_device_t *dev = reader->device;
101        unsigned char buffer[IFD_MAX_ATR_LEN + 100];
102        int rc, lr, c, atrlen;
103
104        if (ifd_usb_control(dev, EUTRON_OUT, 0xa3, 0, 0, NULL, 0, -1) != 0
105            || ifd_usb_control(dev, EUTRON_OUT, 0xa1, 0, 0, NULL, 0, -1) != 0
106            || ifd_usb_control(dev, EUTRON_OUT, 0xa2, 0, 0, NULL, 0, -1) != 0
107            || ifd_usb_control(dev, EUTRON_OUT, 0xa0, 0, 0, NULL, 0, -1) != 0)
108                goto failed;
109        /* flush any leftover buffered data */
110        while (ifd_usb_control(dev, EUTRON_IN, EUTRON_CMD_READ, 0, 0,
111                               buffer, IFD_MAX_ATR_LEN + 100, 1000) > 0) ;
112        if (ifd_usb_control(dev, EUTRON_OUT, EUTRON_CMD_ATR, 0, 0, NULL, 0, -1)
113            != 0)
114                goto failed;
115
116        for (lr = 0, c = 0; c < 20; c++) {
117                rc = ifd_usb_control(dev, EUTRON_IN, EUTRON_CMD_READ, 0, 0,
118                                     &buffer[lr], IFD_MAX_ATR_LEN - lr, 1000);
119
120                if (rc < 0)
121                        goto failed;
122                lr += rc;
123
124                rc = ifd_atr_complete(buffer, lr);
125
126                if (rc)
127                        break;
128
129                if (lr > IFD_MAX_ATR_LEN)
130                        goto failed;
131                usleep(100000);
132        }
133        if (c >= 20)
134                goto failed;
135
136        atrlen = lr;
137        memcpy(atr, buffer, atrlen);
138
139        return atrlen;
140
141      failed:
142        ct_error("eutron: failed to activate token");
143        return -1;
144}
145
146/*
147 * Send/receive routines
148 */
149static int eutron_send(ifd_reader_t * reader, unsigned int dad,
150                       const unsigned char *buffer, size_t len)
151{
152        return ifd_usb_control(reader->device, EUTRON_OUT, EUTRON_CMD_WRITE, 0,
153                               0, (void *)buffer, len, 1000);
154}
155
156static int eutron_recv(ifd_reader_t * reader, unsigned int dad,
157                       unsigned char *buffer, size_t len, long timeout)
158{
159        int rc, c, rbs;
160        eut_priv_t *priv = reader->driver_data;
161
162        ct_debug("eutron_recv: len=%d", len);
163        if (len <= priv->head - priv->tail) {
164                memcpy(buffer, priv->readbuffer + priv->tail, len);
165                priv->tail += len;
166                ct_debug("eutron_recv: returning buffered data, %d bytes left",
167                         priv->head - priv->tail);
168                return len;
169        }
170
171        /* move the data to the beginning of the buffer, so there's a big
172         * contiguous chunk */
173        memmove(priv->readbuffer, &priv->readbuffer[priv->tail],
174               priv->head - priv->tail);
175        priv->head -= priv->tail;
176        /* since we set tail=0 here, the rest of the function can ignore it */
177        priv->tail = 0;
178        for (c = 0; c < 30; c++) {
179                rbs = 499 - priv->head;
180                if (rbs == 0)
181                        break;
182
183                rc = ifd_usb_control(reader->device, EUTRON_IN, EUTRON_CMD_READ,
184                                     0, 0, &priv->readbuffer[priv->head], rbs,
185                                     timeout);
186
187                if (rc < 0)
188                        goto failed;
189                priv->head += rc;
190
191                if (priv->head >= len)
192                        break;
193                usleep(100000);
194        }
195        if (len > priv->head)
196                return -1;
197        memcpy(buffer, priv->readbuffer, len);
198        priv->tail += len;
199        if (priv->head - priv->tail)
200                ct_debug("eutron_recv: buffering %d bytes of data",
201                         priv->head - priv->tail);
202
203        return len;
204      failed:
205        ct_error("eutron: receive failed");
206        return -1;
207}
208
209static int eutron_set_protocol(ifd_reader_t * reader, int nslot, int proto)
210{
211        ifd_slot_t *slot;
212        ifd_atr_info_t atr_info;
213        unsigned char pts[7], ptsret[7];
214        int ptslen, ptsrlen, r, c, speedparam;
215
216        slot = &reader->slot[nslot];
217        if (proto != IFD_PROTOCOL_T0 && proto != IFD_PROTOCOL_T1) {
218                ct_error("%s: protocol not supported", reader->name);
219                return -1;
220        }
221
222        r = ifd_atr_parse(&atr_info, slot->atr, slot->atr_len);
223        if (r < 0) {
224                ct_error("%s: Bad ATR", reader->name);
225                return r;
226        }
227
228        /* if the card supports T=1, prefer it, even if
229         * it is not the default protocol */
230        if (atr_info.supported_protocols & 0x2) {
231                proto = IFD_PROTOCOL_T1;
232        }
233
234        /* XXX disable baud change */
235        atr_info.TA[0] = -1;
236        /* ITSEC-P does not respond correctly to request with PTS2 present */
237        atr_info.TC[0] = -1;
238
239        ptslen = ifd_build_pts(&atr_info, proto, pts, 7);
240        if (ptslen < 0) {
241                return r;
242        }
243        if (eutron_send(reader, slot->dad, pts, ptslen) != ptslen)
244                return IFD_ERROR_COMM_ERROR;
245
246        for (ptsrlen = 0, c = 0; c < 20; c++) {
247                r = ifd_usb_control(reader->device, EUTRON_IN, EUTRON_CMD_READ,
248                                    0, 0, &ptsret[ptsrlen],
249                                    sizeof(ptsret) - ptsrlen, 1000);
250
251                if (r < 0)
252                        return IFD_ERROR_COMM_ERROR;
253                ptsrlen += r;
254                if (ifd_pts_complete(ptsret, ptsrlen))
255                        break;
256
257                if (ptsrlen >= 7)
258                        return IFD_ERROR_COMM_ERROR;
259                usleep(100000);
260        }
261        if (c >= 20)
262                return IFD_ERROR_TIMEOUT;
263
264        r = ifd_verify_pts(&atr_info, proto, ptsret, ptsrlen);
265        if (r < 0) {
266                ct_error("%s: Protocol selection failed", reader->name);
267                return r;
268        }
269
270        if (atr_info.TA[0] != -1)
271                speedparam = atr_info.TA[0];
272        else
273                speedparam = 1;
274        if (ifd_usb_control
275            (reader->device, EUTRON_OUT, EUTRON_CMD_SETPARAM, speedparam, 0,
276             NULL, 0, -1) != 0
277            || ifd_usb_control(reader->device, EUTRON_OUT, 0xa1, 0, 0, NULL, 0,
278                               -1) != 0
279            || ifd_usb_control(reader->device, EUTRON_OUT, 0xa0, 0, 0, NULL, 0,
280                               -1) != 0)
281                return IFD_ERROR_COMM_ERROR;
282
283        slot->proto = ifd_protocol_new(proto, reader, slot->dad);
284        if (slot->proto == NULL) {
285                ct_error("%s: internal error", reader->name);
286                return -1;
287        }
288        /* device is not guaranteed to return whole frames */
289        ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 0);
290        /* Enable larger transfers */
291        if (proto == IFD_PROTOCOL_T1 && atr_info.TA[2] != -1) {
292                ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_T1_IFSC,
293                                           atr_info.TA[2]);
294                if (t1_negotiate_ifsd(slot->proto, slot->dad, atr_info.TA[2]) >
295                    0)
296                        ifd_protocol_set_parameter(slot->proto,
297                                                   IFD_PROTOCOL_T1_IFSD,
298                                                   atr_info.TA[2]);
299
300        }
301        return 0;
302}
303
304/*
305 * Driver operations
306 */
307static struct ifd_driver_ops eutron_driver;
308
309/*
310 * Initialize this module
311 */
312void ifd_eutron_register(void)
313{
314        eutron_driver.open = eutron_open;
315        eutron_driver.activate = eutron_activate;
316        eutron_driver.deactivate = eutron_deactivate;
317        eutron_driver.card_status = eutron_card_status;
318        eutron_driver.card_reset = eutron_card_reset;
319        eutron_driver.send = eutron_send;
320        eutron_driver.recv = eutron_recv;
321        eutron_driver.set_protocol = eutron_set_protocol;
322
323        ifd_driver_register("eutron", &eutron_driver);
324}
Note: See TracBrowser for help on using the repository browser.