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

Revision 3085, 12.5 KB (checked in by aj, 2 years ago)

convert to utf-8.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * card-miocos.c: Support for PKI cards by Miotec
3 *
4 * Copyright (C) 2002  Juha YrjölÀ <juha.yrjola@iki.fi>
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 "internal.h"
22#include "asn1.h"
23#include "cardctl.h"
24#include <stdlib.h>
25#include <string.h>
26
27static struct sc_atr_table miocos_atrs[] = {
28        /* Test card with 32 kB memory */
29        { "3B:9D:94:40:23:00:68:10:11:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL },
30        /* Test card with 64 kB memory */
31        { "3B:9D:94:40:23:00:68:20:01:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL },
32        { NULL, NULL, NULL, 0, 0, NULL }
33};
34
35static struct sc_card_operations miocos_ops;
36static struct sc_card_driver miocos_drv = {
37        "MioCOS 1.1",
38        "miocos",
39        &miocos_ops,
40        NULL, 0, NULL
41};
42
43static int miocos_finish(sc_card_t *card)
44{
45        return 0;
46}
47
48static int miocos_match_card(sc_card_t *card)
49{
50        int i;
51
52        i = _sc_match_atr(card, miocos_atrs, &card->type);
53        if (i < 0)
54                return 0;
55        return 1;
56}
57
58static int miocos_init(sc_card_t *card)
59{
60        card->name = "MioCOS";
61        card->cla = 0x00;
62
63        if (1) {
64                unsigned long flags;
65               
66                flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
67                flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
68
69                _sc_card_add_rsa_alg(card, 1024, flags, 0);
70        }
71
72        /* read_binary and friends shouldn't do more than 244 bytes
73         * per operation */
74        if (card->max_send_size > 244)
75                card->max_send_size = 244;
76        if (card->max_recv_size > 244)
77                card->max_recv_size = 244;
78
79        return 0;
80}
81
82static const struct sc_card_operations *iso_ops = NULL;
83
84static int acl_to_byte(const sc_acl_entry_t *e)
85{
86        switch (e->method) {
87        case SC_AC_NONE:
88                return 0x00;
89        case SC_AC_CHV:
90        case SC_AC_TERM:
91        case SC_AC_AUT:
92                if (e->key_ref == SC_AC_KEY_REF_NONE)
93                        return -1;
94                if (e->key_ref < 1 || e->key_ref > 14)
95                        return -1;
96                return e->key_ref;
97        case SC_AC_NEVER:
98                return 0x0F;
99        }
100        return 0x00;
101}
102
103static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
104                                 u8 *buf, size_t *buflen)
105{
106        u8 *p = buf;
107        const int df_ops[8] = {
108                SC_AC_OP_DELETE, SC_AC_OP_CREATE,
109                /* RFU */ -1, /* CREATE AC */ SC_AC_OP_CREATE,
110                /* UPDATE AC */ SC_AC_OP_CREATE, -1, -1, -1
111        };
112        const int ef_ops[8] = {
113                /* DELETE */ SC_AC_OP_UPDATE, -1, SC_AC_OP_READ,
114                SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
115                SC_AC_OP_REHABILITATE
116        };
117        const int key_ops[8] = {
118                /* DELETE */ SC_AC_OP_UPDATE, -1, -1,
119                SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
120                SC_AC_OP_REHABILITATE
121        };
122        const int *ops;
123        int i;
124
125        *p++ = file->id >> 8;
126        *p++ = file->id & 0xFF;
127        switch (file->type) {
128        case SC_FILE_TYPE_DF:
129                *p++ = 0x20;
130                ops = df_ops;
131                break;
132        case SC_FILE_TYPE_WORKING_EF:
133                switch (file->ef_structure) {
134                case SC_FILE_EF_TRANSPARENT:
135                        *p++ = 0x40;
136                        break;
137                case SC_FILE_EF_LINEAR_FIXED:
138                        *p++ = 0x41;
139                        break;
140                case SC_FILE_EF_CYCLIC:
141                        *p++ = 0x43;
142                        break;
143                default:
144                        sc_error(card->ctx, "Invalid EF structure\n");
145                        return SC_ERROR_INVALID_ARGUMENTS;
146                }
147                ops = ef_ops;
148                break;
149        case SC_FILE_TYPE_INTERNAL_EF:
150                *p++ = 0x44;
151                ops = key_ops;
152                break;
153        default:
154                sc_error(card->ctx, "Unknown file type\n");
155                return SC_ERROR_INVALID_ARGUMENTS;
156        }
157        if (file->type == SC_FILE_TYPE_DF) {
158                *p++ = 0;
159                *p++ = 0;
160        } else {
161                *p++ = file->size >> 8;
162                *p++ = file->size & 0xFF;
163        }
164        if (file->sec_attr_len == 4) {
165                memcpy(p, file->sec_attr, 4);
166                p += 4;
167        } else for (i = 0; i < 8; i++) {
168                u8 nibble;
169
170                if (ops[i] == -1)
171                        nibble = 0x00;
172                else {
173                        int byte = acl_to_byte(sc_file_get_acl_entry(file, ops[i]));
174                        if (byte < 0) {
175                                sc_error(card->ctx, "Invalid ACL\n");
176                                return SC_ERROR_INVALID_ARGUMENTS;
177                        }
178                        nibble = byte;
179                }
180                if ((i & 1) == 0)
181                        *p = nibble << 4;
182                else {
183                        *p |= nibble & 0x0F;
184                        p++;
185                }
186        }
187        if (file->type == SC_FILE_TYPE_WORKING_EF &&
188            file->ef_structure != SC_FILE_EF_TRANSPARENT)
189                *p++ = file->record_length;
190        else
191                *p++ = 0;
192        if (file->status & SC_FILE_STATUS_INVALIDATED)
193                *p++ = 0;
194        else
195                *p++ = 0x01;
196        if (file->type == SC_FILE_TYPE_DF && file->namelen) {
197                assert(file->namelen <= 16);
198                memcpy(p, file->name, file->namelen);
199                p += file->namelen;
200        }
201        *buflen = p - buf;
202
203        return 0;
204}
205
206static int miocos_create_file(sc_card_t *card, sc_file_t *file)
207{
208        sc_apdu_t apdu;
209        u8 sbuf[32];
210        size_t buflen;
211        int r;
212
213        r = encode_file_structure(card, file, sbuf, &buflen);
214        if (r)
215                return r;
216        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
217        apdu.data = sbuf;
218        apdu.datalen = buflen;
219        apdu.lc = buflen;
220
221        r = sc_transmit_apdu(card, &apdu);
222        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
223        if (apdu.sw1 == 0x6A && apdu.sw2 == 0x89)
224                return SC_ERROR_FILE_ALREADY_EXISTS;
225        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
226        SC_TEST_RET(card->ctx, r, "Card returned error");
227
228        return 0;
229}
230
231static int miocos_set_security_env(sc_card_t *card,
232                                  const sc_security_env_t *env,
233                                  int se_num)
234{
235        if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
236                sc_security_env_t tmp;
237
238                tmp = *env;
239                tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
240                tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
241                if (tmp.algorithm != SC_ALGORITHM_RSA) {
242                        sc_error(card->ctx, "Only RSA algorithm supported.\n");
243                        return SC_ERROR_NOT_SUPPORTED;
244                }
245                tmp.algorithm_ref = 0x00;
246                /* potential FIXME: return an error, if an unsupported
247                 * pad or hash was requested, although this shouldn't happen.
248                 */
249                if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
250                        tmp.algorithm_ref = 0x02;
251                if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
252                        tmp.algorithm_ref |= 0x10;
253                return iso_ops->set_security_env(card, &tmp, se_num);
254        }
255        return iso_ops->set_security_env(card, env, se_num);
256}
257
258static void add_acl_entry(sc_file_t *file, int op, u8 byte)
259{
260        unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
261
262        switch (byte) {
263        case 0:
264                method = SC_AC_NONE;
265                break;
266        case 15:
267                method = SC_AC_NEVER;
268                break;
269        default:
270                method = SC_AC_CHV;
271                key_ref = byte;
272                break;
273        }
274        sc_file_add_acl_entry(file, op, method, key_ref);
275}
276
277static void parse_sec_attr(sc_file_t *file, const u8 *buf, size_t len)
278{
279        int i;
280        const int df_ops[8] = {
281                SC_AC_OP_DELETE, SC_AC_OP_CREATE,
282                -1, /* CREATE AC */ -1, /* UPDATE AC */ -1, -1, -1, -1
283        };
284        const int ef_ops[8] = {
285                SC_AC_OP_DELETE, -1, SC_AC_OP_READ,
286                SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
287                SC_AC_OP_REHABILITATE
288        };
289        const int key_ops[8] = {
290                SC_AC_OP_DELETE, -1, -1,
291                SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
292                SC_AC_OP_REHABILITATE
293        };
294        const int *ops;
295
296        if (len < 4)
297                return;
298        switch (file->type) {
299        case SC_FILE_TYPE_WORKING_EF:
300                ops = ef_ops;
301                break;
302        case SC_FILE_TYPE_INTERNAL_EF:
303                ops = key_ops;
304                break;
305        case SC_FILE_TYPE_DF:
306                ops = df_ops;
307                break;
308        default:
309                return;
310        }
311        for (i = 0; i < 8; i++) {
312                if (ops[i] == -1)
313                        continue;
314                if ((i & 1) == 0)
315                        add_acl_entry(file, ops[i], (u8)(buf[i / 2] >> 4));
316                else
317                        add_acl_entry(file, ops[i], (u8)(buf[i / 2] & 0x0F));
318        }
319}
320
321static int miocos_get_acl(sc_card_t *card, sc_file_t *file)
322{
323        sc_apdu_t apdu;
324        u8 rbuf[256];
325        const u8 *seq = rbuf;
326        size_t left;
327        int acl_types[16], r;
328        unsigned int i;
329       
330        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x01);
331        apdu.resp = rbuf;
332        apdu.resplen = sizeof(rbuf);
333        apdu.le = sizeof(rbuf);
334        r = sc_transmit_apdu(card, &apdu);
335        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
336        if (apdu.resplen == 0)
337                return sc_check_sw(card, apdu.sw1, apdu.sw2);
338        for (i = 0; i < 16; i++)
339                acl_types[i] = SC_AC_KEY_REF_NONE;
340        left = apdu.resplen;
341        seq = sc_asn1_skip_tag(card->ctx, &seq, &left,
342                               SC_ASN1_SEQUENCE | SC_ASN1_CONS, &left);
343        if (seq == NULL)
344                SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_UNKNOWN_DATA_RECEIVED);
345        SC_TEST_RET(card->ctx, r, "Unable to process reply");
346        for (i = 1; i < 15; i++) {
347                int j;
348                const u8 *tag;
349                size_t taglen;
350               
351                tag = sc_asn1_skip_tag(card->ctx, &seq, &left,
352                                       SC_ASN1_CTX | i, &taglen);
353                if (tag == NULL || taglen == 0)
354                        continue;
355                for (j = 0; j < SC_MAX_AC_OPS; j++) {
356                        sc_acl_entry_t *e;
357                       
358                        e = (sc_acl_entry_t *) sc_file_get_acl_entry(file, j);
359                        if (e == NULL)
360                                continue;
361                        if (e->method != SC_AC_CHV)
362                                continue;
363                        if (e->key_ref != i)
364                                continue;
365                        switch (tag[0]) {
366                        case 0x01:
367                                e->method = SC_AC_CHV;
368                                break;
369                        case 0x02:
370                                e->method = SC_AC_AUT;
371                                break;
372                        default:
373                                e->method = SC_AC_UNKNOWN;
374                                break;
375                        }
376                }
377        }
378        return 0;
379}
380
381static int miocos_select_file(sc_card_t *card,
382                               const sc_path_t *in_path,
383                               sc_file_t **file)
384{
385        int r;
386
387        r = iso_ops->select_file(card, in_path, file);
388        if (r)
389                return r;
390        if (file != NULL) {
391                parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
392                miocos_get_acl(card, *file);
393        }
394
395        return 0;
396}
397
398static int miocos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
399{
400        sc_apdu_t apdu;
401        int r;
402
403        sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0);
404        apdu.resp = buf;
405        apdu.resplen = buflen;
406        apdu.le = buflen > 256 ? 256 : buflen;
407        r = sc_transmit_apdu(card, &apdu);
408        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
409        if (apdu.resplen == 0)
410                return sc_check_sw(card, apdu.sw1, apdu.sw2);
411        return apdu.resplen;
412}
413
414static int miocos_delete_file(sc_card_t *card, const sc_path_t *path)
415{
416        int r;
417        sc_apdu_t apdu;
418
419        SC_FUNC_CALLED(card->ctx, 1);
420        if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
421                sc_error(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
422                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
423        }
424        r = sc_select_file(card, path, NULL);
425        SC_TEST_RET(card->ctx, r, "Unable to select file to be deleted");
426       
427        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
428        apdu.cla = 0xA0;
429
430        r = sc_transmit_apdu(card, &apdu);
431        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
432        return sc_check_sw(card, apdu.sw1, apdu.sw2);
433}
434
435static int miocos_create_ac(sc_card_t *card,
436                            struct sc_cardctl_miocos_ac_info *ac)
437{
438        sc_apdu_t apdu;
439        u8 sbuf[20];
440        int miocos_type, r;
441        size_t sendsize;
442       
443        if (ac->max_tries > 15)
444                SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_INVALID_ARGUMENTS);
445        switch (ac->type) {
446        case SC_CARDCTL_MIOCOS_AC_PIN:
447                if (ac->max_unblock_tries > 15)
448                        SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_INVALID_ARGUMENTS);
449                miocos_type = 0x01;
450                sbuf[0] = (ac->max_tries << 4) | ac->max_tries;
451                sbuf[1] = 0xFF; /* FIXME... */
452                memcpy(sbuf + 2, ac->key_value, 8);
453                sbuf[10] = (ac->max_unblock_tries << 4) | ac->max_unblock_tries;
454                sbuf[11] = 0xFF;
455                memcpy(sbuf + 12, ac->unblock_value, 8);
456                sendsize = 20;
457                break;
458        default:
459                sc_error(card->ctx, "AC type %d not supported\n", ac->type);
460                return SC_ERROR_NOT_SUPPORTED;
461        }
462        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x1E, miocos_type,
463                       ac->ref);
464        apdu.lc = sendsize;
465        apdu.datalen = sendsize;
466        apdu.data = sbuf;
467        r = sc_transmit_apdu(card, &apdu);
468        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
469        return sc_check_sw(card, apdu.sw1, apdu.sw2);
470}
471
472static int miocos_card_ctl(sc_card_t *card, unsigned long cmd,
473                           void *arg)
474{
475        switch (cmd) {
476        case SC_CARDCTL_MIOCOS_CREATE_AC:
477                return miocos_create_ac(card, (struct sc_cardctl_miocos_ac_info *) arg);
478        }
479        sc_error(card->ctx, "card_ctl command 0x%X not supported\n", cmd);
480        return SC_ERROR_NOT_SUPPORTED;
481}
482
483
484static struct sc_card_driver * sc_get_driver(void)
485{
486        struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
487
488        miocos_ops = *iso_drv->ops;
489        miocos_ops.match_card = miocos_match_card;
490        miocos_ops.init = miocos_init;
491        miocos_ops.finish = miocos_finish;
492        if (iso_ops == NULL)
493                iso_ops = iso_drv->ops;
494        miocos_ops.create_file = miocos_create_file;
495        miocos_ops.set_security_env = miocos_set_security_env;
496        miocos_ops.select_file = miocos_select_file;
497        miocos_ops.list_files = miocos_list_files;
498        miocos_ops.delete_file = miocos_delete_file;
499        miocos_ops.card_ctl = miocos_card_ctl;
500       
501        return &miocos_drv;
502}
503
504#if 1
505struct sc_card_driver * sc_get_miocos_driver(void)
506{
507        return sc_get_driver();
508}
509#endif
Note: See TracBrowser for help on using the browser.