source: trunk/src/ifd/ifd-smartboard.c @ 964

Revision 964, 9.3 KB checked in by aj, 5 years ago (diff)

indent changes only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Driver for Cherry smartboard
3 *
4 * This was written just by looking at the Smartboard protocol
5 * on the wire.
6 *
7 * Some notes on the Smartboard protocol.
8 * The basic message format seems to be
9 *
10 *      00 [len] [code]
11 *
12 * 00   Seems to be some general "I'm okay, you're okay" byte.
13 *      Never seen anything else, but maybe it can be used to
14 *      convey some critical errors etc.
15 * len  One byte; length of following data
16 * code One byte; message code.
17 *      Followed by data
18 *
19 * I have no clue yet how to use the num block for PIN entry...
20 *
21 * This driver is alpha code - it works for me with a Cryptoflex card,
22 * but that doesn't mean a thing :)
23 *
24 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
25 */
26
27#include "internal.h"
28#include <sys/ioctl.h>
29#include <termios.h>
30#include <stdlib.h>
31#include <string.h>
32#include <time.h>
33#include <unistd.h>
34#include "ctbcs.h"
35
36static int smartboard_reset_ct(ifd_reader_t * reader);
37static int smartboard_command(ifd_reader_t *,
38                              unsigned char, const unsigned char *, size_t,
39                              unsigned char *, void *, size_t);
40static int __smartboard_cmd(ifd_reader_t *, unsigned char, const void *,
41                            size_t);
42static int __smartboard_rsp(ifd_reader_t *, unsigned char *, void *, size_t);
43
44/*
45 * Initialize the device
46 */
47static int smartboard_open(ifd_reader_t * reader, const char *device_name)
48{
49        ifd_device_params_t params;
50        ifd_device_t *dev;
51        int res;
52
53        reader->name = "Cherry Smartboard";
54        reader->nslots = 1;
55        reader->slot[0].dad = 0;
56
57        if (!(dev = ifd_device_open(device_name)))
58                return -1;
59
60        ifd_device_flush(dev);
61
62        if (ifd_device_type(dev) != IFD_DEVICE_TYPE_SERIAL) {
63                ct_error("Smartboard: must be a serial device");
64                return -1;
65        }
66        if ((res = ifd_device_get_parameters(dev, &params)) < 0) {
67                ct_error("Smartboard: failed to get serial config");
68                return res;
69        }
70
71        params.serial.bits = 8;
72        params.serial.parity = IFD_SERIAL_PARITY_EVEN;
73        params.serial.stopbits = 2;
74        params.serial.speed = 115200;
75        params.serial.check_parity = 1;
76        if ((res = ifd_device_set_parameters(dev, &params)) < 0) {
77                ct_error("Smartboard: failed to get serial line to 115200/8E2");
78                return res;
79        }
80
81        /* Toggle RTS briefly */
82        {
83                int bits = 0x4000;
84
85                usleep(230000);
86                ioctl(dev->fd, TIOCMSET, &bits);
87                usleep(230000);
88                bits |= TIOCM_DTR;
89                ioctl(dev->fd, TIOCMSET, &bits);
90                usleep(230000);
91                bits |= TIOCM_RTS;
92                ioctl(dev->fd, TIOCMSET, &bits);
93                usleep(100000);
94        }
95
96        ifd_serial_send_break(dev, 500000);
97        ifd_device_flush(dev);
98
99        reader->device = dev;
100
101        /* Reset the CT */
102        if ((res = smartboard_reset_ct(reader)) < 0)
103                return res;
104
105        return 0;
106}
107
108/*
109 * Reset the card reader
110 */
111static int smartboard_reset_ct(ifd_reader_t * reader)
112{
113        unsigned char buffer[128], code;
114        int rc;
115
116#if 1
117        /* shutdown reader - occasionally needed before we can init it */
118        rc = smartboard_command(reader, 0x6a, NULL, 0, &code, NULL, 0);
119        if (rc < 0)
120                return rc;
121#endif
122
123        /* init reader */
124        rc = smartboard_command(reader, 0x60, NULL, 0, &code, buffer,
125                                sizeof(buffer));
126        if (rc < 0)
127                return rc;
128        if (code != 0x60) {
129                ct_error("smartboard_reset_ct, expected status 0x60, got 0x%x",
130                         code);
131                return -1;
132        }
133        ifd_debug(1, "Detected %.*s", rc, buffer);
134        return 0;
135}
136
137/*
138 * Power up the reader
139 */
140static int smartboard_activate(ifd_reader_t * reader)
141{
142        ifd_debug(1, "called.");
143        return 0;
144}
145
146static int smartboard_deactivate(ifd_reader_t * reader)
147{
148        ifd_debug(1, "called.");
149        return 0;
150}
151
152/*
153 * Get the card status
154 */
155static int smartboard_card_status(ifd_reader_t * reader, int idx, int *status)
156{
157        unsigned char code, buffer[16];
158        int rc;
159
160        ifd_debug(1, "slot=%d", idx);
161        rc = smartboard_command(reader, 0x65, NULL, 0, &code, buffer,
162                                sizeof(buffer));
163        if (rc < 0)
164                return rc;
165
166        *status = 0;
167        switch (code) {
168        case 0x61:
169                /* card absent:  00 00 00 01
170                 * card present: 08 00 00 02
171                 * after reset:  19 01 00 04
172                 */
173                if (rc >= 4 && (buffer[0] & 0x08))
174                        *status = IFD_CARD_PRESENT;
175                break;
176        case 0x65:
177                ifd_debug(1, "event: card inserted.");
178                *status = IFD_CARD_PRESENT | IFD_CARD_STATUS_CHANGED;
179                break;
180        case 0x66:
181                ifd_debug(1, "event: card removed.");
182                *status = IFD_CARD_STATUS_CHANGED;
183                break;
184        default:
185                ct_error("smartboard_card_status: unexpected status code 0x%x",
186                         code);
187                return -1;
188        }
189
190        return 0;
191}
192
193/*
194 * Reset card and get ATR
195 */
196static int smartboard_card_reset(ifd_reader_t * reader, int slot, void *result,
197                                 size_t size)
198{
199        unsigned char code;
200        int rc;
201
202        rc = smartboard_command(reader, 0x65, NULL, 0, &code, result, size);
203        if (rc < 0)
204                return rc;
205
206        rc = smartboard_command(reader, 0x62, NULL, 0, &code, result, size);
207        if (rc < 0)
208                return rc;
209
210        if (code != 0x64) {
211                ct_error
212                    ("smartboard_card_reset: expected status code 0x62, got 0x%x",
213                     code);
214                return -1;
215        }
216        return rc;
217}
218
219/*
220 * Select a protocol for communication with the ICC.
221 * We cannot use the T=0 driver directly, because it thinks it can
222 * talk over the wire.
223 */
224static int smartboard_set_protocol(ifd_reader_t * reader, int nslot, int proto)
225{
226        unsigned char cmd_t0[5] = { 0x00, 0x00, 0x0a, 0x00, 0x10 };
227        unsigned char cmd_t1[5] = { 0x10, 0x00, 0x00, 0x75, 0x10 };
228        unsigned char *args, code;
229        ifd_slot_t *slot;
230        int rc;
231
232        slot = &reader->slot[nslot];
233        if (proto == IFD_PROTOCOL_T0) {
234                args = cmd_t0;
235        } else if (proto == IFD_PROTOCOL_T1) {
236                args = cmd_t1;
237        } else {
238                ct_error("%s: protocol not supported", reader->name);
239                return -1;
240        }
241
242        if ((rc =
243             smartboard_command(reader, 0x61, args, 5, &code, NULL, 0)) < 0)
244                return rc;
245        if (code != 0x62) {
246                ct_error("smartboard: unexpected status code 0x%x", code);
247                return -1;
248        }
249
250        slot->proto = ifd_protocol_new(proto, reader, slot->dad);
251        if (slot->proto == NULL) {
252                ct_error("%s: internal error", reader->name);
253                return -1;
254        }
255
256        /* Tell the protocol handler that we will do the framing */
257        ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 1);
258
259        return 0;
260}
261
262#if 0
263/*
264 * Perform a PIN verification
265 */
266static int smartboard_perform_verify(ifd_reader_t * reader, int nslot,
267                                     unsigned int timeout, const char *prompt,
268                                     const unsigned char *data, size_t data_len,
269                                     unsigned char *resp, size_t resp_len)
270{
271...}
272#endif
273
274/*
275 * Simple command
276 */
277static int __smartboard_cmd(ifd_reader_t * reader, unsigned char cmd,
278                            const void *arg, size_t arg_len)
279{
280        unsigned char buffer[257];
281
282        if (arg_len > sizeof(buffer) - 3)
283                return -1;
284
285        buffer[0] = 0x00;       /* never seen anything other than this */
286        buffer[1] = 1 + arg_len;
287        buffer[2] = cmd;
288        memcpy(buffer + 3, arg, arg_len);
289
290        if (ct_config.debug > 1)
291                ifd_debug(3, "sending:%s", ct_hexdump(buffer, 3 + arg_len));
292
293        return ifd_device_send(reader->device, buffer, 3 + arg_len);
294}
295
296static int __smartboard_rsp(ifd_reader_t * reader, unsigned char *code,
297                            void *res, size_t res_len)
298{
299        unsigned char buffer[257];
300        unsigned int rsp_len = 0, total = 2;
301        int rc;
302
303        while (rsp_len < total) {
304                rc = ifd_device_recv(reader->device, buffer + rsp_len,
305                                     total - rsp_len, -1);
306                if (rc < 0)
307                        return rc;
308                if (buffer[0] != 0x00)
309                        goto bad_reply;
310                rsp_len += rc;
311                if (rsp_len == 2) {
312                        if (buffer[1] == 0)
313                                goto bad_reply;
314                        total += buffer[1];
315                }
316        }
317
318        if (total < 3)
319                goto bad_reply;
320        *code = buffer[2];
321
322        if (ct_config.debug > 1)
323                ifd_debug(3, "received:%s", ct_hexdump(buffer, total));
324
325        rsp_len = total - 3;
326        if (res_len > rsp_len)
327                res_len = rsp_len;
328        if (res && res_len)
329                memcpy(res, buffer + 3, res_len);
330
331        return res_len;
332
333      bad_reply:
334        ct_error("smartboard: bad reply from device");
335        return -1;
336}
337
338static int smartboard_command(ifd_reader_t * reader, unsigned char cmd,
339                              const unsigned char *arg, size_t arg_len,
340                              unsigned char *code, void *res, size_t res_len)
341{
342        int n = 0, rc;
343
344        do {
345                if ((rc = __smartboard_cmd(reader, cmd, arg, arg_len)) < 0
346                    || (rc = __smartboard_rsp(reader, code, res, res_len)) < 0)
347                        ct_error("smartboard: transceive error");
348        } while (rc >= 0 && *code == 0x67 && n++ < 3);
349
350        return rc;
351}
352
353/*
354 * Send/receive APDU
355 */
356static int smartboard_send(ifd_reader_t * reader, unsigned int dad,
357                           const unsigned char *buffer, size_t len)
358{
359        ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
360        return __smartboard_cmd(reader, 0x67, buffer, len);
361}
362
363static int smartboard_recv(ifd_reader_t * reader, unsigned int dad,
364                           unsigned char *buffer, size_t len, long timeout)
365{
366        unsigned char code;
367        int rc;
368
369        ifd_debug(4, "called.");
370
371        /* Status code 63 seems to be some sort of wait time extension */
372        while (1) {
373                if ((rc = __smartboard_rsp(reader, &code, buffer, len)) < 0)
374                        return rc;
375                if (code != 0x63)
376                        break;
377        }
378
379        if (code != 0x64) {
380                ct_error("smartboard: unexpected status code 0x%x", code);
381                return -1;
382        }
383
384        ifd_debug(3, "resp:%s", ct_hexdump(buffer, rc));
385        return rc;
386}
387
388/*
389 * Driver operations
390 */
391static struct ifd_driver_ops smartboard_driver;
392
393/*
394 * Initialize this module
395 */
396void ifd_smartboard_register(void)
397{
398        smartboard_driver.open = smartboard_open,
399            smartboard_driver.activate = smartboard_activate,
400            smartboard_driver.deactivate = smartboard_deactivate,
401            smartboard_driver.card_status = smartboard_card_status,
402            smartboard_driver.card_reset = smartboard_card_reset,
403#ifdef notyet
404            smartboard_driver.perform_verify = smartboard_perform_verify,
405#endif
406            smartboard_driver.send = smartboard_send,
407            smartboard_driver.recv = smartboard_recv,
408            smartboard_driver.set_protocol = smartboard_set_protocol,
409            ifd_driver_register("smartboard", &smartboard_driver);
410}
Note: See TracBrowser for help on using the repository browser.