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

Revision 3502, 24.3 KB (checked in by ludovic.rousseau, 7 months ago)

convert C++ in C comment

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * card-tcos.c: Support for TCOS cards
3 *
4 * Copyright (C) 2007  Peter Koch <Koch@smartcard-auth.de>
5 * Copyright (C) 2002  g10 Code GmbH
6 * Copyright (C) 2001  Juha YrjölÀ <juha.yrjola@iki.fi>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22
23#include "internal.h"
24#include "asn1.h"
25#include "cardctl.h"
26#include <string.h>
27#include <ctype.h>
28#include <time.h>
29#include <stdlib.h>
30
31static struct sc_atr_table tcos_atrs[] = {
32        /* Infineon SLE44 */
33        { "3B:BA:13:00:81:31:86:5D:00:64:05:0A:02:01:31:80:90:00:8B", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
34        /* Infineon SLE66S */
35        { "3B:BA:14:00:81:31:86:5D:00:64:05:14:02:02:31:80:90:00:91", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
36        /* Infineon SLE66CX320P */
37        { "3B:BA:96:00:81:31:86:5D:00:64:05:60:02:03:31:80:90:00:66", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
38        /* Infoneon SLE66CX322P */
39        { "3B:BA:96:00:81:31:86:5D:00:64:05:7B:02:03:31:80:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
40        /* Philips P5CT072 */
41        { "3B:BF:96:00:81:31:FE:5D:00:64:04:11:03:01:31:C0:73:F7:01:D0:00:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL },
42        { NULL, NULL, NULL, 0, 0, NULL }
43};
44
45static struct sc_card_operations tcos_ops;
46static struct sc_card_driver tcos_drv = {
47        "TCOS 3.0",
48        "tcos",
49        &tcos_ops,
50        NULL, 0, NULL
51};
52
53static const struct sc_card_operations *iso_ops = NULL;
54
55typedef struct tcos_data_st {
56        unsigned int pad_flags;
57        unsigned int next_sign;
58} tcos_data;
59
60
61static int tcos_finish(sc_card_t *card)
62{
63        free(card->drv_data);
64        return 0;
65}
66
67
68static int tcos_match_card(sc_card_t *card)
69{
70        int i;
71
72        i = _sc_match_atr(card, tcos_atrs, &card->type);
73        if (i < 0)
74                return 0;
75        return 1;
76}
77
78
79static int tcos_init(sc_card_t *card)
80{
81        unsigned long flags;
82
83        tcos_data *data = (tcos_data *) malloc(sizeof(tcos_data));
84        if (!data) return SC_ERROR_OUT_OF_MEMORY;
85
86        card->name = "TCOS";
87        card->drv_data = (void *)data;
88        card->cla = 0x00;
89
90        flags = SC_ALGORITHM_RSA_RAW;
91        flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
92        flags |= SC_ALGORITHM_RSA_HASH_NONE;
93
94        _sc_card_add_rsa_alg(card, 512, flags, 0);
95        _sc_card_add_rsa_alg(card, 768, flags, 0);
96        _sc_card_add_rsa_alg(card, 1024, flags, 0);
97
98        if (card->type == SC_CARD_TYPE_TCOS_V3) {
99                card->caps |= SC_CARD_CAP_RSA_2048|SC_CARD_CAP_APDU_EXT;
100                _sc_card_add_rsa_alg(card, 1280, flags, 0);
101                _sc_card_add_rsa_alg(card, 1536, flags, 0);
102                _sc_card_add_rsa_alg(card, 1792, flags, 0);
103                _sc_card_add_rsa_alg(card, 2048, flags, 0);
104        }
105
106        return 0;
107}
108
109
110/* Hmmm, I don't know what to do.  It seems that the ACL design of
111   OpenSC should be enhanced to allow for the command based security
112   attributes of TCOS.  FIXME: This just allows to create a very basic
113   file. */
114static int tcos_construct_fci(const sc_file_t *file,
115                              u8 *out, size_t *outlen)
116{
117        u8 *p = out;
118        u8 buf[64];
119        size_t n;
120
121        /* FIXME: possible buffer overflow */
122
123        *p++ = 0x6F; /* FCI */
124        p++;
125
126        /* File size */
127        buf[0] = (file->size >> 8) & 0xFF;
128        buf[1] = file->size & 0xFF;
129        sc_asn1_put_tag(0x81, buf, 2, p, 16, &p);
130
131        /* File descriptor */
132        n = 0;
133        buf[n] = file->shareable ? 0x40 : 0;
134        switch (file->type) {
135        case SC_FILE_TYPE_WORKING_EF:
136                break;
137        case SC_FILE_TYPE_DF:
138                buf[0] |= 0x38;
139                break;
140        default:
141                return SC_ERROR_NOT_SUPPORTED;
142        }
143        buf[n++] |= file->ef_structure & 7;
144        if ( (file->ef_structure & 7) > 1) {
145                /* record structured file */
146                buf[n++] = 0x41; /* indicate 3rd byte */
147                buf[n++] = file->record_length;
148        }
149        sc_asn1_put_tag(0x82, buf, n, p, 8, &p);
150
151        /* File identifier */
152        buf[0] = (file->id >> 8) & 0xFF;
153        buf[1] = file->id & 0xFF;
154        sc_asn1_put_tag(0x83, buf, 2, p, 16, &p);
155
156        /* Directory name */
157        if (file->type == SC_FILE_TYPE_DF) {
158                if (file->namelen) {
159                        if (file->namelen > 16 || !file->name)
160                                return SC_ERROR_INVALID_ARGUMENTS;
161                        sc_asn1_put_tag(0x84, file->name, file->namelen,
162                                        p, 16, &p);
163                }
164                else {
165                        /* TCOS needs one, so we use a faked one */
166                        snprintf ((char *) buf, sizeof(buf)-1, "foo-%lu",
167                                  (unsigned long) time (NULL));
168                        sc_asn1_put_tag(0x84, buf, strlen ((char *) buf), p, 16, &p);
169                }
170        }
171
172        /* File descriptor extension */
173        if (file->prop_attr_len && file->prop_attr) {
174                n = file->prop_attr_len;
175                memcpy(buf, file->prop_attr, n);
176        }
177        else {
178                n = 0;
179                buf[n++] = 0x01; /* not invalidated, permanent */
180                if (file->type == SC_FILE_TYPE_WORKING_EF)
181                        buf[n++] = 0x00; /* generic data file */
182        }
183        sc_asn1_put_tag(0x85, buf, n, p, 16, &p);
184
185        /* Security attributes */
186        if (file->sec_attr_len && file->sec_attr) {
187                memcpy(buf, file->sec_attr, file->sec_attr_len);
188                n = file->sec_attr_len;
189        }
190        else {
191                /* no attributes given - fall back to default one */
192                memcpy (buf+ 0, "\xa4\x00\x00\x00\xff\xff", 6); /* select */
193                memcpy (buf+ 6, "\xb0\x00\x00\x00\xff\xff", 6); /* read bin */
194                memcpy (buf+12, "\xd6\x00\x00\x00\xff\xff", 6); /* upd bin */
195                memcpy (buf+18, "\x60\x00\x00\x00\xff\xff", 6); /* admin grp*/
196                n = 24;
197        }
198        sc_asn1_put_tag(0x86, buf, n, p, sizeof (buf), &p);
199
200       
201        /* fixup length of FCI */
202        out[1] = p - out - 2;
203
204        *outlen = p - out;
205        return 0;
206}
207
208
209static int tcos_create_file(sc_card_t *card, sc_file_t *file)
210{
211        int r;
212        size_t len;
213        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
214        sc_apdu_t apdu;
215
216        len = SC_MAX_APDU_BUFFER_SIZE;
217        r = tcos_construct_fci(file, sbuf, &len);
218        SC_TEST_RET(card->ctx, r, "tcos_construct_fci() failed");
219       
220        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
221        apdu.cla |= 0x80;  /* this is an proprietary extension */
222        apdu.lc = len;
223        apdu.datalen = len;
224        apdu.data = sbuf;
225
226        r = sc_transmit_apdu(card, &apdu);
227        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
228        return sc_check_sw(card, apdu.sw1, apdu.sw2);
229}
230
231
232static unsigned int map_operations (int commandbyte )
233{
234        unsigned int op = (unsigned int)-1;
235
236        switch ( (commandbyte & 0xfe) ) {
237                case 0xe2: /* append record */   op = SC_AC_OP_UPDATE; break;
238                case 0x24: /* change password */ op = SC_AC_OP_UPDATE; break;
239                case 0xe0: /* create */          op = SC_AC_OP_CREATE; break;
240                case 0xe4: /* delete */          op = SC_AC_OP_DELETE; break;
241                case 0xe8: /* exclude sfi */     op = SC_AC_OP_WRITE; break;
242                case 0x82: /* external auth */   op = SC_AC_OP_READ; break;
243                case 0xe6: /* include sfi */     op = SC_AC_OP_WRITE; break;
244                case 0x88: /* internal auth */   op = SC_AC_OP_READ; break;
245                case 0x04: /* invalidate */      op = SC_AC_OP_INVALIDATE; break;
246                case 0x2a: /* perform sec. op */ op = SC_AC_OP_SELECT; break;
247                case 0xb0: /* read binary */     op = SC_AC_OP_READ; break;
248                case 0xb2: /* read record */     op = SC_AC_OP_READ; break;
249                case 0x44: /* rehabilitate */    op = SC_AC_OP_REHABILITATE; break;
250                case 0xa4: /* select */          op = SC_AC_OP_SELECT; break;
251                case 0xee: /* set permanent */   op = SC_AC_OP_CREATE; break;
252                case 0x2c: /* unblock password */op = SC_AC_OP_WRITE; break;
253                case 0xd6: /* update binary */   op = SC_AC_OP_WRITE; break;
254                case 0xdc: /* update record */   op = SC_AC_OP_WRITE; break;
255                case 0x20: /* verify password */ op = SC_AC_OP_SELECT; break;
256                case 0x60: /* admin group */     op = SC_AC_OP_CREATE; break;
257        }
258        return op;
259}
260
261
262/* Hmmm, I don't know what to do.  It seems that the ACL design of
263   OpenSC should be enhanced to allow for the command based security
264   attributes of TCOS.  FIXME: This just allows to create a very basic
265   file. */
266static void parse_sec_attr(sc_card_t *card,
267                           sc_file_t *file, const u8 *buf, size_t len)
268{
269        unsigned int op;
270       
271        /* list directory is not covered by ACLs - so always add an entry */
272        sc_file_add_acl_entry (file, SC_AC_OP_LIST_FILES,
273                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
274        /* FIXME: check for what LOCK is used */
275        sc_file_add_acl_entry (file, SC_AC_OP_LOCK,
276                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
277        for (; len >= 6; len -= 6, buf += 6) {
278                /* FIXME: temporary hacks */
279                if (!memcmp(buf, "\xa4\x00\x00\x00\xff\xff", 6)) /* select */
280                        sc_file_add_acl_entry (file, SC_AC_OP_SELECT,
281                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
282                else if (!memcmp(buf, "\xb0\x00\x00\x00\xff\xff", 6)) /*read*/
283                        sc_file_add_acl_entry (file, SC_AC_OP_READ,
284                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
285                else if (!memcmp(buf, "\xd6\x00\x00\x00\xff\xff", 6)) /*upd*/
286                        sc_file_add_acl_entry (file, SC_AC_OP_UPDATE,
287                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
288                else if (!memcmp(buf, "\x60\x00\x00\x00\xff\xff", 6)) {/*adm */
289                        sc_file_add_acl_entry (file, SC_AC_OP_WRITE,
290                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
291                        sc_file_add_acl_entry (file, SC_AC_OP_CREATE,
292                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
293                        sc_file_add_acl_entry (file, SC_AC_OP_INVALIDATE,
294                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
295                        sc_file_add_acl_entry (file, SC_AC_OP_REHABILITATE,
296                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
297                }
298                else {
299                        /* the first byte tells use the command or the
300                           command group.  We have to mask bit 0
301                           because this one distinguish between AND/OR
302                           combination of PINs*/
303                        op = map_operations (buf[0]);
304                        if (op == (unsigned int)-1)
305                        {
306                                sc_debug (card->ctx,
307                                       "Unknown security command byte %02x\n",
308                                       buf[0]);
309                                continue;
310                        }
311                        if (!buf[1])
312                                sc_file_add_acl_entry (file, op,
313                                                       SC_AC_NONE,
314                                                       SC_AC_KEY_REF_NONE);
315                        else
316                                sc_file_add_acl_entry (file, op,
317                                                       SC_AC_CHV, buf[1]);
318
319                        if (!buf[2] && !buf[3])
320                                sc_file_add_acl_entry (file, op,
321                                                       SC_AC_NONE,
322                                                       SC_AC_KEY_REF_NONE);
323                        else
324                                sc_file_add_acl_entry (file, op,
325                                                       SC_AC_TERM,
326                                                       (buf[2]<<8)|buf[3]);
327                }
328        }
329}
330
331
332static int tcos_select_file(sc_card_t *card,
333                            const sc_path_t *in_path,
334                            sc_file_t **file_out)
335{
336        sc_context_t *ctx;
337        sc_apdu_t apdu;
338        sc_file_t *file=NULL;
339        u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
340        int i, r, pathlen;
341
342        assert(card != NULL && in_path != NULL);
343        ctx=card->ctx;
344        memcpy(path, in_path->value, in_path->len);
345        pathlen = in_path->len;
346
347        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x04);
348       
349        switch (in_path->type) {
350        case SC_PATH_TYPE_FILE_ID:
351                if (pathlen != 2) return SC_ERROR_INVALID_ARGUMENTS;
352        case SC_PATH_TYPE_FROM_CURRENT:
353                apdu.p1 = 9;
354                break;
355        case SC_PATH_TYPE_DF_NAME:
356                apdu.p1 = 4;
357                break;
358        case SC_PATH_TYPE_PATH:
359                apdu.p1 = 8;
360                if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) path += 2, pathlen -= 2;
361                if (pathlen == 0) apdu.p1 = 0;
362                break;
363        case SC_PATH_TYPE_PARENT:
364                apdu.p1 = 3;
365                pathlen = 0;
366                break;
367        default:
368                SC_FUNC_RETURN(ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
369        }
370        if( pathlen == 0 ) apdu.cse = SC_APDU_CASE_2_SHORT;
371
372        apdu.lc = pathlen;
373        apdu.data = path;
374        apdu.datalen = pathlen;
375
376        if (file_out != NULL) {
377                apdu.resp = buf;
378                apdu.resplen = sizeof(buf);
379                apdu.le = 256;
380        } else {
381                apdu.resplen = 0;
382                apdu.le = 0;
383                apdu.p2 = 0x0C;
384                apdu.cse = (pathlen == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT;
385        }
386
387        r = sc_transmit_apdu(card, &apdu);
388        SC_TEST_RET(ctx, r, "APDU transmit failed");
389        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
390        if (r || file_out == NULL) SC_FUNC_RETURN(ctx, 2, r);
391
392        if (apdu.resplen < 1 || apdu.resp[0] != 0x62){
393                sc_debug(ctx, "received invalid template %02X\n", apdu.resp[0]);
394                SC_FUNC_RETURN(ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
395        }
396
397        file = sc_file_new();
398        if (file == NULL) SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY);
399        file->path = *in_path;
400
401        for(i=2; i+1<apdu.resplen && i+1+apdu.resp[i+1]<apdu.resplen; i+=2+apdu.resp[i+1]){
402                int j, len=apdu.resp[i+1];
403                unsigned char type=apdu.resp[i], *d=apdu.resp+i+2;
404
405                switch (type) {
406                case 0x80:
407                case 0x81:
408                        file->size=0;
409                        for(j=0; j<len; ++j) file->size = (file->size<<8) | d[j];
410                        break;
411                case 0x82:
412                        file->shareable = (d[0] & 0x40) ? 1 : 0;
413                        file->ef_structure = d[0] & 7;
414                        switch ((d[0]>>3) & 7) {
415                        case 0: file->type = SC_FILE_TYPE_WORKING_EF; break;
416                        case 7: file->type = SC_FILE_TYPE_DF; break;
417                        default:
418                                sc_debug(ctx, "invalid file type %02X in file descriptor\n", d[0]);
419                                SC_FUNC_RETURN(ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
420                        }
421                        break;
422                case 0x83:
423                        file->id = (d[0]<<8) | d[1];
424                        break;
425                case 0x84:
426                        memcpy(file->name, d, len);
427                        file->namelen = len;
428                        break;
429                case 0x86:
430                        sc_file_set_sec_attr(file, d, len);
431                        break;
432                default:
433                        if (len>0) sc_file_set_prop_attr(file, d, len);
434                }
435        }
436        file->magic = SC_FILE_MAGIC;
437        *file_out = file;
438
439        parse_sec_attr(card, file, file->sec_attr, file->sec_attr_len);
440
441        return 0;
442}
443
444
445static int tcos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
446{
447        sc_context_t *ctx;
448        sc_apdu_t apdu;
449        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], p1;
450        int r, count = 0;
451
452        assert(card != NULL);
453        ctx = card->ctx;
454
455        for (p1=1; p1<=2; p1++) {
456                sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, p1, 0);
457                apdu.cla = 0x80;
458                apdu.resp = rbuf;
459                apdu.resplen = sizeof(rbuf);
460                apdu.le = 256;
461                r = sc_transmit_apdu(card, &apdu);
462                SC_TEST_RET(ctx, r, "APDU transmit failed");
463                if (apdu.sw1==0x6A && (apdu.sw2==0x82 || apdu.sw2==0x88)) continue;
464                r = sc_check_sw(card, apdu.sw1, apdu.sw2);
465                SC_TEST_RET(ctx, r, "List Dir failed");
466                if (apdu.resplen > buflen) return SC_ERROR_BUFFER_TOO_SMALL;
467                if(ctx->debug >= 3) sc_debug(ctx, "got %d %s-FileIDs\n", apdu.resplen/2, p1==1 ? "DF" : "EF");
468
469                memcpy(buf, apdu.resp, apdu.resplen);
470                buf += apdu.resplen;
471                buflen -= apdu.resplen;
472                count += apdu.resplen;
473        }
474        return count;
475}
476
477
478static int tcos_delete_file(sc_card_t *card, const sc_path_t *path)
479{
480        int r;
481        u8 sbuf[2];
482        sc_apdu_t apdu;
483
484        SC_FUNC_CALLED(card->ctx, 1);
485        if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
486                sc_error(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
487                SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
488        }
489        sbuf[0] = path->value[0];
490        sbuf[1] = path->value[1];
491        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
492        apdu.cla |= 0x80;
493        apdu.lc = 2;
494        apdu.datalen = 2;
495        apdu.data = sbuf;
496       
497        r = sc_transmit_apdu(card, &apdu);
498        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
499        return sc_check_sw(card, apdu.sw1, apdu.sw2);
500}
501
502
503static int tcos_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num)
504{
505        sc_context_t *ctx;
506        sc_apdu_t apdu;
507        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
508        int r, default_key, tcos3;
509        tcos_data *data;
510
511        assert(card != NULL && env != NULL);
512        ctx = card->ctx;
513        tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
514        data=(tcos_data *)card->drv_data;
515
516        if (se_num || (env->operation!=SC_SEC_OPERATION_DECIPHER && env->operation!=SC_SEC_OPERATION_SIGN)){
517                SC_FUNC_RETURN(ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
518        }
519        if(ctx->debug >= 3){
520                if(!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)) sc_debug(ctx, "No Key-Reference in SecEnvironment\n");
521                else sc_debug(ctx, "Key-Reference %02X (len=%d)\n", env->key_ref[0], env->key_ref_len);
522        }
523        /* Key-Reference 0x80 ?? */
524        default_key= !(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || (env->key_ref_len==1 && env->key_ref[0]==0x80);
525        if(ctx->debug>=3){
526                sc_debug(ctx, "TCOS3:%d PKCS1:%d\n", tcos3, !!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1));
527        }
528
529        data->pad_flags = env->algorithm_flags;
530        data->next_sign = default_key;
531
532        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, tcos3 ? 0x41 : 0xC1, 0xB8);
533        p = sbuf;
534        *p++=0x80; *p++=0x01; *p++=tcos3 ? 0x0A : 0x10;
535        if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
536                *p++ = (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) ? 0x83 : 0x84;
537                *p++ = env->key_ref_len;
538                memcpy(p, env->key_ref, env->key_ref_len);
539                p += env->key_ref_len;
540        }
541        apdu.data = sbuf;
542        apdu.lc = apdu.datalen = (p - sbuf);
543
544        if ((r=sc_transmit_apdu(card, &apdu))) {
545                sc_perror(ctx, r, "APDU transmit failed");
546                return r;
547        }
548        if (apdu.sw1==0x6A && (apdu.sw2==0x81 || apdu.sw2==0x88)) {
549                if (ctx->debug >= 3) sc_debug(ctx, "Detected Signature-Only key\n");
550                if (env->operation==SC_SEC_OPERATION_SIGN && default_key) return SC_SUCCESS;
551        }
552        SC_FUNC_RETURN(ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
553}
554
555
556static int tcos_restore_security_env(sc_card_t *card, int se_num)
557{
558        return 0;
559}
560
561
562static int tcos_compute_signature(sc_card_t *card, const u8 * data, size_t datalen, u8 * out, size_t outlen)
563{
564        size_t i, dlen=datalen;
565        sc_apdu_t apdu;
566        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
567        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
568        int tcos3, r;
569
570        assert(card != NULL && data != NULL && out != NULL);
571        tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
572
573        if (datalen > 255) SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
574
575        if(((tcos_data *)card->drv_data)->next_sign){
576                if(datalen>48){
577                        sc_error(card->ctx, "Data to be signed is too long (TCOS supports max. 48 bytes)\n");
578                        SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
579                }
580                sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
581                memcpy(sbuf, data, datalen);
582                dlen=datalen;
583        } else {
584                int keylen= tcos3 ? 256 : 128;
585                sc_format_apdu(card, &apdu, keylen>255 ? SC_APDU_CASE_4_EXT : SC_APDU_CASE_4_SHORT, 0x2A,0x80,0x86);
586                for(i=0; i<sizeof(sbuf);++i) sbuf[i]=0xff;
587                sbuf[0]=0x02; sbuf[1]=0x00; sbuf[2]=0x01; sbuf[keylen-datalen]=0x00;
588                memcpy(sbuf+keylen-datalen+1, data, datalen);
589                dlen=keylen+1;
590        }
591        apdu.resp = rbuf;
592        apdu.resplen = sizeof(rbuf);
593        apdu.le = tcos3 ? 256 : 128;
594        apdu.data = sbuf;
595        apdu.lc = apdu.datalen = dlen;
596
597        r = sc_transmit_apdu(card, &apdu);
598        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
599        if (tcos3 && apdu.p1==0x80 && apdu.sw1==0x6A && apdu.sw2==0x87) {
600                int keylen=128;
601                sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A,0x80,0x86);
602                for(i=0; i<sizeof(sbuf);++i) sbuf[i]=0xff;
603                sbuf[0]=0x02; sbuf[1]=0x00; sbuf[2]=0x01; sbuf[keylen-datalen]=0x00;
604                memcpy(sbuf+keylen-datalen+1, data, datalen);
605                dlen=keylen+1;
606
607                apdu.resp = rbuf;
608                apdu.resplen = sizeof(rbuf);
609                apdu.le = 128;
610                apdu.data = sbuf;
611                apdu.lc = apdu.datalen = dlen;
612                r = sc_transmit_apdu(card, &apdu);
613                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
614        }
615        if (apdu.sw1==0x90 && apdu.sw2==0x00) {
616                size_t len = apdu.resplen>outlen ? outlen : apdu.resplen;
617                memcpy(out, apdu.resp, len);
618                SC_FUNC_RETURN(card->ctx, 4, len);
619        }
620        SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
621}
622
623
624static int tcos_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
625{
626        sc_context_t *ctx;
627        sc_apdu_t apdu;
628        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
629        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
630        tcos_data *data;
631        int tcos3, r;
632
633        assert(card != NULL && crgram != NULL && out != NULL);
634        ctx = card->ctx;
635        tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
636        data=(tcos_data *)card->drv_data;
637
638        SC_FUNC_CALLED(ctx, 2);
639        if(ctx->debug>=3) sc_debug(ctx, "TCOS3:%d PKCS1:%d\n",tcos3,!!(data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1));
640
641        sc_format_apdu(card, &apdu, crgram_len>255 ? SC_APDU_CASE_4_EXT : SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
642        apdu.resp = rbuf;
643        apdu.resplen = sizeof(rbuf);
644        apdu.le = crgram_len;
645
646        apdu.data = sbuf;
647        apdu.lc = apdu.datalen = crgram_len+1;
648        sbuf[0] = tcos3 ? 0x00 : ((data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) ? 0x81 : 0x02);
649        memcpy(sbuf+1, crgram, crgram_len);
650
651        r = sc_transmit_apdu(card, &apdu);
652        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
653
654        if (apdu.sw1==0x90 && apdu.sw2==0x00) {
655                size_t len= (apdu.resplen>outlen) ? outlen : apdu.resplen;
656                int offset=0;
657                if(tcos3 && (data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) && apdu.resp[0]==0 && apdu.resp[1]==2){
658                        offset=2; while(offset<len && apdu.resp[offset]!=0) ++offset;
659                        offset=(offset<len-1) ? offset+1 : 0;
660                }
661                memcpy(out, apdu.resp+offset, len-offset);
662                SC_FUNC_RETURN(card->ctx, 2, len-offset);
663        }
664        SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
665}
666
667
668/* Issue the SET PERMANENT command.  With ENABLE_NULLPIN set the
669   NullPIN method will be activated, otherwise the permanent operation
670   will be done on the active file. */
671static int tcos_setperm(sc_card_t *card, int enable_nullpin)
672{
673        int r;
674        sc_apdu_t apdu;
675
676        SC_FUNC_CALLED(card->ctx, 1);
677        sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xEE, 0x00, 0x00);
678        apdu.cla |= 0x80;
679        apdu.lc = 0;
680        apdu.datalen = 0;
681        apdu.data = NULL;
682       
683        r = sc_transmit_apdu(card, &apdu);
684        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
685        return sc_check_sw(card, apdu.sw1, apdu.sw2);
686}
687
688
689static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
690{
691        int       r;
692        u8        buf[64];
693        size_t    len;
694        sc_path_t tpath;
695        sc_file_t *tfile = NULL;
696
697        if (!serial) return SC_ERROR_INVALID_ARGUMENTS;
698
699        /* see if we have cached serial number */
700        if (card->serialnr.len) {
701                memcpy(serial, &card->serialnr, sizeof(*serial));
702                return SC_SUCCESS;
703        }
704        sc_format_path("3F002F02", &tpath);
705        r = sc_select_file(card, &tpath, &tfile);
706        if (r < 0) return r;
707
708        len = tfile->size;
709        sc_file_free(tfile);
710        if (len > sizeof(buf) || len < 12) return SC_ERROR_INTERNAL;
711
712        r = sc_read_binary(card, 0, buf, len, 0);
713        if (r < 0) return r;
714        if (buf[0] != 0x5a || buf[1] > len - 2) return SC_ERROR_INTERNAL;
715
716        card->serialnr.len = buf[1];   
717        memcpy(card->serialnr.value, buf+2, buf[1]);
718        memcpy(serial, &card->serialnr, sizeof(*serial));
719
720        return SC_SUCCESS;
721}
722
723
724static int tcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
725{
726        switch (cmd) {
727        case SC_CARDCTL_TCOS_SETPERM:
728                return tcos_setperm(card, !!ptr);
729        case SC_CARDCTL_GET_SERIALNR:
730                return tcos_get_serialnr(card, (sc_serial_number_t *)ptr);
731        }
732        return SC_ERROR_NOT_SUPPORTED;
733}
734
735
736struct sc_card_driver * sc_get_tcos_driver(void)
737{
738        struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
739
740        if (iso_ops == NULL) iso_ops = iso_drv->ops;
741        tcos_ops = *iso_drv->ops;
742
743        tcos_ops.match_card           = tcos_match_card;
744        tcos_ops.init                 = tcos_init;
745        tcos_ops.finish               = tcos_finish;
746        tcos_ops.create_file          = tcos_create_file;
747        tcos_ops.set_security_env     = tcos_set_security_env;
748        tcos_ops.select_file          = tcos_select_file;
749        tcos_ops.list_files           = tcos_list_files;
750        tcos_ops.delete_file          = tcos_delete_file;
751        tcos_ops.set_security_env     = tcos_set_security_env;
752        tcos_ops.compute_signature    = tcos_compute_signature;
753        tcos_ops.decipher             = tcos_decipher;
754        tcos_ops.restore_security_env = tcos_restore_security_env;
755        tcos_ops.card_ctl             = tcos_card_ctl;
756       
757        return &tcos_drv;
758}
Note: See TracBrowser for help on using the browser.