source: trunk/src/ifd/process.c @ 1190

Revision 1190, 11.7 KB checked in by alonbl, 4 months ago (diff)

epass2003 transmits >255 APDUs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * IFD resource manager protocol handling
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 */
6
7#include "internal.h"
8#ifdef HAVE_GETOPT_H
9#include <getopt.h>
10#endif
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include <openct/ifd.h>
17#include <openct/conf.h>
18#include <openct/logging.h>
19#include <openct/error.h>
20#include <openct/tlv.h>
21
22#include "ifdhandler.h"
23
24static struct cmd_name {
25        unsigned int value;
26        const char *str;
27} cmd_name[] = {
28        {
29        CT_CMD_STATUS, "CT_CMD_STATUS"}, {
30        CT_CMD_LOCK, "CT_CMD_LOCK"}, {
31        CT_CMD_UNLOCK, "CT_CMD_UNLOCK"}, {
32        CT_CMD_RESET, "CT_CMD_RESET"}, {
33        CT_CMD_REQUEST_ICC, "CT_CMD_REQUEST_ICC"}, {
34        CT_CMD_EJECT_ICC, "CT_CMD_EJECT_ICC"}, {
35        CT_CMD_OUTPUT, "CT_CMD_OUTPUT"}, {
36        CT_CMD_INPUT, "CT_CMD_INPUT"}, {
37        CT_CMD_PERFORM_VERIFY, "CT_CMD_PERFORM_VERIFY"}, {
38        CT_CMD_CHANGE_PIN, "CT_CMD_CHANGE_PIN"}, {
39        CT_CMD_MEMORY_READ, "CT_CMD_MEMORY_READ"}, {
40        CT_CMD_MEMORY_WRITE, "CT_CMD_MEMORY_WRITE"}, {
41        CT_CMD_TRANSACT_OLD, "CT_CMD_TRANSACT_OLD"}, {
42        CT_CMD_TRANSACT, "CT_CMD_TRANSACT"}, {
43        CT_CMD_SET_PROTOCOL, "CT_CMD_SET_PROTOCOL"}, {
440, NULL},};
45
46static const char *get_cmd_name(unsigned int cmd)
47{
48        struct cmd_name *c;
49
50        for (c = cmd_name; c->str; c++) {
51                if (c->value == cmd)
52                        return c->str;
53        }
54        return "<unknown>";
55}
56
57static int do_before_command(ifd_reader_t *);
58static int do_after_command(ifd_reader_t *);
59static int do_status(ifd_reader_t *, int,
60                     ct_tlv_parser_t *, ct_tlv_builder_t *);
61static int do_output(ifd_reader_t *, int,
62                     ct_tlv_parser_t *, ct_tlv_builder_t *);
63static int do_lock(ct_socket_t *, ifd_reader_t *, int,
64                   ct_tlv_parser_t *, ct_tlv_builder_t *);
65static int do_unlock(ct_socket_t *, ifd_reader_t *, int,
66                     ct_tlv_parser_t *, ct_tlv_builder_t *);
67static int do_reset(ifd_reader_t *, int, ct_tlv_parser_t *, ct_tlv_builder_t *);
68static int do_eject(ifd_reader_t *, int, ct_tlv_parser_t *, ct_tlv_builder_t *);
69static int do_verify(ifd_reader_t *, int,
70                     ct_tlv_parser_t *, ct_tlv_builder_t *);
71static int do_transact(ifd_reader_t *, int,
72                       ct_tlv_parser_t *, ct_tlv_builder_t *);
73static int do_memory_read(ifd_reader_t *, int,
74                          ct_tlv_parser_t *, ct_tlv_builder_t *);
75static int do_memory_write(ifd_reader_t *, int,
76                           ct_tlv_parser_t *, ct_tlv_builder_t *);
77static int do_transact_old(ifd_reader_t *, int, ct_buf_t *, ct_buf_t *);
78static int do_set_protocol(ifd_reader_t *, int,
79                           ct_tlv_parser_t *, ct_tlv_builder_t *);
80
81int ifdhandler_process(ct_socket_t * sock, ifd_reader_t * reader,
82                       ct_buf_t * argbuf, ct_buf_t * resbuf)
83{
84        unsigned char cmd, unit;
85        ct_tlv_parser_t args;
86        ct_tlv_builder_t resp;
87        int rc;
88
89        /* Get command and target unit */
90        if (ct_buf_get(argbuf, &cmd, 1) < 0 || ct_buf_get(argbuf, &unit, 1) < 0)
91                return IFD_ERROR_INVALID_MSG;
92
93        ifd_debug(1, "ifdhandler_process(cmd=%s, unit=%u)",
94                  get_cmd_name(cmd), unit);
95
96        /* First, handle commands that don't do TLV encoded
97         * arguments - currently this is only CT_CMD_TRANSACT. */
98        if (cmd == CT_CMD_TRANSACT_OLD) {
99                /* Security - deny any APDUs if there's an
100                 * exclusive lock held by some other client. */
101                if ((rc =
102                     ifdhandler_check_lock(sock, unit, IFD_LOCK_EXCLUSIVE)) < 0)
103                        return rc;
104                return do_transact_old(reader, unit, argbuf, resbuf);
105        }
106
107        if ((rc = do_before_command(reader)) < 0) {
108                return rc;
109        }
110
111        memset(&args, 0, sizeof(args));
112        if (ct_tlv_parse(&args, argbuf) < 0)
113                return IFD_ERROR_INVALID_MSG;
114        if (args.use_large_tags)
115                sock->use_large_tags = 1;
116
117        ct_tlv_builder_init(&resp, resbuf, sock->use_large_tags);
118
119        switch (cmd) {
120        case CT_CMD_STATUS:
121                rc = do_status(reader, unit, &args, &resp);
122                break;
123
124        case CT_CMD_OUTPUT:
125                rc = do_output(reader, unit, &args, &resp);
126                break;
127
128        case CT_CMD_RESET:
129        case CT_CMD_REQUEST_ICC:
130                rc = do_reset(reader, unit, &args, &resp);
131                break;
132
133        case CT_CMD_EJECT_ICC:
134                rc = do_eject(reader, unit, &args, &resp);
135                break;
136
137        case CT_CMD_PERFORM_VERIFY:
138                rc = do_verify(reader, unit, &args, &resp);
139                break;
140
141        case CT_CMD_LOCK:
142                rc = do_lock(sock, reader, unit, &args, &resp);
143                break;
144
145        case CT_CMD_UNLOCK:
146                rc = do_unlock(sock, reader, unit, &args, &resp);
147                break;
148
149        case CT_CMD_MEMORY_READ:
150                rc = do_memory_read(reader, unit, &args, &resp);
151                break;
152
153        case CT_CMD_MEMORY_WRITE:
154                rc = do_memory_write(reader, unit, &args, &resp);
155                break;
156
157        case CT_CMD_TRANSACT:
158                rc = do_transact(reader, unit, &args, &resp);
159                break;
160        case CT_CMD_SET_PROTOCOL:
161                rc = do_set_protocol(reader, unit, &args, &resp);
162                break;
163        default:
164                return IFD_ERROR_INVALID_CMD;
165        }
166
167        if (rc >= 0)
168                rc = resp.error;
169
170        /*
171         * TODO consider checking error
172         */
173        do_after_command(reader);
174
175        return rc;
176}
177
178/*
179 * Before command
180 */
181static int do_before_command(ifd_reader_t * reader)
182{
183        return ifd_before_command(reader);
184}
185
186/*
187 * After command
188 */
189static int do_after_command(ifd_reader_t * reader)
190{
191        return ifd_after_command(reader);
192}
193
194/*
195 * Status query
196 */
197static int do_status(ifd_reader_t * reader, int unit, ct_tlv_parser_t * args,
198                     ct_tlv_builder_t * resp)
199{
200        int n, rc, status;
201
202        switch (unit) {
203        case CT_UNIT_READER:
204                ct_tlv_put_string(resp, CT_TAG_READER_NAME, reader->name);
205
206                ct_tlv_put_tag(resp, CT_TAG_READER_UNITS);
207                for (n = 0; n < reader->nslots; n++)
208                        ct_tlv_add_byte(resp, n);
209
210                if (reader->flags & IFD_READER_DISPLAY)
211                        ct_tlv_add_byte(resp, CT_UNIT_DISPLAY);
212                if (reader->flags & IFD_READER_KEYPAD)
213                        ct_tlv_add_byte(resp, CT_UNIT_KEYPAD);
214                break;
215
216        default:
217                if (unit > reader->nslots)
218                        return IFD_ERROR_INVALID_SLOT;
219                if ((rc = ifd_activate(reader)) < 0
220                    || (rc = ifd_card_status(reader, unit, &status)) < 0)
221                        return rc;
222                ct_tlv_put_int(resp, CT_TAG_CARD_STATUS, status);
223                break;
224        }
225
226        return 0;
227}
228
229/*
230 * Output string to reader's display
231 */
232static int do_output(ifd_reader_t * reader, int unit, ct_tlv_parser_t * args,
233                     ct_tlv_builder_t * resp)
234{
235        char msgbuf[128];
236        const char *message = NULL;
237
238        if (unit > CT_UNIT_READER)
239                return IFD_ERROR_INVALID_ARG;
240
241        /* See if we have message parameter */
242        if (ct_tlv_get_string(args, CT_TAG_MESSAGE, msgbuf, sizeof(msgbuf)) > 0)
243                message = msgbuf;
244
245        return ifd_output(reader, message);
246}
247
248/*
249 * Lock/unlock card
250 */
251static int do_lock(ct_socket_t * sock, ifd_reader_t * reader, int unit,
252                   ct_tlv_parser_t * args, ct_tlv_builder_t * resp)
253{
254        unsigned int lock_type;
255        ct_lock_handle lock;
256        int rc;
257
258        if (unit > reader->nslots)
259                return IFD_ERROR_INVALID_SLOT;
260
261        if (ct_tlv_get_int(args, CT_TAG_LOCKTYPE, &lock_type) == 0)
262                return IFD_ERROR_MISSING_ARG;
263
264        if ((rc = ifdhandler_lock(sock, unit, lock_type, &lock)) < 0)
265                return rc;
266
267        /* Return the lock handle */
268        ct_tlv_put_int(resp, CT_TAG_LOCK, lock);
269        return 0;
270}
271
272static int do_unlock(ct_socket_t * sock, ifd_reader_t * reader, int unit,
273                     ct_tlv_parser_t * args, ct_tlv_builder_t * resp)
274{
275        ct_lock_handle lock;
276        int rc;
277
278        if (unit > reader->nslots)
279                return IFD_ERROR_INVALID_SLOT;
280
281        if (ct_tlv_get_int(args, CT_TAG_LOCK, &lock) == 0)
282                return IFD_ERROR_MISSING_ARG;
283
284        if ((rc = ifdhandler_unlock(sock, unit, lock)) < 0)
285                return rc;
286
287        return 0;
288}
289
290/*
291 * Reset card
292 */
293static int do_reset(ifd_reader_t * reader, int unit, ct_tlv_parser_t * args,
294                    ct_tlv_builder_t * resp)
295{
296        unsigned char atr[64];
297        char msgbuf[128];
298        const char *message = NULL;
299        unsigned int timeout = 0;
300        int rc;
301
302        if (unit > reader->nslots)
303                return IFD_ERROR_INVALID_SLOT;
304
305        /* See if we have timeout and/or message parameters */
306        ct_tlv_get_int(args, CT_TAG_TIMEOUT, &timeout);
307        if (ct_tlv_get_string(args, CT_TAG_MESSAGE, msgbuf, sizeof(msgbuf)) > 0)
308                message = msgbuf;
309
310        rc = ifd_card_request(reader, unit, timeout, message, atr, sizeof(atr));
311        if (rc < 0)
312                return rc;
313
314        /* Add the ATR to the response */
315        if (rc != 0) {
316                ct_tlv_put_tag(resp, CT_TAG_ATR);
317                ct_tlv_add_bytes(resp, atr, rc);
318        }
319
320        return 0;
321}
322
323/*
324 * Eject card
325 */
326static int do_eject(ifd_reader_t * reader, int unit, ct_tlv_parser_t * args,
327                    ct_tlv_builder_t * resp)
328{
329        char msgbuf[128];
330        const char *message = NULL;
331        unsigned int timeout = 0;
332        int rc;
333
334        if (unit > reader->nslots)
335                return IFD_ERROR_INVALID_SLOT;
336
337        /* See if we have timeout and/or message parameters */
338        ct_tlv_get_int(args, CT_TAG_TIMEOUT, &timeout);
339        if (ct_tlv_get_string(args, CT_TAG_MESSAGE, msgbuf, sizeof(msgbuf)) > 0)
340                message = msgbuf;
341
342        rc = ifd_card_eject(reader, unit, timeout, message);
343        if (rc < 0)
344                return rc;
345
346        return 0;
347}
348
349/*
350 * Request PIN through key pad and have card verify it
351 */
352static int do_verify(ifd_reader_t * reader, int unit, ct_tlv_parser_t * args,
353                     ct_tlv_builder_t * resp)
354{
355        char msgbuf[128];
356        unsigned char *data;
357        size_t data_len;
358        const char *message = NULL;
359        unsigned int timeout = 0;
360        int rc;
361
362        if (unit > reader->nslots)
363                return IFD_ERROR_INVALID_SLOT;
364
365        /* See if we have timeout and/or message parameters */
366        ct_tlv_get_int(args, CT_TAG_TIMEOUT, &timeout);
367        if (ct_tlv_get_string(args, CT_TAG_MESSAGE, msgbuf, sizeof(msgbuf)) > 0)
368                message = msgbuf;
369        if (!ct_tlv_get_opaque(args, CT_TAG_PIN_DATA, &data, &data_len))
370                return IFD_ERROR_MISSING_ARG;
371
372        rc = ifd_card_perform_verify(reader, unit, timeout, message,
373                                     data, data_len,
374                                     (unsigned char *)msgbuf, sizeof(msgbuf));
375        if (rc < 0)
376                return rc;
377
378        ct_tlv_put_tag(resp, CT_TAG_CARD_RESPONSE);
379        ct_tlv_add_bytes(resp, (const unsigned char *)msgbuf, rc);
380        return 0;
381}
382
383/*
384 * Transceive APDU
385 */
386static int do_transact(ifd_reader_t * reader, int unit, ct_tlv_parser_t * args,
387                       ct_tlv_builder_t * resp)
388{
389        unsigned char replybuf[258+256]; /* @ALON: added +256 as APDUs grew at some point */
390        unsigned char *data;
391        size_t data_len;
392        unsigned int timeout = 0;
393        int rc;
394
395        if (unit > reader->nslots)
396                return IFD_ERROR_INVALID_SLOT;
397
398        ct_tlv_get_int(args, CT_TAG_TIMEOUT, &timeout);
399        if (!ct_tlv_get_opaque(args, CT_TAG_CARD_REQUEST, &data, &data_len))
400                return IFD_ERROR_MISSING_ARG;
401
402        rc = ifd_card_command(reader, unit, data, data_len,
403                              replybuf, sizeof(replybuf));
404        if (rc < 0)
405                return rc;
406
407        ct_tlv_put_tag(resp, CT_TAG_CARD_RESPONSE);
408        ct_tlv_add_bytes(resp, replybuf, rc);
409        return 0;
410}
411
412static int do_transact_old(ifd_reader_t * reader, int unit, ct_buf_t * args,
413                           ct_buf_t * resp)
414{
415        int rc;
416
417        rc = ifd_card_command(reader, unit,
418                              ct_buf_head(args), ct_buf_avail(args),
419                              ct_buf_tail(resp), ct_buf_tailroom(resp));
420        if (rc < 0)
421                return rc;
422
423        ct_buf_put(resp, NULL, rc);
424        return 0;
425}
426
427static int do_set_protocol(ifd_reader_t * reader, int unit,
428                           ct_tlv_parser_t * args, ct_tlv_builder_t * resp)
429{
430        unsigned int protocol = 0xFF;
431        int rc;
432
433        if (unit > reader->nslots)
434                return IFD_ERROR_INVALID_SLOT;
435
436        if (ct_tlv_get_int(args, CT_TAG_PROTOCOL, &protocol) == 0)
437                return IFD_ERROR_MISSING_ARG;
438
439        rc = ifd_set_protocol(reader, unit, protocol);
440        if (rc < 0)
441                return rc;
442
443        return 0;
444}
445
446/*
447 * Synchronous ICC read/write
448 */
449static int do_memory_write(ifd_reader_t * reader, int unit,
450                           ct_tlv_parser_t * args, ct_tlv_builder_t * resp)
451{
452        unsigned char *data;
453        unsigned int data_len;
454        unsigned int address;
455        int rc;
456
457        if (unit > reader->nslots)
458                return IFD_ERROR_INVALID_SLOT;
459
460        if (ct_tlv_get_int(args, CT_TAG_ADDRESS, &address) == 0
461            || !ct_tlv_get_opaque(args, CT_TAG_DATA, &data, &data_len))
462                return IFD_ERROR_MISSING_ARG;
463
464        rc = ifd_card_write_memory(reader, unit, address, data, data_len);
465        if (rc < 0)
466                return rc;
467
468        return 0;
469}
470
471static int do_memory_read(ifd_reader_t * reader, int unit,
472                          ct_tlv_parser_t * args, ct_tlv_builder_t * resp)
473{
474        unsigned char data[CT_SOCKET_BUFSIZ];
475        unsigned int data_len;
476        unsigned int address;
477        int rc;
478
479        if (unit > reader->nslots)
480                return IFD_ERROR_INVALID_SLOT;
481
482        if (ct_tlv_get_int(args, CT_TAG_ADDRESS, &address) == 0
483            || !ct_tlv_get_int(args, CT_TAG_COUNT, &data_len))
484                return IFD_ERROR_MISSING_ARG;
485
486        if (data_len > sizeof(data))
487                data_len = sizeof(data);
488
489        rc = ifd_card_read_memory(reader, unit, address, data, data_len);
490        if (rc < 0)
491                return rc;
492
493        ct_tlv_put_opaque(resp, CT_TAG_DATA, data, rc);
494        return 0;
495}
Note: See TracBrowser for help on using the repository browser.