root/trunk/src/libopensc/card-acos5.c

Revision 3131, 5.3 KB (checked in by aj, 21 months ago)

Ian Young: use proper card type for acos5.

Line 
1/*
2 * card-acos5.c: Support for ACS ACOS5 cards.
3 *
4 * Copyright (C) 2007  Ian A. Young<ian@iay.org.uk>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include <string.h>
22#include "internal.h"
23#include "cardctl.h"
24
25static struct sc_atr_table acos5_atrs[] = {
26        {"3b:be:18:00:00:41:05:10:00:00:00:00:00:00:00:00:00:90:00", NULL, NULL,
27         SC_CARD_TYPE_ACOS5_GENERIC, 0, NULL},
28        {NULL, NULL, NULL, 0, 0, NULL}
29};
30
31static struct sc_card_operations *iso_ops;
32static struct sc_card_operations acos5_ops;
33static struct sc_card_driver acos5_drv = {
34        "ACS ACOS5 card",
35        "acos5",
36        &acos5_ops,
37        NULL, 0, NULL
38};
39
40static int acos5_match_card(sc_card_t * card)
41{
42        int i;
43
44        i = _sc_match_atr(card, acos5_atrs, &card->type);
45        if (i < 0)
46                return 0;
47        return 1;
48}
49
50static int acos5_init(sc_card_t * card)
51{
52        card->max_recv_size = 128;
53        card->max_send_size = 128;
54        return SC_SUCCESS;
55}
56
57static int acos5_finish(sc_card_t * card)
58{
59        return SC_SUCCESS;
60}
61
62static int acos5_select_file_by_path(sc_card_t * card,
63                                     const sc_path_t * in_path,
64                                     sc_file_t ** file_out)
65{
66        int in_len = in_path->len;
67        const u8 *in_pos = in_path->value;
68
69        sc_path_t path;
70        path.len = 2;           /* one component at a time */
71        path.type = SC_PATH_TYPE_FILE_ID;
72
73        /*
74         * Check parameters.
75         */
76        if (in_len % 2 != 0)
77                return SC_ERROR_INVALID_ARGUMENTS;
78
79        /*
80         * File ID by file ID...
81         */
82        while (in_len) {
83                int result;
84                memcpy(path.value, in_pos, 2);
85                result = iso_ops->select_file(card, &path, file_out);
86                if (result != SC_SUCCESS)
87                        return result;
88                in_len -= 2;
89                in_pos += 2;
90        }
91        return SC_SUCCESS;
92}
93
94static int acos5_select_file(sc_card_t * card,
95                             const sc_path_t * in_path, sc_file_t ** file_out)
96{
97        switch (in_path->type) {
98
99        case SC_PATH_TYPE_PATH:
100                return acos5_select_file_by_path(card, in_path, file_out);
101
102        default:
103                return iso_ops->select_file(card, in_path, file_out);
104        }
105}
106
107static int acos5_get_serialnr(sc_card_t * card, sc_serial_number_t * serial)
108{
109        int r;
110        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
111        sc_apdu_t apdu;
112
113        /*
114         * Check arguments.
115         */
116        if (!serial)
117                return SC_ERROR_INVALID_ARGUMENTS;
118
119        /*
120         * Return a cached serial number, if we have one.
121         */
122        if (card->serialnr.len) {
123                memcpy(serial, &card->serialnr, sizeof(*serial));
124                return SC_SUCCESS;
125        }
126
127        /*
128         * Fetch serial number using GET CARD INFO.
129         */
130        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x14, 0, 0);
131        apdu.cla |= 0x80;
132        apdu.resp = rbuf;
133        apdu.resplen = sizeof(rbuf);
134        apdu.le = 6;
135        r = sc_transmit_apdu(card, &apdu);
136        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
137        if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
138                return SC_ERROR_INTERNAL;
139
140        /*
141         * Cache serial number.
142         */
143        memcpy(card->serialnr.value, apdu.resp, apdu.resplen);
144        card->serialnr.len = apdu.resplen;
145
146        /*
147         * Copy and return serial number.
148         */
149        memcpy(serial, &card->serialnr, sizeof(*serial));
150        return SC_SUCCESS;
151}
152
153static int acos5_card_ctl(sc_card_t * card, unsigned long cmd, void *ptr)
154{
155        switch (cmd) {
156
157        case SC_CARDCTL_GET_SERIALNR:
158                return acos5_get_serialnr(card, (sc_serial_number_t *) ptr);
159
160        default:
161                return SC_ERROR_NOT_SUPPORTED;
162        }
163}
164
165static int acos5_list_files(sc_card_t * card, u8 * buf, size_t buflen)
166{
167        sc_apdu_t apdu;
168        int r;
169        size_t count;
170        u8 *bufp = buf;         /* pointer into buf */
171        int fno = 0;            /* current file index */
172
173        /*
174         * Check parameters.
175         */
176        if (!buf || (buflen & 1))
177                return SC_ERROR_INVALID_ARGUMENTS;
178
179        /*
180         * Use CARD GET INFO to fetch the number of files under the
181         * curently selected DF.
182         */
183        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x14, 0x01, 0x00);
184        apdu.cla |= 0x80;
185        r = sc_transmit_apdu(card, &apdu);
186        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
187        if (apdu.sw1 != 0x90)
188                return SC_ERROR_INTERNAL;
189        count = apdu.sw2;
190
191        while (count--) {
192                u8 info[8];
193
194                /*
195                 * Truncate the scan if no more room left in output buffer.
196                 */
197                if (buflen == 0)
198                        break;
199
200                sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x14, 0x02,
201                               fno++);
202                apdu.cla |= 0x80;
203                apdu.resp = info;
204                apdu.resplen = sizeof(info);
205                apdu.le = sizeof(info);
206                r = sc_transmit_apdu(card, &apdu);
207                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
208                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
209                        return SC_ERROR_INTERNAL;
210
211                *bufp++ = info[2];
212                *bufp++ = info[3];
213                buflen -= 2;
214        }
215
216        return (bufp - buf);
217}
218
219static struct sc_card_driver *sc_get_driver(void)
220{
221        struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
222
223        iso_ops = iso_drv->ops;
224        acos5_ops = *iso_ops;
225
226        acos5_ops.match_card = acos5_match_card;
227        acos5_ops.init = acos5_init;
228        acos5_ops.finish = acos5_finish;
229        acos5_ops.select_file = acos5_select_file;
230        acos5_ops.card_ctl = acos5_card_ctl;
231        acos5_ops.list_files = acos5_list_files;
232
233        return &acos5_drv;
234}
235
236struct sc_card_driver *sc_get_acos5_driver(void)
237{
238        return sc_get_driver();
239}
Note: See TracBrowser for help on using the browser.