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

Revision 3521, 13.0 KB (checked in by ludovic.rousseau, 7 months ago)

do not use system as a variable name. system() is also a function

card-akis.c:400: warning: declaration of 'system' shadows a global declaration
/usr/include/stdlib.h:730: warning: shadowed declaration is here

Line 
1/*
2 * card-akis.c: Support for AKIS smart cards
3 *
4 * Copyright (C) 2007 TUBITAK / UEKAE
5 * contact: bilgi@pardus.org.tr
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22#include <string.h>
23#include <stdlib.h>
24
25#include "internal.h"
26#include "asn1.h"
27#include "cardctl.h"
28
29/* generic iso 7816 operations table */
30static const struct sc_card_operations *iso_ops = NULL;
31
32/* our operations table with overrides */
33static struct sc_card_operations akis_ops;
34
35static struct sc_card_driver akis_drv = {
36        "TUBITAK UEKAE AKIS",
37        "akis",
38        &akis_ops,
39        NULL, 0, NULL
40};
41
42static struct sc_atr_table akis_atrs[] = {
43        { "3b:ba:11:00:81:31:fe:4d:55:45:4b:41:45:20:56:31:2e:30:ae", NULL, NULL, SC_CARD_TYPE_AKIS_GENERIC, 0, NULL },
44        { NULL, NULL, NULL, 0, 0, NULL }
45};
46
47static int
48akis_match_card(sc_card_t *card)
49{
50        int i;
51
52        i = _sc_match_atr(card, akis_atrs, &card->type);
53        if (i < 0)
54                return 0;
55        return 1;
56}
57
58static int
59akis_init(sc_card_t *card)
60{
61        unsigned long flags;
62
63        card->name = "AKIS";
64        card->cla = 0x00;
65        card->max_pin_len = 16;
66        if (card->max_recv_size > 244)
67                card->max_recv_size = 244;
68        if (card->max_send_size > 244)
69                card->max_send_size = 244;
70
71        flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
72        _sc_card_add_rsa_alg(card, 2048, flags, 0);
73
74        return 0;
75}
76
77static int
78select_file(sc_card_t *card, sc_apdu_t *apdu, const sc_path_t *path,
79            int mode, sc_file_t **file_out)
80{
81        int r;
82        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
83        sc_file_t *file;
84
85        sc_format_apdu(card, apdu, SC_APDU_CASE_4_SHORT, 0xA4, mode, 0);
86        apdu->resp = rbuf;
87        apdu->resplen = sizeof(rbuf);
88        apdu->datalen = path->len;
89        apdu->data = path->value;
90        apdu->lc = path->len;
91        apdu->le = 256;
92
93        r = sc_transmit_apdu(card, apdu);
94        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
95        r = sc_check_sw(card, apdu->sw1, apdu->sw2);
96        SC_TEST_RET(card->ctx, r, "Card returned error");
97
98        if (file_out == NULL)
99                return 0;
100
101        file = sc_file_new();
102        if (file == NULL)
103                SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
104
105        r = card->ops->process_fci(card, file, apdu->resp + 2, apdu->resp[1]);
106        if (r) {
107                sc_file_free(file);
108                return r;
109        }
110
111        *file_out = file;
112        return 0;
113}
114
115static int
116akis_select_file(sc_card_t *card, const sc_path_t *path,
117                 sc_file_t **file_out)
118{
119        int r;
120        sc_apdu_t apdu;
121
122        if (path->type == SC_PATH_TYPE_PATH) {
123                /* FIXME: iso implementation seems already do that
124                */
125                r = select_file(card, &apdu, path, path->len == 2 ? 0 : 8, file_out);
126
127                SC_TEST_RET(card->ctx, r, "Unable to select DF");
128                return 0;
129        } else if (path->type == SC_PATH_TYPE_FILE_ID) {
130                /* AKIS differentiates between EF and DF files
131                 * when selecting with ID, this workaround tries both
132                 */
133                r = select_file(card, &apdu, path, 2, file_out);
134                if (r)
135                        r = select_file(card, &apdu, path, 0, file_out);
136
137                SC_TEST_RET(card->ctx, r, "Unable to select DF");
138                return 0;
139        } else {
140                return iso_ops->select_file(card, path, file_out);
141        }
142}
143
144static int
145akis_list_files(sc_card_t *card, u8 *buf, size_t buflen)
146{
147        /* This AKIS specific command is not provided by generic ISO driver
148         */
149        sc_apdu_t apdu;
150        u8 rbuf[256];
151        size_t left, fids = 0;
152        u8 *p;
153        int r;
154
155        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x18, 0, 0);
156        apdu.cla = 0x80;
157        apdu.le = 256;
158        apdu.resplen = sizeof(rbuf);
159        apdu.resp = rbuf;
160
161        r = sc_transmit_apdu(card, &apdu);
162        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
163        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
164        SC_TEST_RET(card->ctx, r, "DIRECTORY command returned error");
165
166        left = apdu.resplen;
167        p = rbuf;
168
169        while (left > 19) {
170                if (p[0] != 0x2f && p[0] != 0x3d) {
171                        sc_error(card->ctx, "Malformatted list reply %02x", p[0]);
172                        return SC_ERROR_INTERNAL;
173                }
174                if (buflen >= 2) {
175                        buf[fids++] = p[1];
176                        buf[fids++] = p[2];
177                        buflen -= 2;
178                } else {
179                        break;
180                }
181                p += 20;
182                left -= 20;
183        }
184
185        r = fids;
186        SC_FUNC_RETURN(card->ctx, 1, r);
187}
188
189static int
190akis_process_fci(sc_card_t *card, sc_file_t *file,
191                 const u8 *buf, size_t buflen)
192{
193        int r;
194        size_t len;
195        const u8 *p;
196        u8 perms;
197
198        r = iso_ops->process_fci(card, file, buf, buflen);
199        if (r < 0) return r;
200
201        /* AKIS uses a different security model than ISO implementation
202         */
203        p = sc_asn1_find_tag(card->ctx, buf, buflen, 0x90, &len);
204        if (p == NULL) {
205                sc_error(card->ctx, "Security tag missing");
206                return SC_ERROR_INTERNAL;
207        }
208        perms = p[0];
209        /* Bit definitions:
210         * 0x01 Encrypted
211         * 0x02 Valid
212         * 0x04 PIN needed
213         * 0x08 New PIN
214         * 0x10 Read
215         * 0x20 Write
216         * 0x40 Wrong PIN entered once
217         * 0x80 Last try for PIN
218         */
219
220        if (file->type == SC_FILE_TYPE_DF) {
221                if (perms & 0x04)
222                        sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, SC_AC_CHV, 0x80);
223        } else {
224                if (!(perms & 0x04))
225                        sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_CHV, 0x80);
226        }
227
228        return 0;
229}
230
231static int
232akis_create_file(sc_card_t *card, sc_file_t *file)
233{
234        int r;
235        u8 type;
236        u8 acl;
237        u8 fid[4];
238        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
239        sc_apdu_t apdu;
240
241        /* AKIS uses different create commands for EF and DF.
242         * Parameters are not passed as ASN.1 structs but in
243         * a custom format.
244         */
245
246        /* FIXME: hardcoded for now, better get it from file acl params */
247        acl = 0xb0;
248
249        fid[0] = (file->id >> 8) & 0xFF;
250        fid[1] = file->id & 0xFF;
251
252        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x15, 0, acl);
253        apdu.cla = 0x80;
254        apdu.data = fid;
255        apdu.datalen = 2;
256        apdu.lc = 2;
257        apdu.resp = rbuf;
258        apdu.resplen = sizeof(rbuf);
259
260        if (file->type == SC_FILE_TYPE_WORKING_EF) {
261                switch (file->ef_structure) {
262                        case SC_FILE_EF_TRANSPARENT:
263                                type = 0x80;
264                                break;
265                        case SC_FILE_EF_LINEAR_FIXED:
266                                type = 0x41;
267                                break;
268                        case SC_FILE_EF_CYCLIC:
269                                type = 0x43;
270                                break;
271                        case SC_FILE_EF_LINEAR_VARIABLE_TLV:
272                                type = 0x45;
273                                break;
274                        default:
275                                sc_error(card->ctx, "This EF structure is not supported yet");
276                                return SC_ERROR_NOT_SUPPORTED;
277                }
278                apdu.p1 = type;
279                if (type == 0x41 || type == 0x43) {
280                        fid[2] = file->record_length;
281                        apdu.datalen++;
282                        apdu.lc++;
283                }
284        } else if (file->type == SC_FILE_TYPE_DF) {
285                apdu.ins = 0x10;
286        } else {
287                sc_error(card->ctx, "Unknown file type");
288                return SC_ERROR_NOT_SUPPORTED;
289        }
290
291        r = sc_transmit_apdu(card, &apdu);
292        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
293        return sc_check_sw(card, apdu.sw1, apdu.sw2);
294}
295
296static int
297akis_delete_file(sc_card_t *card, const sc_path_t *path)
298{
299        int r;
300        u8 sbuf[2];
301        const u8 *buf;
302        size_t buflen;
303        int type;
304        sc_apdu_t apdu;
305
306        switch (path->type) {
307                case SC_PATH_TYPE_FILE_ID:
308                        sbuf[0] = path->value[0];
309                        sbuf[1] = path->value[1];
310                        buf = sbuf;
311                        buflen = 2;
312                        type = 0x02;
313                        break;
314                case SC_PATH_TYPE_PATH:
315                        buf = path->value;
316                        buflen = path->len;
317                        type = 0x08;
318                        break;
319                default:
320                        sc_error(card->ctx, "File type has to be FID or PATH");
321                        SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
322        }
323        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x16, type, 0x00);
324        apdu.cla = 0x80;
325        apdu.lc = buflen;
326        apdu.datalen = buflen;
327        apdu.data = buf;
328
329        r = sc_transmit_apdu(card, &apdu);
330        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
331        return sc_check_sw(card, apdu.sw1, apdu.sw2);
332}
333
334static int
335akis_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left)
336{
337        if (data->cmd == SC_PIN_CMD_VERIFY) {
338                /* ISO7816 implementation works */
339                return iso_ops->pin_cmd(card, data, tries_left);
340        }
341
342        if (data->cmd == SC_PIN_CMD_CHANGE) {
343                /* This is AKIS specific */
344                int r;
345                sc_apdu_t apdu;
346                u8 buf[64];
347                int p1, p2;
348
349                p2 = data->pin_reference;
350                if (p2 & 0x80) {
351                        p1 = 2;
352                        p2 &= 0x7f;
353                } else {
354                        p1 = 1;
355                }
356                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, p1, p2);
357                apdu.sensitive = 1;
358
359                buf[0] = data->pin1.len;
360                memcpy(buf+1, data->pin1.data, data->pin1.len);
361
362                buf[data->pin1.len+1] = data->pin2.len;
363                memcpy(buf+data->pin1.len+2, data->pin2.data, data->pin2.len);
364
365                apdu.data = buf;
366                apdu.datalen = data->pin1.len + data->pin2.len + 2;
367                apdu.lc = apdu.datalen;
368
369                r = sc_transmit_apdu(card, &apdu);
370                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
371                r = sc_check_sw(card, apdu.sw1, apdu.sw2);
372                return r;
373        }
374
375        sc_error(card->ctx, "Other pin cmds not supported yet");
376        return SC_ERROR_NOT_SUPPORTED;
377}
378
379static int
380akis_get_data(sc_card_t *card, unsigned int dataid, u8 *buf, size_t len)
381{
382        int r;
383        sc_apdu_t apdu;
384
385        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, dataid);
386        apdu.resp = buf;
387        apdu.resplen = len;
388        apdu.le = len;
389
390        r = sc_transmit_apdu(card, &apdu);
391        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
392        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
393        return r;
394}
395
396static int
397akis_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
398{
399        int r;
400        u8 system_buffer[128];
401
402        if (!serial)
403                return SC_ERROR_INVALID_ARGUMENTS;
404
405        /* see if we have cached serial number */
406        if (card->serialnr.len) goto end;
407
408        /* read serial number */
409        r = akis_get_data(card, 6, system_buffer, 0x4D);
410        SC_TEST_RET(card->ctx, r, "GET_DATA failed");
411
412        card->serialnr.len = 12;
413        memcpy(card->serialnr.value, system_buffer+55, 12);
414
415end:
416        memcpy(serial, &card->serialnr, sizeof(*serial));
417        return SC_SUCCESS;
418}
419
420static int
421akis_lifecycle_get(sc_card_t *card, int *mode)
422{
423        int r;
424        u8 memory[10];
425
426        r = akis_get_data(card, 4, memory, 10);
427        SC_TEST_RET(card->ctx, r, "GET_DATA failed");
428
429        switch(memory[6]) {
430                case 0xA0:
431                        *mode = SC_CARDCTRL_LIFECYCLE_ADMIN;
432                        break;
433                case 0xA5:
434                        *mode = SC_CARDCTRL_LIFECYCLE_USER;
435                        break;
436                default:
437                        *mode = SC_CARDCTRL_LIFECYCLE_OTHER;
438                        break;
439        }
440        return SC_SUCCESS;
441}
442
443static int
444akis_lifecycle_set(sc_card_t *card, int *mode)
445{
446        int r;
447        u8 stage;
448        sc_apdu_t apdu;
449
450        switch(*mode) {
451                case SC_CARDCTRL_LIFECYCLE_ADMIN:
452                        stage = 0x02;
453                        break;
454                case SC_CARDCTRL_LIFECYCLE_USER:
455                        stage = 0x01;
456                        break;
457                default:
458                        return SC_ERROR_INVALID_ARGUMENTS;
459        }
460        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x09, 0x00, stage);
461        apdu.cla = 0x80;
462
463        r = sc_transmit_apdu(card, &apdu);
464        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
465        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
466        return r;
467}
468
469static int
470akis_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
471{
472        switch (cmd) {
473        case SC_CARDCTL_GET_SERIALNR:
474                return akis_get_serialnr(card, (sc_serial_number_t *)ptr);
475        case SC_CARDCTL_LIFECYCLE_GET:
476                return akis_lifecycle_get(card, (int *) ptr);
477        case SC_CARDCTL_LIFECYCLE_SET:
478                return akis_lifecycle_set(card, (int *) ptr);
479        }
480        return SC_ERROR_NOT_SUPPORTED;
481}
482
483static int
484akis_set_security_env(sc_card_t *card,
485                      const sc_security_env_t *env,
486                      int se_num)
487{
488        int r;
489        u8 ref;
490        sc_apdu_t apdu;
491
492        /* AKIS uses key references for accessing keys
493         */
494        if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
495                ref = env->key_ref[0];
496                sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0xC3, ref);
497                r = sc_transmit_apdu(card, &apdu);
498                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
499                r = sc_check_sw(card, apdu.sw1, apdu.sw2);
500                return r;
501        }
502        return SC_SUCCESS;
503}
504
505static int
506akis_logout(sc_card_t *card)
507{
508        int r;
509        sc_apdu_t apdu;
510
511        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x1A, 0, 0);
512        apdu.cla = 0x80;
513        r = sc_transmit_apdu(card, &apdu);
514        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
515        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
516        return r;
517}
518
519static struct sc_card_driver *
520sc_get_driver(void)
521{
522        if (iso_ops == NULL)
523                iso_ops = sc_get_iso7816_driver()->ops;
524
525        akis_ops = *iso_ops;
526
527        akis_ops.match_card = akis_match_card;
528        akis_ops.init = akis_init;
529        /* read_binary: ISO7816 implementation works */
530        /* write_binary: ISO7816 implementation works */
531        /* update_binary: ISO7816 implementation works */
532        /* erase_binary: Untested */
533        /* read_record: Untested */
534        /* write_record: Untested */
535        /* append_record: Untested */
536        /* update_record: Untested */
537        akis_ops.select_file = akis_select_file;
538        /* get_response: ISO7816 implementation works */
539        /* get_challenge: ISO7816 implementation works */
540        akis_ops.logout = akis_logout;
541        /* restore_security_env: Untested */
542        akis_ops.set_security_env = akis_set_security_env;
543        /* decipher: Untested */
544        /* compute_signature: ISO7816 implementation works */
545        akis_ops.create_file = akis_create_file;
546        akis_ops.delete_file = akis_delete_file;
547        akis_ops.list_files = akis_list_files;
548        /* check_sw: ISO7816 implementation works */
549        akis_ops.card_ctl = akis_card_ctl;
550        akis_ops.process_fci = akis_process_fci;
551        /* construct_fci: Not needed */
552        akis_ops.pin_cmd = akis_pin_cmd;
553        akis_ops.get_data = akis_get_data;
554        /* put_data: Not implemented */
555        /* delete_record: Not implemented */
556
557        return &akis_drv;
558}
559
560#if 1
561struct sc_card_driver *
562sc_get_akis_driver(void)
563{
564        return sc_get_driver();
565}
566#endif
Note: See TracBrowser for help on using the browser.