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

Revision 3085, 40.8 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-starcos.c: Support for STARCOS SPK 2.3 cards
3 *
4 * Copyright (C) 2003  Jörn Zukowski <zukowski@trustcenter.de> and
5 *                     Nils Larsch   <larsch@trustcenter.de>, TrustCenter AG
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#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 starcos_atrs[] = {
28        { "3B:B7:94:00:c0:24:31:fe:65:53:50:4b:32:33:90:00:b4", NULL, NULL, SC_CARD_TYPE_STARCOS_GENERIC, 0, NULL },
29        { "3B:B7:94:00:81:31:fe:65:53:50:4b:32:33:90:00:d1", NULL, NULL, SC_CARD_TYPE_STARCOS_GENERIC, 0, NULL },
30        { "3b:b7:18:00:c0:3e:31:fe:65:53:50:4b:32:34:90:00:25", NULL, NULL, SC_CARD_TYPE_STARCOS_GENERIC, 0, NULL },
31        { NULL, NULL, NULL, 0, 0, NULL }
32};
33
34static struct sc_card_operations starcos_ops;
35static struct sc_card_operations *iso_ops = NULL;
36
37static struct sc_card_driver starcos_drv = {
38        "STARCOS SPK 2.3/2.4",
39        "starcos",
40        &starcos_ops,
41        NULL, 0, NULL
42};
43
44static const struct sc_card_error starcos_errors[] =
45{
46        { 0x6600, SC_ERROR_INCORRECT_PARAMETERS, "Error setting the security env"},
47        { 0x66F0, SC_ERROR_INCORRECT_PARAMETERS, "No space left for padding"},
48        { 0x69F0, SC_ERROR_NOT_ALLOWED,          "Command not allowed"},
49        { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS,  "Files exists"},
50        { 0x6A8A, SC_ERROR_FILE_ALREADY_EXISTS,  "Application exists"},
51        { 0x6F01, SC_ERROR_CARD_CMD_FAILED, "public key not complete"},
52        { 0x6F02, SC_ERROR_CARD_CMD_FAILED, "data overflow"},
53        { 0x6F03, SC_ERROR_CARD_CMD_FAILED, "invalid command sequence"},
54        { 0x6F05, SC_ERROR_CARD_CMD_FAILED, "security enviroment invalid"},
55        { 0x6F07, SC_ERROR_FILE_NOT_FOUND, "key part not found"},
56        { 0x6F08, SC_ERROR_CARD_CMD_FAILED, "signature failed"},
57        { 0x6F0A, SC_ERROR_INCORRECT_PARAMETERS, "key format does not match key length"},
58        { 0x6F0B, SC_ERROR_INCORRECT_PARAMETERS, "length of key component inconsistent with algorithm"},
59        { 0x6F81, SC_ERROR_CARD_CMD_FAILED, "system error"}
60};
61
62/* internal structure to save the current security enviroment */
63typedef struct starcos_ex_data_st {
64        int    sec_ops; /* the currently selected security operation,
65                         * i.e. SC_SEC_OPERATION_AUTHENTICATE etc. */
66        unsigned int    fix_digestInfo;
67} starcos_ex_data;
68
69/* the starcos part */
70static int starcos_match_card(sc_card_t *card)
71{
72        int i;
73
74        i = _sc_match_atr(card, starcos_atrs, &card->type);
75        if (i < 0)
76                return 0;
77        return 1;
78}
79
80static int starcos_init(sc_card_t *card)
81{
82        unsigned int flags;
83        starcos_ex_data *ex_data;
84
85        ex_data = (starcos_ex_data *) calloc(1, sizeof(starcos_ex_data));
86        if (ex_data == NULL)
87                return SC_ERROR_OUT_OF_MEMORY;
88
89        card->name = "STARCOS SPK 2.3";
90        card->cla  = 0x00;
91        card->drv_data = (void *)ex_data;
92
93        flags = SC_ALGORITHM_RSA_PAD_PKCS1
94                | SC_ALGORITHM_ONBOARD_KEY_GEN
95                | SC_CARD_FLAG_RNG
96                | SC_ALGORITHM_RSA_PAD_ISO9796
97                | SC_ALGORITHM_RSA_HASH_NONE
98                | SC_ALGORITHM_RSA_HASH_SHA1
99                | SC_ALGORITHM_RSA_HASH_MD5
100                | SC_ALGORITHM_RSA_HASH_RIPEMD160
101                | SC_ALGORITHM_RSA_HASH_MD5_SHA1;
102
103        _sc_card_add_rsa_alg(card, 512, flags, 0x10001);
104        _sc_card_add_rsa_alg(card, 768, flags, 0x10001);
105        _sc_card_add_rsa_alg(card,1024, flags, 0x10001);
106
107        card->caps = SC_CARD_CAP_RNG;
108
109        /* we need read_binary&friends with max 128 bytes per read */
110        if (card->max_send_size > 128)
111                card->max_send_size = 128;
112        if (card->max_recv_size > 128)
113                card->max_recv_size = 128;
114
115        return 0;
116}
117
118static int starcos_finish(sc_card_t *card)
119{
120        if (card->drv_data)
121                free((starcos_ex_data *)card->drv_data);
122        return 0;
123}
124
125static int process_fci(sc_context_t *ctx, sc_file_t *file,
126                       const u8 *buf, size_t buflen)
127{
128        /* NOTE: According to the Starcos S 2.1 manual it's possible
129         *       that a SELECT DF returns as a FCI arbitrary data which
130         *       is stored in a object file (in the corresponding DF)
131         *       with the tag 0x6f.
132         */
133
134        size_t taglen, len = buflen;
135        const u8 *tag = NULL, *p;
136 
137        if (ctx->debug >= 3)
138                sc_debug(ctx, "processing FCI bytes\n");
139
140        if (buflen < 2)
141                return SC_ERROR_INTERNAL;
142        if (buf[0] != 0x6f)
143                return SC_ERROR_INVALID_DATA;
144        len = (size_t)buf[1];
145        if (buflen - 2 < len)
146                return SC_ERROR_INVALID_DATA;
147        p = buf + 2;
148
149        /* defaults */
150        file->type = SC_FILE_TYPE_WORKING_EF;
151        file->ef_structure = SC_FILE_EF_UNKNOWN;
152        file->shareable = 0;
153        file->record_length = 0;
154        file->size = 0;
155 
156        tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
157        if (tag != NULL && taglen >= 2) {
158                int bytes = (tag[0] << 8) + tag[1];
159                if (ctx->debug >= 3)
160                        sc_debug(ctx, "  bytes in file: %d\n", bytes);
161                file->size = bytes;
162        }
163
164        tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
165        if (tag != NULL) {
166                const char *type = "unknown";
167                const char *structure = "unknown";
168
169                if (taglen == 1 && tag[0] == 0x01) {
170                        /* transparent EF */
171                        type = "working EF";
172                        structure = "transparent";
173                        file->type = SC_FILE_TYPE_WORKING_EF;
174                        file->ef_structure = SC_FILE_EF_TRANSPARENT;
175                } else if (taglen == 1 && tag[0] == 0x11) {
176                        /* object EF */
177                        type = "working EF";
178                        structure = "object";
179                        file->type = SC_FILE_TYPE_WORKING_EF;
180                        file->ef_structure = SC_FILE_EF_TRANSPARENT; /* TODO */
181                } else if (taglen == 3 && tag[1] == 0x21) {
182                        type = "working EF";
183                        file->record_length = tag[2];
184                        file->type = SC_FILE_TYPE_WORKING_EF;
185                        /* linear fixed, cyclic or compute */
186                        switch ( tag[0] )
187                        {
188                                case 0x02:
189                                        structure = "linear fixed";
190                                        file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
191                                        break;
192                                case 0x07:
193                                        structure = "cyclic";
194                                        file->ef_structure = SC_FILE_EF_CYCLIC;
195                                        break;
196                                case 0x17:
197                                        structure = "compute";
198                                        file->ef_structure = SC_FILE_EF_UNKNOWN;
199                                        break;
200                                default:
201                                        structure = "unknown";
202                                        file->ef_structure = SC_FILE_EF_UNKNOWN;
203                                        file->record_length = 0;
204                                        break;
205                        }
206                }
207
208                if (ctx->debug >= 3) {
209                        sc_debug(ctx, "  type: %s\n", type);
210                        sc_debug(ctx, "  EF structure: %s\n", structure);
211                }
212        }
213        file->magic = SC_FILE_MAGIC;
214
215        return SC_SUCCESS;
216}
217
218static int starcos_select_aid(sc_card_t *card,
219                              u8 aid[16], size_t len,
220                              sc_file_t **file_out)
221{
222        sc_apdu_t apdu;
223        int r;
224        size_t i = 0;
225
226        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
227        apdu.lc = len;
228        apdu.data = (u8*)aid;
229        apdu.datalen = len;
230        apdu.resplen = 0;
231        apdu.le = 0;
232        r = sc_transmit_apdu(card, &apdu);
233        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
234
235        /* check return value */
236        if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 )
237                SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
238 
239        /* update cache */
240        card->cache.current_path.type = SC_PATH_TYPE_DF_NAME;
241        card->cache.current_path.len = len;
242        memcpy(card->cache.current_path.value, aid, len);
243
244        if (file_out) {
245                sc_file_t *file = sc_file_new();
246                if (!file)
247                        SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
248                file->type = SC_FILE_TYPE_DF;
249                file->ef_structure = SC_FILE_EF_UNKNOWN;
250                file->path.len = 0;
251                file->size = 0;
252                /* AID */
253                for (i = 0; i < len; i++) 
254                        file->name[i] = aid[i];
255                file->namelen = len;
256                file->id = 0x0000;
257                file->magic = SC_FILE_MAGIC;
258                *file_out = file;
259        }
260        SC_FUNC_RETURN(card->ctx, 2, SC_SUCCESS);
261}
262
263static int starcos_select_fid(sc_card_t *card,
264                              unsigned int id_hi, unsigned int id_lo,
265                              sc_file_t **file_out)
266{
267        sc_apdu_t apdu;
268        u8 data[] = {id_hi & 0xff, id_lo & 0xff};
269        u8 resp[SC_MAX_APDU_BUFFER_SIZE];
270        int bIsDF = 0, r;
271
272        /* request FCI to distinguish between EFs and DFs */
273        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00);
274        apdu.p2   = 0x00;
275        apdu.resp = (u8*)resp;
276        apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
277        apdu.le = 256;
278        apdu.lc = 2;
279        apdu.data = (u8*)data;
280        apdu.datalen = 2;
281
282        r = sc_transmit_apdu(card, &apdu);
283        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
284
285        if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) {
286                /* no FCI => we have a DF (see comment in process_fci()) */
287                bIsDF = 1;
288                apdu.p2 = 0x0C;
289                apdu.cse = SC_APDU_CASE_3_SHORT;
290                apdu.resplen = 0;
291                apdu.le = 0;
292                r = sc_transmit_apdu(card, &apdu);
293                SC_TEST_RET(card->ctx, r, "APDU re-transmit failed");
294        } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)) {
295                /* SELECT returned some data (possible FCI) =>
296                 * try a READ BINARY to see if a EF is selected */
297                sc_apdu_t apdu2;
298                u8 resp2[2];
299                sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0);
300                apdu2.resp = (u8*)resp2;
301                apdu2.resplen = 2;
302                apdu2.le = 1;
303                apdu2.lc = 0;
304                r = sc_transmit_apdu(card, &apdu2);
305                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
306                if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86)
307                        /* no current EF is selected => we have a DF */
308                        bIsDF = 1;
309        }
310
311        if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00))
312                SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
313
314        /* update cache */
315        if (bIsDF) {
316                card->cache.current_path.type = SC_PATH_TYPE_PATH;
317                card->cache.current_path.value[0] = 0x3f;
318                card->cache.current_path.value[1] = 0x00;
319                if (id_hi == 0x3f && id_lo == 0x00)
320                        card->cache.current_path.len = 2;
321                else {
322                        card->cache.current_path.len = 4;
323                        card->cache.current_path.value[2] = id_hi;
324                        card->cache.current_path.value[3] = id_lo;
325                }
326        }
327
328        if (file_out) {
329                sc_file_t *file = sc_file_new();
330                if (!file)
331                        SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
332                file->id   = (id_hi << 8) + id_lo;
333                file->path = card->cache.current_path;
334
335                if (bIsDF) {
336                        /* we have a DF */
337                        file->type = SC_FILE_TYPE_DF;
338                        file->ef_structure = SC_FILE_EF_UNKNOWN;
339                        file->size = 0;
340                        file->namelen = 0;
341                        file->magic = SC_FILE_MAGIC;
342                        *file_out = file;
343                } else {
344                        /* ok, assume we have a EF */
345                        r = process_fci(card->ctx, file, apdu.resp,
346                                        apdu.resplen);
347                        if (r != SC_SUCCESS) {
348                                sc_file_free(file);
349                                return r;
350                        }
351
352                        *file_out = file;
353                }
354        }
355
356        SC_FUNC_RETURN(card->ctx, 2, SC_SUCCESS);
357}
358
359static int starcos_select_file(sc_card_t *card,
360                               const sc_path_t *in_path,
361                               sc_file_t **file_out)
362{
363        u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
364        int    r;
365        size_t i, pathlen;
366
367        SC_FUNC_CALLED(card->ctx, 1);
368
369        if (card->ctx->debug >= 4) {
370                char pbuf[SC_MAX_PATH_STRING_SIZE];
371
372                r = sc_path_print(pbuf, sizeof(pbuf), &card->cache.current_path);
373                if (r != SC_SUCCESS)
374                        pbuf[0] = '\0';
375
376                sc_debug(card->ctx, "current path (%s, %s): %s (len: %u)\n",
377                        (card->cache.current_path.type==SC_PATH_TYPE_DF_NAME?"aid":"path"),
378                        (card->cache_valid?"valid":"invalid"), pbuf,
379                        card->cache.current_path.len);
380        }
381 
382        memcpy(path, in_path->value, in_path->len);
383        pathlen = in_path->len;
384
385        if (in_path->type == SC_PATH_TYPE_FILE_ID)
386        {       /* SELECT EF/DF with ID */
387                /* Select with 2byte File-ID */
388                if (pathlen != 2)
389                        SC_FUNC_RETURN(card->ctx,2,SC_ERROR_INVALID_ARGUMENTS);
390                return starcos_select_fid(card, path[0], path[1], file_out);
391        }
392        else if (in_path->type == SC_PATH_TYPE_DF_NAME)
393        {       /* SELECT DF with AID */
394                /* Select with 1-16byte Application-ID */
395                if (card->cache_valid
396                    && card->cache.current_path.type == SC_PATH_TYPE_DF_NAME
397                    && card->cache.current_path.len == pathlen
398                    && memcmp(card->cache.current_path.value, pathbuf, pathlen) == 0 )
399                {
400                        if (card->ctx->debug >= 4)
401                                sc_debug(card->ctx, "cache hit\n");
402                        SC_FUNC_RETURN(card->ctx, 2, SC_SUCCESS);
403                }
404                else
405                        return starcos_select_aid(card, pathbuf, pathlen, file_out);
406        }
407        else if (in_path->type == SC_PATH_TYPE_PATH)
408        {
409                u8 n_pathbuf[SC_MAX_PATH_SIZE];
410                int bMatch = -1;
411
412                /* Select with path (sequence of File-IDs) */
413                /* Starcos (S 2.1 and SPK 2.3) only supports one
414                 * level of subdirectories, therefore a path is
415                 * at most 3 FID long (the last one being the FID
416                 * of a EF) => pathlen must be even and less than 6
417                 */
418                if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
419                        SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
420                /* if pathlen == 6 then the first FID must be MF (== 3F00) */
421                if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
422                        SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
423
424                /* unify path (the first FID should be MF) */
425                if (path[0] != 0x3f || path[1] != 0x00)
426                {
427                        n_pathbuf[0] = 0x3f;
428                        n_pathbuf[1] = 0x00;
429                        for (i=0; i< pathlen; i++)
430                                n_pathbuf[i+2] = pathbuf[i];
431                        path = n_pathbuf;
432                        pathlen += 2;
433                }
434       
435                /* check current working directory */
436                if (card->cache_valid
437                    && card->cache.current_path.type == SC_PATH_TYPE_PATH
438                    && card->cache.current_path.len >= 2
439                    && card->cache.current_path.len <= pathlen )
440                {
441                        bMatch = 0;
442                        for (i=0; i < card->cache.current_path.len; i+=2)
443                                if (card->cache.current_path.value[i] == path[i]
444                                    && card->cache.current_path.value[i+1] == path[i+1] )
445                                        bMatch += 2;
446                }
447
448                if ( card->cache_valid && bMatch >= 0 )
449                {
450                        if ( pathlen - bMatch == 2 )
451                                /* we are in the rigth directory */
452                                return starcos_select_fid(card, path[bMatch], path[bMatch+1], file_out);
453                        else if ( pathlen - bMatch > 2 )
454                        {
455                                /* two more steps to go */
456                                sc_path_t new_path;
457       
458                                /* first step: change directory */
459                                r = starcos_select_fid(card, path[bMatch], path[bMatch+1], NULL);
460                                SC_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
461               
462                                new_path.type = SC_PATH_TYPE_PATH;
463                                new_path.len  = pathlen - bMatch-2;
464                                memcpy(new_path.value, &(path[bMatch+2]), new_path.len);
465                                /* final step: select file */
466                                return starcos_select_file(card, &new_path, file_out);
467                        }
468                        else /* if (bMatch - pathlen == 0) */
469                        {
470                                /* done: we are already in the
471                                 * requested directory */
472                                if ( card->ctx->debug >= 4 )
473                                        sc_debug(card->ctx, "cache hit\n");
474                                /* copy file info (if necessary) */
475                                if (file_out) {
476                                        sc_file_t *file = sc_file_new();
477                                        if (!file)
478                                                SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
479                                        file->id = (path[pathlen-2] << 8) +
480                                                   path[pathlen-1];
481                                        file->path = card->cache.current_path;
482                                        file->type = SC_FILE_TYPE_DF;
483                                        file->ef_structure = SC_FILE_EF_UNKNOWN;
484                                        file->size = 0;
485                                        file->namelen = 0;
486                                        file->magic = SC_FILE_MAGIC;
487                                        *file_out = file;
488                                }
489                                /* nothing left to do */
490                                return SC_SUCCESS;
491                        }
492                }
493                else
494                {
495                        /* no usable cache */
496                        for ( i=0; i<pathlen-2; i+=2 )
497                        {
498                                r = starcos_select_fid(card, path[i], path[i+1], NULL);
499                                SC_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
500                        }
501                        return starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out);
502                }
503        }
504        else
505                SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
506}
507
508#define STARCOS_AC_ALWAYS       0x9f
509#define STARCOS_AC_NEVER        0x5f
510#define STARCOS_PINID2STATE(a)  ((((a) & 0x0f) == 0x01) ? ((a) & 0x0f) : (0x0f - ((0x0f & (a)) >> 1)))
511
512static u8 process_acl_entry(sc_file_t *in, unsigned int method, unsigned int in_def)
513{
514        u8 def = (u8)in_def;
515        const sc_acl_entry_t *entry = sc_file_get_acl_entry(in, method);
516        if (!entry)
517                return def;
518        else if (entry->method & SC_AC_CHV) {
519                unsigned int key_ref = entry->key_ref;
520                if (key_ref == SC_AC_KEY_REF_NONE)
521                        return def;
522                else if ((key_ref & 0x0f) == 1)
523                        /* SOPIN */
524                        return (key_ref & 0x80 ? 0x10 : 0x00) | 0x01;
525                else
526                        return (key_ref & 0x80 ? 0x10 : 0x00) | STARCOS_PINID2STATE(key_ref);
527        } else if (entry->method & SC_AC_NEVER)
528                return STARCOS_AC_NEVER;
529        else
530                return def;
531}
532
533/** starcos_process_acl
534 * \param card pointer to the sc_card object
535 * \param file pointer to the sc_file object
536 * \param data pointer to a sc_starcos_create_data structure
537 * \return SC_SUCCESS if no error occured otherwise error code
538 *
539 * This function tries to create a somewhat useable Starcos spk 2.3 acl
540 * from the OpenSC internal acl (storing the result in the supplied
541 * sc_starcos_create_data structure).
542 */
543static int starcos_process_acl(sc_card_t *card, sc_file_t *file,
544        sc_starcos_create_data *data)
545{
546        u8     tmp, *p;
547        static const u8 def_key[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
548
549        if (file->type == SC_FILE_TYPE_DF && file->id == 0x3f00) {
550                p    = data->data.mf.header;
551                memcpy(p, def_key, 8);
552                p   += 8;
553                *p++ = (file->size >> 8) & 0xff;
554                *p++ = file->size & 0xff;
555                /* guess isf size (mf_size / 4) */
556                *p++ = (file->size >> 10) & 0xff;
557                *p++ = (file->size >> 2)  & 0xff;
558                /* ac create ef  */
559                *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
560                /* ac create key */
561                *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
562                /* ac create df  */
563                *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
564                /* use the same ac for register df and create df */
565                *p++ = data->data.mf.header[14];
566                /* if sm is required use combined mode */
567                if (file->acl[SC_AC_OP_CREATE] && (sc_file_get_acl_entry(file, SC_AC_OP_CREATE))->method & SC_AC_PRO)
568                        tmp = 0x03;     /* combinde mode */
569                else
570                        tmp = 0x00;     /* no sm */
571                *p++ = tmp;     /* use the same sm mode for all ops */
572                *p++ = tmp;
573                *p++ = tmp;
574                data->type = SC_STARCOS_MF_DATA;
575
576                return SC_SUCCESS;
577        } else if (file->type == SC_FILE_TYPE_DF){
578                p    = data->data.df.header;
579                *p++ = (file->id >> 8) & 0xff;
580                *p++ = file->id & 0xff;
581                if (file->namelen) {
582                        /* copy aid */
583                        *p++ = file->namelen & 0xff;
584                        memset(p, 0, 16);
585                        memcpy(p, file->name, (u8)file->namelen);
586                        p   += 16;
587                } else {
588                        /* (mis)use the fid as aid */
589                        *p++ = 2;
590                        memset(p, 0, 16);
591                        *p++ = (file->id >> 8) & 0xff;
592                        *p++ = file->id & 0xff;
593                        p   += 14;
594                }
595                /* guess isf size */
596                *p++ = (file->size >> 10) & 0xff;       /* ISF space */
597                *p++ = (file->size >> 2)  & 0xff;       /* ISF space */
598                /* ac create ef  */
599                *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
600                /* ac create key */
601                *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
602                /* set sm byte (same for keys and ef) */
603                if (file->acl[SC_AC_OP_CREATE] &&
604                    (sc_file_get_acl_entry(file, SC_AC_OP_CREATE)->method &
605                     SC_AC_PRO))
606                        tmp = 0x03;
607                else
608                        tmp = 0x00;
609                *p++ = tmp;     /* SM CR  */
610                *p++ = tmp;     /* SM ISF */
611
612                data->data.df.size[0] = (file->size >> 8) & 0xff;
613                data->data.df.size[1] = file->size & 0xff;
614                data->type = SC_STARCOS_DF_DATA;
615
616                return SC_SUCCESS;
617        } else if (file->type == SC_FILE_TYPE_WORKING_EF) {
618                p    = data->data.ef.header;
619                *p++ = (file->id >> 8) & 0xff;
620                *p++ = file->id & 0xff;
621                /* ac read  */
622                *p++ = process_acl_entry(file, SC_AC_OP_READ,STARCOS_AC_ALWAYS);
623                /* ac write */
624                *p++ = process_acl_entry(file, SC_AC_OP_WRITE,STARCOS_AC_ALWAYS);
625                /* ac erase */
626                *p++ = process_acl_entry(file, SC_AC_OP_ERASE,STARCOS_AC_ALWAYS);
627                *p++ = STARCOS_AC_ALWAYS;       /* AC LOCK     */
628                *p++ = STARCOS_AC_ALWAYS;       /* AC UNLOCK   */
629                *p++ = STARCOS_AC_ALWAYS;       /* AC INCREASE */
630                *p++ = STARCOS_AC_ALWAYS;       /* AC DECREASE */
631                *p++ = 0x00;                    /* rfu         */
632                *p++ = 0x00;                    /* rfu         */
633                /* use sm (in combined mode) if wanted */
634                if ((file->acl[SC_AC_OP_READ]   && (sc_file_get_acl_entry(file, SC_AC_OP_READ)->method & SC_AC_PRO)) ||
635                    (file->acl[SC_AC_OP_UPDATE] && (sc_file_get_acl_entry(file, SC_AC_OP_UPDATE)->method & SC_AC_PRO)) ||
636                    (file->acl[SC_AC_OP_WRITE]  && (sc_file_get_acl_entry(file, SC_AC_OP_WRITE)->method & SC_AC_PRO)) )
637                        tmp = 0x03;
638                else
639                        tmp = 0x00;
640                *p++ = tmp;                     /* SM byte     */
641                *p++ = 0x00;                    /* use the least significant 5 bits
642                                                 * of the FID as SID */
643                switch (file->ef_structure)
644                {
645                case SC_FILE_EF_TRANSPARENT:
646                        *p++ = 0x81;
647                        *p++ = (file->size >> 8) & 0xff;
648                        *p++ = file->size & 0xff;
649                        break;
650                case SC_FILE_EF_LINEAR_FIXED:
651                        *p++ = 0x82;
652                        *p++ = file->record_count  & 0xff;
653                        *p++ = file->record_length & 0xff;
654                        break;
655                case SC_FILE_EF_CYCLIC:
656                        *p++ = 0x84;
657                        *p++ = file->record_count  & 0xff;
658                        *p++ = file->record_length & 0xff;
659                        break;
660                default:
661                        return SC_ERROR_INVALID_ARGUMENTS;
662                }
663                data->type = SC_STARCOS_EF_DATA;
664
665                return SC_SUCCESS;
666        } else
667                return SC_ERROR_INVALID_ARGUMENTS;
668}
669
670/** starcos_create_mf
671 * internal function to create the MF
672 * \param card pointer to the sc_card structure
673 * \param data pointer to a sc_starcos_create_data object
674 * \return SC_SUCCESS or error code
675 *
676 * This function creates the MF based on the information stored
677 * in the sc_starcos_create_data.mf structure. Note: CREATE END must be
678 * called separately to activate the ACs.
679 */
680static int starcos_create_mf(sc_card_t *card, sc_starcos_create_data *data)
681{
682        int    r;
683        sc_apdu_t       apdu;
684        sc_context_t   *ctx = card->ctx;
685
686        if (ctx->debug >= 3)
687                sc_debug(ctx, "creating MF \n");
688        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
689        apdu.cla |= 0x80;
690        apdu.lc   = 19;
691        apdu.datalen = 19;
692        apdu.data = (u8 *) data->data.mf.header;
693
694        r = sc_transmit_apdu(card, &apdu);
695        SC_TEST_RET(ctx, r, "APDU transmit failed");
696        return sc_check_sw(card, apdu.sw1, apdu.sw2);   
697}
698
699/** starcos_create_df
700 * internal function to create a DF
701 * \param card pointer to the sc_card structure
702 * \param data pointer to a sc_starcos_create_data object
703 * \return SC_SUCCESS or error code
704 *
705 * This functions registers and creates a DF based in the information
706 * stored in a sc_starcos_create_data.df data structure. Note: CREATE END must
707 * be called separately to activate the ACs.
708 */
709static int starcos_create_df(sc_card_t *card, sc_starcos_create_data *data)
710{
711        int    r;
712        size_t len;
713        sc_apdu_t       apdu;
714        sc_context_t   *ctx = card->ctx;
715
716        if (ctx->debug >= 3)
717                sc_debug(ctx, "creating DF\n");
718        /* first step: REGISTER DF */
719        if (ctx->debug >= 3)
720                sc_debug(ctx, "calling REGISTER DF\n");
721
722        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x52,
723                       data->data.df.size[0], data->data.df.size[1]);
724        len  = 3 + data->data.df.header[2];
725        apdu.cla |= 0x80;
726        apdu.lc   = len;
727        apdu.datalen = len;
728        apdu.data = data->data.df.header;
729
730        r = sc_transmit_apdu(card, &apdu);
731        SC_TEST_RET(ctx, r, "APDU transmit failed");
732        /* second step: CREATE DF */
733        if (ctx->debug >= 3)
734                sc_debug(ctx, "calling CREATE DF\n");
735
736        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x01, 0x00);
737        apdu.cla |= 0x80;
738        apdu.lc   = 25;
739        apdu.datalen = 25;
740        apdu.data = data->data.df.header;
741
742        r = sc_transmit_apdu(card, &apdu);
743        SC_TEST_RET(ctx, r, "APDU transmit failed");
744        return sc_check_sw(card, apdu.sw1, apdu.sw2);
745}
746
747/** starcos_create_ef
748 * internal function to create a EF
749 * \param card pointer to the sc_card structure
750 * \param data pointer to a sc_starcos_create_data object
751 * \return SC_SUCCESS or error code
752 *
753 * This function creates a EF based on the information stored in
754 * the sc_starcos_create_data.ef data structure.
755 */
756static int starcos_create_ef(sc_card_t *card, sc_starcos_create_data *data)
757{       
758        int    r;
759        sc_apdu_t       apdu;
760        sc_context_t   *ctx = card->ctx;
761
762        if (ctx->debug >= 3)
763                sc_debug(ctx, "creating EF\n");
764
765        sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT,0xE0,0x03,0x00);
766        apdu.cla |= 0x80;
767        apdu.lc   = 16;
768        apdu.datalen = 16;
769        apdu.data = (u8 *) data->data.ef.header;
770
771        r = sc_transmit_apdu(card, &apdu);
772        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
773        return sc_check_sw(card, apdu.sw1, apdu.sw2);
774}
775
776/** starcos_create_end
777 * internal function to activate the ACs
778 * \param card pointer to the sc_card structure
779 * \param file pointer to a sc_file object
780 * \return SC_SUCCESS or error code
781 *
782 * This function finishs the creation of a DF (or MF) and activates
783 * the ACs.
784 */
785static int starcos_create_end(sc_card_t *card, sc_file_t *file)
786{
787        int r;
788        u8  fid[2];
789        sc_apdu_t       apdu;
790
791        if (file->type != SC_FILE_TYPE_DF)
792                return SC_ERROR_INVALID_ARGUMENTS;
793
794        fid[0] = (file->id >> 8) & 0xff;
795        fid[1] = file->id & 0xff;
796        sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT, 0xE0, 0x02, 0x00);
797        apdu.cla |= 0x80;
798        apdu.lc   = 2;
799        apdu.datalen = 2;
800        apdu.data = fid;
801        r = sc_transmit_apdu(card, &apdu);
802        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
803        return sc_check_sw(card, apdu.sw1, apdu.sw2);
804}
805
806/** starcos_create_file
807 * \param card pointer to the sc_card structure
808 * \param file pointer to a sc_file object
809 * \return SC_SUCCESS or error code
810 *
811 * This function creates MF, DF or EF based on the supplied
812 * information in the sc_file structure (using starcos_process_acl).
813 */
814static int starcos_create_file(sc_card_t *card, sc_file_t *file)
815{       
816        int    r;
817        sc_starcos_create_data data;
818
819        SC_FUNC_CALLED(card->ctx, 1);
820
821        if (file->type == SC_FILE_TYPE_DF) {
822                if (file->id == 0x3f00) {
823                        /* CREATE MF */
824                        r = starcos_process_acl(card, file, &data);
825                        if (r != SC_SUCCESS)
826                                return r;
827                        return starcos_create_mf(card, &data);
828                } else {
829                        /* CREATE DF */
830                        r = starcos_process_acl(card, file, &data);
831                        if (r != SC_SUCCESS)
832                                return r;
833                        return starcos_create_df(card, &data);
834                }
835        } else if (file->type == SC_FILE_TYPE_WORKING_EF) {
836                /* CREATE EF */
837                r = starcos_process_acl(card, file, &data);
838                if (r != SC_SUCCESS)
839                        return r;
840                return starcos_create_ef(card, &data);
841        } else
842                return SC_ERROR_INVALID_ARGUMENTS;
843}
844
845/** starcos_erase_card
846 * internal function to restore the delivery state
847 * \param card pointer to the sc_card object
848 * \return SC_SUCCESS or error code
849 *
850 * This function deletes the MF (for 'test cards' only).
851 */
852static int starcos_erase_card(sc_card_t *card)
853{       /* restore the delivery state */
854        int r;
855        u8  sbuf[2];
856        sc_apdu_t apdu;
857
858        sbuf[0] = 0x3f;
859        sbuf[1] = 0x00;
860        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
861        apdu.cla |= 0x80;
862        apdu.lc   = 2;
863        apdu.datalen = 2;
864        apdu.data = sbuf;
865       
866        r = sc_transmit_apdu(card, &apdu);
867        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
868        /* invalidate cache */
869        card->cache_valid = 0;
870        if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85)
871                /* no MF to delete, ignore error */
872                return SC_SUCCESS;
873        else return sc_check_sw(card, apdu.sw1, apdu.sw2);
874}
875
876#define STARCOS_WKEY_CSIZE      124
877
878/** starcos_write_key
879 * set key in isf
880 * \param card pointer to the sc_card object
881 * \param data pointer to a sc_starcos_wkey_data structure
882 * \return SC_SUCCESS or error code
883 *
884 * This function installs a key header in the ISF (based on the
885 * information supplied in the sc_starcos_wkey_data structure)
886 * and set a supplied key (depending on the mode).
887 */
888static int starcos_write_key(sc_card_t *card, sc_starcos_wkey_data *data)
889{
890        int       r;
891        u8        sbuf[SC_MAX_APDU_BUFFER_SIZE];
892        const u8 *p;
893        size_t    len = sizeof(sbuf), tlen, offset = 0;
894        sc_apdu_t       apdu;
895
896        if (data->mode == 0) {  /* mode == 0 => install */
897                /* install key header */
898                sbuf[0] = 0xc1; /* key header tag    */
899                sbuf[1] = 0x0c; /* key header length */
900                memcpy(sbuf + 2, data->key_header, 12);
901                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xf4,
902                               data->mode, 0x00);
903                apdu.cla |= 0x80;
904                apdu.lc   = 14;
905                apdu.datalen = 14;
906                apdu.data = sbuf;
907
908                r = sc_transmit_apdu(card, &apdu);
909                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
910                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
911                        return sc_check_sw(card, apdu.sw1, apdu.sw2);
912                if (data->key == NULL)
913                        return SC_SUCCESS;
914        }
915
916        if (data->key == NULL)
917                return SC_ERROR_INVALID_ARGUMENTS;
918
919        p    = data->key;
920        tlen = data->key_len;
921        while (tlen != 0) {
922                /* transmit the key in chunks of STARCOS_WKEY_CSIZE bytes */
923                u8 clen = tlen < STARCOS_WKEY_CSIZE ? tlen : STARCOS_WKEY_CSIZE;
924                sbuf[0] = 0xc2;
925                sbuf[1] = 3 + clen;
926                sbuf[2] = data->kid;
927                sbuf[3] = (offset >> 8) & 0xff;
928                sbuf[4] = offset & 0xff;
929                memcpy(sbuf+5, p, clen);
930                len     = 5 + clen;
931                sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xf4,
932                               data->mode, 0x00);
933                apdu.cla    |= 0x80;
934                apdu.lc      = len;
935                apdu.datalen = len;
936                apdu.data    = sbuf;
937
938                r = sc_transmit_apdu(card, &apdu);
939                SC_TEST_RET(card->ctx, r, "APDU transmit failed");
940                if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
941                        return sc_check_sw(card, apdu.sw1, apdu.sw2);
942                offset += clen;
943                p      += clen;
944            Â