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

Revision 3291, 32.3 KB (checked in by ludovic.rousseau, 13 months ago)

setcos_match_card(): replace sc_error() by sc_debug() since some cards
are not SetCOS bug respond to the APDU: 00 CA DF 30 05

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * card-setcos.c: Support for PKI cards by Setec
3 *
4 * Copyright (C) 2001, 2002  Juha YrjölÀ <juha.yrjola@iki.fi>
5 * Copyright (C) 2005  Antti Tapaninen <aet@cc.hut.fi>
6 * Copyright (C) 2005  Zetes
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 "cardctl.h"
25#include <stdlib.h>
26#include <string.h>
27
28#include <opensc/asn1.h>
29
30static struct sc_atr_table setcos_atrs[] = {
31        /* some Nokia branded SC */
32        { "3B:1F:11:00:67:80:42:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_GENERIC, 0, NULL },
33        /* RSA SecurID 3100 */
34        { "3B:9F:94:40:1E:00:67:16:43:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_PKI, 0, NULL },
35
36        /* FINEID 1016 (SetCOS 4.3.1B3/PKCS#15, VRK) */
37        { "3b:9f:94:40:1e:00:67:00:43:46:49:53:45:10:52:66:ff:81:90:00", "ff:ff:ff:ff:ff:ff:ff:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID, SC_CARD_FLAG_RNG, NULL },
38        /* FINEID 2032 (EIDApplet/7816-15, VRK test) */
39        { "3b:6b:00:ff:80:62:00:a2:56:46:69:6e:45:49:44", "ff:ff:00:ff:ff:ff:00:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
40        /* FINEID 2132 (EIDApplet/7816-15, 3rdparty test) */
41        { "3b:64:00:ff:80:62:00:a2", "ff:ff:00:ff:ff:ff:00:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
42        /* FINEID 2064 (EIDApplet/7816-15, VRK) */
43        { "3b:7b:00:00:00:80:62:00:51:56:46:69:6e:45:49:44", "ff:ff:00:ff:ff:ff:ff:f0:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
44        /* FINEID 2164 (EIDApplet/7816-15, 3rdparty) */
45        { "3b:64:00:00:80:62:00:51", "ff:ff:ff:ff:ff:ff:f0:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
46        /* FINEID 2264 (EIDApplet/7816-15, OPK/EMV/AVANT) */
47        { "3b:6e:00:00:00:62:00:00:57:41:56:41:4e:54:10:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
48        { "3b:7b:94:00:00:80:62:11:51:56:46:69:6e:45:49:44", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
49        /* Swedish NIDEL card */
50        { "3b:9f:94:80:1f:c3:00:68:10:44:05:01:46:49:53:45:31:c8:07:90:00:18", NULL, NULL, SC_CARD_TYPE_SETCOS_NIDEL, 0, NULL },
51        /* Setcos 4.4.1 */
52        { "3b:9f:94:80:1f:c3:00:68:11:44:05:01:46:49:53:45:31:c8:00:00:00:00", "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00", NULL, SC_CARD_TYPE_SETCOS_44, 0, NULL },
53        { NULL, NULL, NULL, 0, 0, NULL }
54};
55
56#define SETCOS_IS_EID_APPLET(card) ((card)->type == SC_CARD_TYPE_SETCOS_EID_V2_0 || (card)->type == SC_CARD_TYPE_SETCOS_EID_V2_1)
57
58/* Setcos 4.4 Life Cycle Status Integer  */
59#define SETEC_LCSI_CREATE      0x01
60#define SETEC_LCSI_INIT        0x03
61#define SETEC_LCSI_ACTIVATED   0x07
62#define SETEC_LCSI_DEACTIVATE  0x06
63#define SETEC_LCSI_TEMINATE    0x0F /* MF only  */
64
65static struct sc_card_operations setcos_ops;
66static struct sc_card_driver setcos_drv = {
67        "Setec cards",
68        "setcos",
69        &setcos_ops,
70        NULL, 0, NULL
71};
72
73static int setcos_finish(sc_card_t *card)
74{
75        return 0;
76}
77
78static int match_hist_bytes(sc_card_t *card, const char *str, size_t len)
79{
80        const char *src = (const char *) card->slot->atr_info.hist_bytes;
81        size_t srclen = card->slot->atr_info.hist_bytes_len;
82        size_t offset = 0;
83
84        if (len == 0)
85                len = strlen(str);
86        if (srclen < len)
87                return 0;
88        while (srclen - offset > len) {
89                if (memcmp(src + offset, str, len) == 0) {
90                        return 1;
91                }
92                offset++;
93        }
94        return 0;
95}
96
97static int setcos_match_card(sc_card_t *card)
98{
99        sc_apdu_t apdu;
100        u8 buf[6];
101        int i;
102
103        i = _sc_match_atr(card, setcos_atrs, &card->type);
104        if (i < 0) {
105                /* Unknown card, but has the FinEID application for sure */
106                if (match_hist_bytes(card, "FinEID", 0)) {
107                        card->type = SC_CARD_TYPE_SETCOS_FINEID_V2;
108                        return 1;
109                }
110                if (match_hist_bytes(card, "FISE", 0)) {
111                        card->type = SC_CARD_TYPE_SETCOS_GENERIC;
112                        return 1;
113                }
114                /* Check if it's a EID2.x applet by reading the version info */
115                sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0xDF, 0x30);
116                apdu.cla = 0x00;
117                apdu.resp = buf;
118                apdu.resplen = 5;
119                apdu.le = 5;
120                i = sc_transmit_apdu(card, &apdu);
121                if (i == 0 && apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && apdu.resplen == 5) {
122                        if (memcmp(buf, "v2.0", 4) == 0)
123                                card->type = SC_CARD_TYPE_SETCOS_EID_V2_0;
124                        else if (memcmp(buf, "v2.1", 4) == 0)
125                                card->type = SC_CARD_TYPE_SETCOS_EID_V2_1;
126                        else {
127                                buf[sizeof(buf) - 1] = '\0';
128                                sc_debug(card->ctx, "SetCOS EID applet %s is not supported", (char *) buf);
129                                return 0;
130                        }
131                        return 1;
132                }
133
134                return 0;
135        }
136        card->flags = setcos_atrs[i].flags;
137        return 1;
138}
139
140static int select_pkcs15_app(sc_card_t * card)
141{
142        sc_path_t app;
143        int r;
144
145        /* Regular PKCS#15 AID */
146        sc_format_path("A000000063504B43532D3135", &app);
147        app.type = SC_PATH_TYPE_DF_NAME;
148        sc_ctx_suppress_errors_on(card->ctx);
149        r = sc_select_file(card, &app, NULL);
150        sc_ctx_suppress_errors_off(card->ctx);
151        return r;
152}
153
154static int setcos_init(sc_card_t *card)
155{
156        card->name = "SetCOS";
157
158        /* Handle unknown or forced cards */
159        if (card->type < 0) {
160                card->type = SC_CARD_TYPE_SETCOS_GENERIC;
161#if 0
162                /* Hmm. For now, assume it's a bank card with FinEID application */
163                if (match_hist_bytes(card, "AVANT", 0))
164                        card->type = SC_CARD_TYPE_SETCOS_FINEID_V2;
165#endif
166        }
167
168        switch (card->type) {
169        case SC_CARD_TYPE_SETCOS_FINEID:
170        case SC_CARD_TYPE_SETCOS_FINEID_V2:
171        case SC_CARD_TYPE_SETCOS_NIDEL:
172                card->cla = 0x00;
173                select_pkcs15_app(card);
174                if (card->flags & SC_CARD_FLAG_RNG)
175                        card->caps |= SC_CARD_CAP_RNG;
176                break;
177        case SC_CARD_TYPE_SETCOS_44:
178        case SC_CARD_TYPE_SETCOS_EID_V2_0:
179        case SC_CARD_TYPE_SETCOS_EID_V2_1:
180                card->cla = 0x00;
181                card->caps |= SC_CARD_CAP_USE_FCI_AC;
182                card->caps |= SC_CARD_CAP_RNG;
183                card->caps |= SC_CARD_FLAG_ONBOARD_KEY_GEN;
184                break;
185        default:
186                /* XXX: Get SetCOS version */
187                card->cla = 0x80;       /* SetCOS 4.3.x */
188                /* State that we have an RNG */
189                card->caps |= SC_CARD_CAP_RNG;
190                break;
191        }
192
193        switch (card->type) {
194        case SC_CARD_TYPE_SETCOS_PKI:
195        case SC_CARD_TYPE_SETCOS_FINEID:
196        case SC_CARD_TYPE_SETCOS_FINEID_V2:
197                {
198                        unsigned long flags;
199
200                        flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
201                        flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
202
203                        _sc_card_add_rsa_alg(card, 1024, flags, 0);
204                }
205                break;
206        case SC_CARD_TYPE_SETCOS_44:
207        case SC_CARD_TYPE_SETCOS_NIDEL:
208        case SC_CARD_TYPE_SETCOS_EID_V2_0:
209        case SC_CARD_TYPE_SETCOS_EID_V2_1:
210                {
211                        unsigned long flags;
212
213                        flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
214                        flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
215                        flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
216
217                        _sc_card_add_rsa_alg(card, 512, flags, 0);
218                        _sc_card_add_rsa_alg(card, 768, flags, 0);
219                        _sc_card_add_rsa_alg(card, 1024, flags, 0);
220                }
221                break;
222        }
223        return 0;
224}
225
226static const struct sc_card_operations *iso_ops = NULL;
227
228static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
229{
230        u8 *p = out;
231        u8 buf[64];
232        const u8 *pin_key_info;
233        int len;
234
235        /* Command */
236        *p++ = 0x6F;
237        p++;
238
239        /* Size (set to 0 for keys/PINs on a Java card) */
240        if (SETCOS_IS_EID_APPLET(card) &&
241            (file->type == SC_FILE_TYPE_INTERNAL_EF ||
242             (file->type == SC_FILE_TYPE_WORKING_EF && file->ef_structure == 0x22)))
243                buf[0] = buf[1] = 0x00;
244        else {
245                buf[0] = (file->size >> 8) & 0xFF;
246                buf[1] = file->size & 0xFF;
247        }
248        sc_asn1_put_tag(0x81, buf, 2, p, *outlen - (p - out), &p);
249
250        /* Type */
251        if (file->type_attr_len) {
252                memcpy(buf, file->type_attr, file->type_attr_len);
253                sc_asn1_put_tag(0x82, buf, file->type_attr_len, p, *outlen - (p - out), &p);
254        } else {
255                u8      bLen = 1;
256
257                buf[0] = file->shareable ? 0x40 : 0;
258                switch (file->type) {
259                case SC_FILE_TYPE_INTERNAL_EF:                          /* RSA keyfile */
260                        buf[0] = 0x11;                         
261                        break;
262                case SC_FILE_TYPE_WORKING_EF:
263                        if (file->ef_structure == 0x22) {               /* pin-file */
264                                buf[0] = 0x0A;                          /* EF linear fixed EF for ISF keys */
265                                if (SETCOS_IS_EID_APPLET(card))
266                                        bLen = 1;
267                                else {
268                                        /* Setcos V4.4 */
269                                        bLen = 5;
270                                        buf[1] = 0x41;                          /* fixed */
271                                        buf[2] = file->record_length >> 8;      /* 2 byte record length  */
272                                        buf[3] = file->record_length & 0xFF;
273                                        buf[4] = file->size / file->record_length; /* record count */
274                                }
275                        } else {
276                                buf[0] |= file->ef_structure & 7;       /* set file-type, only for EF, not for DF objects  */
277                        }
278                        break;
279                case SC_FILE_TYPE_DF:   
280                        buf[0] = 0x38;
281                        break;
282                default:
283                        return SC_ERROR_NOT_SUPPORTED;
284                }
285                sc_asn1_put_tag(0x82, buf, bLen, p, *outlen - (p - out), &p);
286        }
287
288        /* File ID */
289        buf[0] = (file->id >> 8) & 0xFF;
290        buf[1] = file->id & 0xFF;
291        sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
292
293        /* DF name */
294        if (file->type == SC_FILE_TYPE_DF) {
295                if (file->name[0] != 0)
296                        sc_asn1_put_tag(0x84, (u8 *) file->name, file->namelen, p, *outlen - (p - out), &p);
297                else { /* Name required -> take the FID if not specified */
298                        buf[0] = (file->id >> 8) & 0xFF;
299                        buf[1] = file->id & 0xFF;
300                        sc_asn1_put_tag(0x84, buf, 2, p, *outlen - (p - out), &p);
301                }
302        }
303
304        /* Security Attributes */
305        memcpy(buf, file->sec_attr, file->sec_attr_len);
306        sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p);
307
308        /* Life cycle status */
309        if (file->prop_attr_len) {
310                memcpy(buf, file->prop_attr, file->prop_attr_len);
311                sc_asn1_put_tag(0x8A, buf, file->prop_attr_len, p, *outlen - (p - out), &p);
312        }
313
314        /* PIN definitions */
315        if (file->type == SC_FILE_TYPE_DF) {
316                if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_1) {
317                        pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84";
318                        len = 6;
319                }
320                else if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_0) {
321                        pin_key_info = (const u8*)"\xC1\x04\x81\x82"; /* Max 2 PINs supported */
322                        len = 4;
323                }
324                else {
325                        /* Pin/key info: define 4 pins, no keys */
326                        if(file->path.len == 2)
327                                pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84\xC2\x00";   /* root-MF: use local pin-file */
328                        else
329                                pin_key_info = (const u8 *)"\xC1\x04\x01\x02\x03\x04\xC2\x00";  /* sub-DF: use parent pin-file in root-MF */
330                        len = 8;
331                }
332                sc_asn1_put_tag(0xA5, pin_key_info, len, p, *outlen - (p - out), &p);
333        }
334
335        /* Length */
336        out[1] = p - out - 2;
337
338        *outlen = p - out;
339        return 0;
340}
341
342static int setcos_construct_fci(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
343{
344        if (card->type == SC_CARD_TYPE_SETCOS_44 ||
345            card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
346            SETCOS_IS_EID_APPLET(card))
347                return setcos_construct_fci_44(card, file, out, outlen);
348        else
349                return iso_ops->construct_fci(card, file, out, outlen);
350}
351
352static u8 acl_to_byte(const sc_acl_entry_t *e)
353{
354        switch (e->method) {
355        case SC_AC_NONE:
356                return 0x00;
357        case SC_AC_CHV:
358                switch (e->key_ref) {
359                case 1:
360                        return 0x01;
361                        break;
362                case 2:
363                        return 0x02;
364                        break;
365                default:
366                        return 0x00;
367                }
368                break;
369        case SC_AC_TERM:
370                return 0x04;
371        case SC_AC_NEVER:
372                return 0x0F;
373        }
374        return 0x00;
375}
376
377static unsigned int acl_to_byte_44(const struct sc_acl_entry *e, u8* p_bNumber)
378{
379        /* Handle special fixed values */
380        if (e == (sc_acl_entry_t *) 1)           /* SC_AC_NEVER */
381                return SC_AC_NEVER;
382        else if ((e == (sc_acl_entry_t *) 2) ||  /* SC_AC_NONE */
383                 (e == (sc_acl_entry_t *) 3) ||  /* SC_AC_UNKNOWN */
384                 (e == (sc_acl_entry_t *) 0))
385                return SC_AC_NONE;
386
387        /* Handle standard values */
388        *p_bNumber = e->key_ref;
389        return(e->method);
390}
391
392/* If pin is present in the pins list, return it's index.
393 * If it's not yet present, add it to the list and return the index. */
394static int setcos_pin_index_44(int *pins, int len, int pin)
395{
396        int i;
397        for (i = 0; i < len; i++) {
398                if (pins[i] == pin)
399                        return i;
400                if (pins[i] == -1) {
401                        pins[i] = pin;
402                        return i;
403                }
404        }
405        assert(i != len); /* Too much PINs, shouldn't happen */
406        return 0;
407}
408
409/* The ACs are allways for the SETEC_LCSI_ACTIVATED state, even if
410 * we have to create the file in the SC_FILE_STATUS_INITIALISATION state. */
411static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
412{
413        const u8 bFileStatus = file->status == SC_FILE_STATUS_CREATION ?
414                SETEC_LCSI_CREATE : SETEC_LCSI_ACTIVATED;
415        u8 bCommands_always = 0;
416        int pins[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
417        u8 bCommands_pin[sizeof(pins)/sizeof(pins[0])]; /* both 7 entries big */
418        u8 bCommands_key = 0;
419        u8 bNumber = 0;
420        u8 bKeyNumber = 0;
421        unsigned int bMethod = 0;
422
423        /* -1 means RFU */
424        const int df_idx[8] = {  /* byte 1 = OpenSC type of AC Bit0,  byte 2 = OpenSC type of AC Bit1 ...*/
425                SC_AC_OP_DELETE, SC_AC_OP_CREATE, SC_AC_OP_CREATE,
426                SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
427                SC_AC_OP_LOCK, SC_AC_OP_DELETE, -1};
428        const int ef_idx[8] = {  /* note: SC_AC_OP_SELECT to be ignored, actually RFU */
429                SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
430                SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
431                -1, SC_AC_OP_ERASE, -1};
432        const int efi_idx[8] = {  /* internal EF used for RSA keys */
433                SC_AC_OP_READ, SC_AC_OP_ERASE, SC_AC_OP_UPDATE,
434                SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
435                -1, SC_AC_OP_ERASE, -1};
436
437        /* Set file creation status  */
438        sc_file_set_prop_attr(file, &bFileStatus, 1);
439
440        /* Build ACI from local structure = get AC for each operation group */
441        if (file->sec_attr_len == 0) {
442                const int* p_idx;
443                int            i;
444                int            len = 0;
445                u8         bBuf[32];
446
447                /* Get specific operation groups for specified file-type */
448                switch (file->type){
449                case SC_FILE_TYPE_DF:           /* DF */
450                        p_idx = df_idx;
451                        break;
452                case SC_FILE_TYPE_INTERNAL_EF:  /* EF for RSA keys */
453                        p_idx = efi_idx;
454                        break;
455                default:                        /* SC_FILE_TYPE_WORKING_EF */
456                        p_idx = ef_idx;
457                        break;
458                }
459
460                /* Get enabled commands + required Keys/Pins  */
461                memset(bCommands_pin, 0, sizeof(bCommands_pin));
462                for (i = 7; i >= 0; i--) {  /* for each AC Setcos operation */
463                        bCommands_always <<= 1;
464                        bCommands_key <<= 1;
465
466                        if (p_idx[i] == -1)  /* -1 means that bit is RFU -> set to 0 */
467                                continue;
468
469                        bMethod = acl_to_byte_44(file->acl[ p_idx[i] ], &bNumber);
470                        /* Convert to OpenSc-index, convert to pin/key number */
471                        switch(bMethod){
472                        case SC_AC_NONE:                        /* always allowed */
473                                bCommands_always |= 1;
474                                break;
475                        case SC_AC_CHV:                         /* pin */
476                                if ((bNumber & 0x7F) == 0 || (bNumber & 0x7F) > 7) {
477                                        sc_error(card->ctx, "SetCOS 4.4 PIN refs can only be 1..7\n");
478                                        return SC_ERROR_INVALID_ARGUMENTS;
479                                }
480                                bCommands_pin[setcos_pin_index_44(pins, sizeof(pins), (int) bNumber)] |= 1 << i;
481                                break;
482                        case SC_AC_TERM:                        /* key */
483                                bKeyNumber = bNumber;   /* There should be only 1 key */
484                                bCommands_key |= 1;
485                                break;
486                        }
487                }
488
489                /* Add the commands that are allways allowed */
490                if (bCommands_always) {
491                        bBuf[len++] = 1;
492                        bBuf[len++] = bCommands_always;
493                }
494                /* Add commands that require pins */
495                for (i = 0; i < (int)sizeof(bCommands_pin) && pins[i] != -1; i++) {
496                        bBuf[len++] = 2;
497                        bBuf[len++] = bCommands_pin[i];
498                        if (SETCOS_IS_EID_APPLET(card))
499                                bBuf[len++] = pins[i];  /* pin ref */
500                        else
501                                bBuf[len++] = pins[i] & 0x07;  /* pin ref */
502                }
503                /* Add ommands that require the key */
504                if (bCommands_key) {
505                        bBuf[len++] = 2 | 0x20;                 /* indicate keyNumber present */
506                        bBuf[len++] = bCommands_key;
507                        bBuf[len++] = bKeyNumber;
508                }
509                /* RSA signing/decryption requires AC adaptive coding,  can't be put
510                   in AC simple coding. Only implemented for pins, not for a key. */
511                bKeyNumber = 0;
512                if ( (file->type == SC_FILE_TYPE_INTERNAL_EF) &&
513                     (acl_to_byte_44(file->acl[SC_AC_OP_CRYPTO], &bNumber) == SC_AC_CHV) ) {
514                        bBuf[len++] = 0x83;
515                        bBuf[len++] = 0x01;
516                        bBuf[len++] = 0x2A;  /* INS byte for the sign/decrypt APDU */
517                        bBuf[len++] = bNumber & 0x07;  /* pin ref */
518                }
519
520                sc_file_set_sec_attr(file, bBuf, len);
521        }
522
523        return iso_ops->create_file(card, file);
524}
525
526static int setcos_create_file(sc_card_t *card, sc_file_t *file)
527{
528        if (card->type == SC_CARD_TYPE_SETCOS_44 || SETCOS_IS_EID_APPLET(card))
529                return setcos_create_file_44(card, file);
530
531        if (file->prop_attr_len == 0)
532                sc_file_set_prop_attr(file, (const u8 *) "\x03\x00\x00", 3);
533        if (file->sec_attr_len == 0) {
534                int idx[6], i;
535                u8 buf[6];
536
537                if (file->type == SC_FILE_TYPE_DF) {
538                        const int df_idx[6] = {
539                                SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
540                                SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
541                                SC_AC_OP_INVALIDATE
542                        };
543                        for (i = 0; i < 6; i++)
544                                idx[i] = df_idx[i];
545                } else {
546                        const int ef_idx[6] = {
547                                SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
548                                SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
549                                SC_AC_OP_INVALIDATE
550                        };
551                        for (i = 0; i < 6; i++)
552                                idx[i] = ef_idx[i];
553                }
554                for (i = 0; i < 6; i++) {
555                        const struct sc_acl_entry *entry;
556                        entry = sc_file_get_acl_entry(file, idx[i]);
557                        buf[i] = acl_to_byte(entry);
558                }
559
560                sc_file_set_sec_attr(file, buf, 6);
561        }
562
563        return iso_ops->create_file(card, file);
564}
565
566static int setcos_set_security_env2(sc_card_t *card,
567                                    const sc_security_env_t *env, int se_num)
568{
569        sc_apdu_t apdu;
570        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
571        u8 *p;
572        int r, locked = 0;
573
574        assert(card != NULL && env != NULL);
575
576        if (card->type == SC_CARD_TYPE_SETCOS_44 ||
577            card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
578            SETCOS_IS_EID_APPLET(card)) {
579                if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) {
580                        sc_error(card->ctx, "asymmetric keyref not supported.\n");
581                        return SC_ERROR_NOT_SUPPORTED;
582                }
583                if (se_num > 0) {
584                        sc_error(card->ctx, "restore security environment not supported.\n");
585                        return SC_ERROR_NOT_SUPPORTED;
586                }
587        }
588
589        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
590        switch (env->operation) {
591        case SC_SEC_OPERATION_DECIPHER:
592                /* Should be 0x81 */
593                apdu.p1 = 0x41;
594                apdu.p2 = 0xB8;
595                break;
596        case SC_SEC_OPERATION_SIGN:
597                /* Should be 0x41 */
598                apdu.p1 = ((card->type == SC_CARD_TYPE_SETCOS_FINEID_V2) ||
599                           (card->type == SC_CARD_TYPE_SETCOS_44) ||
600                           (card->type == SC_CARD_TYPE_SETCOS_NIDEL) ||
601                           SETCOS_IS_EID_APPLET(card)) ? 0x41 : 0x81;
602                apdu.p2 = 0xB6;
603                break;
604        default:
605                return SC_ERROR_INVALID_ARGUMENTS;
606        }
607        apdu.le = 0;
608        p = sbuf;
609        if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
610                *p++ = 0x80;    /* algorithm reference */
611                *p++ = 0x01;
612                *p++ = env->algorithm_ref & 0xFF;
613        }
614        if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {
615                *p++ = 0x81;
616                *p++ = env->file_ref.len;
617                memcpy(p, env->file_ref.value, env->file_ref.len);
618                p += env->file_ref.len;
619        }
620        if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
621                if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC)
622                        *p++ = 0x83;
623                else
624                        *p++ = 0x84;
625                *p++ = env->key_ref_len;
626                memcpy(p, env->key_ref, env->key_ref_len);
627                p += env->key_ref_len;
628        }
629        r = p - sbuf;
630        apdu.lc = r;
631        apdu.datalen = r;
632        apdu.data = sbuf;
633        apdu.resplen = 0;
634        if (se_num > 0) {
635                r = sc_lock(card);
636                SC_TEST_RET(card->ctx, r, "sc_lock() failed");
637                locked = 1;
638        }
639        if (apdu.datalen != 0) {
640                r = sc_transmit_apdu(card, &apdu);
641                if (r) {
642                        sc_perror(card->ctx, r, "APDU transmit failed");
643                        goto err;
644                }
645                r = sc_check_sw(card, apdu.sw1, apdu.sw2);
646                if (r) {
647                        sc_perror(card->ctx, r, "Card returned error");
648                        goto err;
649                }
650        }
651        if (se_num <= 0)
652                return 0;
653        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num);
654        r = sc_transmit_apdu(card, &apdu);
655        sc_unlock(card);
656        SC_TEST_RET(card->ctx, r, "APDU transmit failed");
657        return sc_check_sw(card, apdu.sw1, apdu.sw2);
658err:
659        if (locked)
660                sc_unlock(card);
661        return r;
662}
663
664static int setcos_set_security_env(sc_card_t *card,
665                                   const sc_security_env_t *env, int se_num)
666{
667        if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
668                sc_security_env_t tmp;
669
670                tmp = *env;
671                tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
672                tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
673                if (tmp.algorithm != SC_ALGORITHM_RSA) {
674                        sc_error(card->ctx, "Only RSA algorithm supported.\n");
675                        return SC_ERROR_NOT_SUPPORTED;
676                }
677                switch (card->type) {
678                case SC_CARD_TYPE_SETCOS_PKI:
679                case SC_CARD_TYPE_SETCOS_FINEID:
680                case SC_CARD_TYPE_SETCOS_FINEID_V2:
681                case SC_CARD_TYPE_SETCOS_NIDEL:
682                case SC_CARD_TYPE_SETCOS_44:
683                case SC_CARD_TYPE_SETCOS_EID_V2_0:
684                case SC_CARD_TYPE_SETCOS_EID_V2_1:
685                        break;
686                default:
687                        sc_error(card->ctx, "Card does not support RSA.\n");
688                        return SC_ERROR_NOT_SUPPORTED;
689                        break;
690                }
691                tmp.algorithm_ref = 0x00;
692                /* potential FIXME: return an error, if an unsupported
693                 * pad or hash was requested, although this shouldn't happen.
694                 */
695                if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
696                        tmp.algorithm_ref = 0x02;
697                if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
698                        tmp.algorithm_ref |= 0x10;
699                return setcos_set_security_env2(card, &tmp, se_num);
700        }
701        return setcos_set_security_env2(card, env, se_num);
702}
703
704static void add_acl_entry(sc_file_t *file, int op, u8 byte)
705{
706        unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
707
708        switch (byte >> 4) {
709        case 0:
710                method = SC_AC_NONE;
711                break;
712        case 1:
713                method = SC_AC_CHV;
714                key_ref = 1;
715                break;
716        case 2:
717                method = SC_AC_CHV;
718                key_ref = 2;
719                break;
720        case 4:
721                method = SC_AC_TERM;
722                break;
723        case 15:
724                method = SC_AC_NEVER;
725                break;
726        default:
727                method = SC_AC_UNKNOWN;
728                break;
729        }
730        sc_file_add_acl_entry(file, op, method, key_ref);
731}
732
733static void parse_sec_attr(sc_file_t *file, const u8 * buf, size_t len)
734{
735        int i;
736        int idx[6];
737
738        if (len < 6)
739                return;
740        if (file->type == SC_FILE_TYPE_DF) {
741                const int df_idx[6] = {
742                        SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
743                        SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
744                        SC_AC_OP_INVALIDATE
745                };
746                for (i = 0; i < 6; i++)
747                        idx[i] = df_idx[i];
748        } else {
749                const int ef_idx[6] = {
750                        SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
751                        SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
752                        SC_AC_OP_INVALIDATE
753                };
754                for (i = 0; i < 6; i++)
755                        idx[i] = ef_idx[i];
756        }
757        for (i = 0; i < 6; i++)
758                add_acl_entry(file, idx[i], buf[i]);
759}
760
761static void parse_sec_attr_44(sc_file_t *file, const u8 *buf, size_t len)
762{
763        /* OpenSc Operation values for each command operation-type */
764        const int df_idx[8] = {  /* byte 1 = OpenSC type of AC Bit0,  byte 2 = OpenSC type of AC Bit1 ...*/
765                SC_AC_OP_DELETE, SC_AC_OP_CREATE, SC_AC_OP_CREATE,
766                SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
767                SC_AC_OP_LOCK, SC_AC_OP_DELETE, -1};
768        const int ef_idx[8] = {
769                SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
770                SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
771                -1, SC_AC_OP_ERASE, -1};
772        const int efi_idx[8] = { /* internal EF used for RSA keys */
773                SC_AC_OP_READ, SC_AC_OP_ERASE, SC_AC_OP_UPDATE,
774                SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
775                -1, SC_AC_OP_ERASE, -1};
776
777        u8              bValue;
778        int             i;
779        int             iKeyRef = 0;
780        int             iMethod;
781        int             iPinCount;
782        int             iOffset = 0;
783        int             iOperation;
784        const int*      p_idx;
785
786        /* Check all sub-AC definitions whitin the total AC */
787        while (len > 1) {                               /* minimum length = 2 */
788                int     iACLen   = buf[iOffset] & 0x0F;
789
790                iPinCount = -1;                 /* default no pin required */
791                iMethod = SC_AC_NONE;           /* default no authentication required */
792
793                if (buf[iOffset] & 0X80) { /* AC in adaptive coding */
794                        /* Evaluates only the command-byte, not the optional P1/P2/Option bytes */
795                        int     iParmLen = 1;                   /* command-byte is always present */
796                        int     iKeyLen  = 0;                   /* Encryption key is optional */
797
798                        if (buf[iOffset]   & 0x20) iKeyLen++;
799                        if (buf[iOffset+1] & 0x40) iParmLen++;
800                        if (buf[iOffset+1] & 0x20) iParmLen++;
801                        if (buf[iOffset+1] & 0x10) iParmLen++;
802                        if (buf[iOffset+1] & 0x08) iParmLen++;
803
804                        /* Get KeyNumber if available */
805                        if(iKeyLen) {
806                                int iSC = buf[iOffset+iACLen];
807
808                                switch( (iSC>>5) & 0x03 ){
809                                case 0:
810                                        iMethod = SC_AC_TERM;           /* key authentication */
811                                        break;
812                                case 1:
813                                        iMethod = SC_AC_AUT;            /* key authentication  */
814                                        break;
815                                case 2:
816                                case 3:
817                                        iMethod = SC_AC_PRO;            /* secure messaging */
818                                        break;
819                                }
820                                iKeyRef = iSC & 0x1F;                   /* get key number */
821                        }
822
823                        /* Get PinNumber if available */
824                        if (iACLen > (1+iParmLen+iKeyLen)) {  /* check via total length if pin is present */
825                                iKeyRef = buf[iOffset+1+1+iParmLen];  /* PTL + AM-header + parameter-bytes */
826                                iMethod = SC_AC_CHV;
827                        }
828
829                        /* Convert SETCOS command to OpenSC command group */
830                        switch(buf[iOffset+2]){
831                        case 0x2A:                      /* crypto operation */
832                                iOperation = SC_AC_OP_CRYPTO;
833                                break;
834                        case 0x46:                      /* key-generation operation */
835                                iOperation = SC_AC_OP_UPDATE;
836                                break;
837                        default:
838                                iOperation = SC_AC_OP_SELECT;
839                                break;
840                        }
841                        sc_file_add_acl_entry(file, iOperation, iMethod, iKeyRef);
842                }
843                else { /* AC in simple coding */
844                           /* Initial AC is treated as an operational AC */
845
846                        /* Get specific Cmd groups for specified file-type */
847                        switch (file->type) {
848                        case SC_FILE_TYPE_DF:            /* DF */
849                                p_idx = df_idx;
850                                break;
851                        case SC_FILE_TYPE_INTERNAL_EF:   /* EF for RSA keys */
852                                p_idx = efi_idx;
853                                break;
854                        default:                         /* EF */
855                                p_idx = ef_idx;
856                                break;
857                        }
858
859                        /* Encryption key present ? */
860                        iPinCount = iACLen - 1;         
861
862                        if (buf[iOffset] & 0x20) {
863                                int iSC = buf[iOffset + iACLen];
864
865                                switch( (iSC>>5) & 0x03 ) {
866                                case 0:
867                                        iMethod = SC_AC_TERM;           /* key authentication */
868                                        break;
869                                case 1:
870                                        iMethod = SC_AC_AUT;            /* key authentication  */
871                                        break;
872                                case 2:
873                                case 3:
874                                        iMethod = SC_AC_PRO;            /* secure messaging */
875                                        break;
876                                }
877                                iKeyRef = iSC & 0x1F;                   /* get key number */
878
879                                iPinCount--;                            /* one byte used for keyReference  */
880                        }
881
882                        /* Pin present ? */
883                        if ( iPinCount > 0 ) {
884                                iKeyRef = buf[iOffset + 2];     /* pin ref */
885              Â