Coverage Report

Created: 2025-08-24 06:59

/src/opensc/src/libopensc/card-setcos.c
Line
Count
Source (jump to first uncovered 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
27
#include <stdlib.h>
28
#include <string.h>
29
30
#include "internal.h"
31
#include "asn1.h"
32
#include "cardctl.h"
33
34
0
#define _FINEID_BROKEN_SELECT_FLAG 1
35
36
static const struct sc_atr_table setcos_atrs[] = {
37
  /* some Nokia branded SC */
38
  { "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 },
39
  /* RSA SecurID 3100 */
40
  { "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 },
41
42
  /* FINEID 1016 (SetCOS 4.3.1B3/PKCS#15, VRK) */
43
  { "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 },
44
  /* FINEID 2032 (EIDApplet/7816-15, VRK test) */
45
  { "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 },
46
  /* FINEID 2132 (EIDApplet/7816-15, 3rdparty test) */
47
  { "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 },
48
  /* FINEID 2064 (EIDApplet/7816-15, VRK) */
49
  { "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 },
50
  /* FINEID 2164 (EIDApplet/7816-15, 3rdparty) */
51
  { "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 },
52
  /* FINEID 2264 (EIDApplet/7816-15, OPK/EMV/AVANT) */
53
  { "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 },
54
  { "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 },
55
  /* FINEID cards 1.3.2011 with Samsung chips (round connector) that supports 2048 bit keys. */
56
  { "3b:7b:94:00:00:80:62:12:51:56:46:69:6e:45:49:44", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2_2048, 0, NULL },
57
  /* FINEID card for organisations, chip unknown. */
58
  { "3b:7b:18:00:00:80:62:01:54:56:46:69:6e:45:49:44", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, _FINEID_BROKEN_SELECT_FLAG, NULL },
59
  /* Swedish NIDEL card */
60
  { "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 },
61
  /* Setcos 4.4.1 */
62
  { "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 },
63
  { NULL, NULL, NULL, 0, 0, NULL }
64
};
65
66
0
#define SETCOS_IS_EID_APPLET(card) ((card)->type == SC_CARD_TYPE_SETCOS_EID_V2_0 || (card)->type == SC_CARD_TYPE_SETCOS_EID_V2_1)
67
68
/* Setcos 4.4 Life Cycle Status Integer  */
69
0
#define SETEC_LCSI_CREATE      0x01
70
#define SETEC_LCSI_INIT        0x03
71
0
#define SETEC_LCSI_ACTIVATED   0x07
72
#define SETEC_LCSI_DEACTIVATE  0x06
73
#define SETEC_LCSI_TEMINATE    0x0F /* MF only  */
74
75
static struct sc_card_operations setcos_ops;
76
static struct sc_card_driver setcos_drv = {
77
  "Setec cards",
78
  "setcos",
79
  &setcos_ops,
80
  NULL, 0, NULL
81
};
82
83
static int match_hist_bytes(sc_card_t *card, const char *str, size_t len)
84
0
{
85
0
  const char *src = (const char *) card->reader->atr_info.hist_bytes;
86
0
  size_t srclen = card->reader->atr_info.hist_bytes_len;
87
0
  size_t offset = 0;
88
89
0
  if (len == 0)
90
0
    len = strlen(str);
91
0
  if (srclen < len)
92
0
    return 0;
93
0
  while (srclen - offset > len) {
94
0
    if (memcmp(src + offset, str, len) == 0) {
95
0
      return 1;
96
0
    }
97
0
    offset++;
98
0
  }
99
0
  return 0;
100
0
}
101
102
static int setcos_match_card(sc_card_t *card)
103
0
{
104
0
  sc_apdu_t apdu;
105
0
  u8 buf[6];
106
0
  int i;
107
108
0
  i = _sc_match_atr(card, setcos_atrs, &card->type);
109
0
  if (i < 0) {
110
    /* Unknown card, but has the FinEID application for sure */
111
0
    if (match_hist_bytes(card, "FinEID", 0)) {
112
0
      card->type = SC_CARD_TYPE_SETCOS_FINEID_V2_2048;
113
0
      return 1;
114
0
    }
115
0
    if (match_hist_bytes(card, "FISE", 0)) {
116
0
      card->type = SC_CARD_TYPE_SETCOS_GENERIC;
117
0
      return 1;
118
0
    }
119
    /* Check if it's a EID2.x applet by reading the version info */
120
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0xDF, 0x30);
121
0
    apdu.cla = 0x00;
122
0
    apdu.resp = buf;
123
0
    apdu.resplen = 5;
124
0
    apdu.le = 5;
125
0
    i = sc_transmit_apdu(card, &apdu);
126
0
    if (i == 0 && apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && apdu.resplen == 5) {
127
0
      if (memcmp(buf, "v2.0", 4) == 0)
128
0
        card->type = SC_CARD_TYPE_SETCOS_EID_V2_0;
129
0
      else if (memcmp(buf, "v2.1", 4) == 0)
130
0
        card->type = SC_CARD_TYPE_SETCOS_EID_V2_1;
131
0
      else {
132
0
        buf[sizeof(buf) - 1] = '\0';
133
0
        sc_log(card->ctx,  "SetCOS EID applet %s is not supported", (char *) buf);
134
0
        return 0;
135
0
      }
136
0
      return 1;
137
0
    }
138
139
0
    return 0;
140
0
  }
141
0
  card->flags = setcos_atrs[i].flags;
142
0
  return 1;
143
0
}
144
145
static int select_pkcs15_app(sc_card_t * card)
146
0
{
147
0
  sc_path_t app;
148
0
  int r;
149
150
  /* Regular PKCS#15 AID */
151
0
  sc_format_path("A000000063504B43532D3135", &app);
152
0
  app.type = SC_PATH_TYPE_DF_NAME;
153
0
  r = sc_select_file(card, &app, NULL);
154
0
  return r;
155
0
}
156
157
static int setcos_init(sc_card_t *card)
158
0
{
159
0
  card->name = "SetCOS";
160
161
  /* Handle unknown or forced cards */
162
0
  if (card->type < 0) {
163
0
    card->type = SC_CARD_TYPE_SETCOS_GENERIC;
164
0
  }
165
166
0
  switch (card->type) {
167
0
  case SC_CARD_TYPE_SETCOS_FINEID:
168
0
  case SC_CARD_TYPE_SETCOS_FINEID_V2_2048:
169
0
  case SC_CARD_TYPE_SETCOS_NIDEL:
170
0
    card->cla = 0x00;
171
0
    select_pkcs15_app(card);
172
0
    if (card->flags & SC_CARD_FLAG_RNG)
173
0
      card->caps |= SC_CARD_CAP_RNG;
174
0
    break;
175
0
  case SC_CARD_TYPE_SETCOS_44:
176
0
  case SC_CARD_TYPE_SETCOS_EID_V2_0:
177
0
  case SC_CARD_TYPE_SETCOS_EID_V2_1:
178
0
    card->cla = 0x00;
179
0
    card->caps |= SC_CARD_CAP_USE_FCI_AC;
180
0
    card->caps |= SC_CARD_CAP_RNG;
181
0
    card->caps |= SC_CARD_CAP_APDU_EXT;
182
0
    break;
183
0
  default:
184
    /* XXX: Get SetCOS version */
185
0
    card->cla = 0x80; /* SetCOS 4.3.x */
186
    /* State that we have an RNG */
187
0
    card->caps |= SC_CARD_CAP_RNG;
188
0
    break;
189
0
  }
190
191
0
  switch (card->type) {
192
0
  case SC_CARD_TYPE_SETCOS_PKI:
193
0
  case SC_CARD_TYPE_SETCOS_FINEID_V2_2048:
194
0
    {
195
0
      unsigned long flags;
196
197
0
      flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
198
0
      flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
199
200
0
      _sc_card_add_rsa_alg(card, 1024, flags, 0);
201
0
      _sc_card_add_rsa_alg(card, 2048, flags, 0);
202
0
    }
203
0
    break;
204
0
  case SC_CARD_TYPE_SETCOS_44:
205
0
  case SC_CARD_TYPE_SETCOS_NIDEL:
206
0
  case SC_CARD_TYPE_SETCOS_EID_V2_0:
207
0
  case SC_CARD_TYPE_SETCOS_EID_V2_1:
208
0
    {
209
0
      unsigned long flags;
210
211
0
      flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
212
0
      flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
213
0
      flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
214
215
0
      _sc_card_add_rsa_alg(card, 512, flags, 0);
216
0
      _sc_card_add_rsa_alg(card, 768, flags, 0);
217
0
      _sc_card_add_rsa_alg(card, 1024, flags, 0);
218
0
      _sc_card_add_rsa_alg(card, 2048, flags, 0);
219
0
    }
220
0
    break;
221
0
  }
222
0
  return 0;
223
0
}
224
225
static const struct sc_card_operations *iso_ops = NULL;
226
227
static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
228
0
{
229
0
  u8 *p = out;
230
0
  u8 buf[64];
231
0
  const u8 *pin_key_info;
232
0
  int len;
233
234
  /* Command */
235
0
  *p++ = 0x6F;
236
0
  p++;
237
238
  /* Size (set to 0 for keys/PINs on a Java card) */
239
0
  if (SETCOS_IS_EID_APPLET(card) &&
240
0
      (file->type == SC_FILE_TYPE_INTERNAL_EF ||
241
0
       (file->type == SC_FILE_TYPE_WORKING_EF && file->ef_structure == 0x22)))
242
0
        buf[0] = buf[1] = 0x00;
243
0
  else {
244
0
    buf[0] = (file->size >> 8) & 0xFF;
245
0
    buf[1] = file->size & 0xFF;
246
0
  }
247
0
  sc_asn1_put_tag(0x81, buf, 2, p, *outlen - (p - out), &p);
248
249
  /* Type */
250
0
  if (file->type_attr_len) {
251
0
    memcpy(buf, file->type_attr, file->type_attr_len);
252
0
    sc_asn1_put_tag(0x82, buf, file->type_attr_len, p, *outlen - (p - out), &p);
253
0
  } else {
254
0
    u8  bLen = 1;
255
256
0
    buf[0] = file->shareable ? 0x40 : 0;
257
0
    switch (file->type) {
258
0
    case SC_FILE_TYPE_INTERNAL_EF:       /* RSA keyfile */
259
0
      buf[0] = 0x11;
260
0
      break;
261
0
    case SC_FILE_TYPE_WORKING_EF:
262
0
      if (file->ef_structure == 0x22) {   /* pin-file */
263
0
        buf[0] = 0x0A;        /* EF linear fixed EF for ISF keys */
264
0
        if (SETCOS_IS_EID_APPLET(card))
265
0
          bLen = 1;
266
0
        else {
267
          /* Setcos V4.4 */
268
0
          bLen = 5;
269
0
          buf[1] = 0x41;        /* fixed */
270
0
          buf[2] = file->record_length >> 8;  /* 2 byte record length  */
271
0
          buf[3] = file->record_length & 0xFF;
272
0
          buf[4] = file->size / file->record_length; /* record count */
273
0
        }
274
0
      } else {
275
0
        buf[0] |= file->ef_structure & 7; /* set file-type, only for EF, not for DF objects  */
276
0
      }
277
0
      break;
278
0
    case SC_FILE_TYPE_DF:
279
0
      buf[0] = 0x38;
280
0
      break;
281
0
    default:
282
0
      return SC_ERROR_NOT_SUPPORTED;
283
0
    }
284
0
    sc_asn1_put_tag(0x82, buf, bLen, p, *outlen - (p - out), &p);
285
0
  }
286
287
  /* File ID */
288
0
  buf[0] = (file->id >> 8) & 0xFF;
289
0
  buf[1] = file->id & 0xFF;
290
0
  sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
291
292
  /* DF name */
293
0
  if (file->type == SC_FILE_TYPE_DF) {
294
0
    if (file->name[0] != 0)
295
0
      sc_asn1_put_tag(0x84, (u8 *) file->name, file->namelen, p, *outlen - (p - out), &p);
296
0
    else { /* Name required -> take the FID if not specified */
297
0
      buf[0] = (file->id >> 8) & 0xFF;
298
0
      buf[1] = file->id & 0xFF;
299
0
      sc_asn1_put_tag(0x84, buf, 2, p, *outlen - (p - out), &p);
300
0
    }
301
0
  }
302
303
  /* Security Attributes */
304
0
  memcpy(buf, file->sec_attr, file->sec_attr_len);
305
0
  sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p);
306
307
  /* Life cycle status */
308
0
  if (file->prop_attr_len) {
309
0
    memcpy(buf, file->prop_attr, file->prop_attr_len);
310
0
    sc_asn1_put_tag(0x8A, buf, file->prop_attr_len, p, *outlen - (p - out), &p);
311
0
  }
312
313
  /* PIN definitions */
314
0
  if (file->type == SC_FILE_TYPE_DF) {
315
0
    if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_1) {
316
0
      pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84";
317
0
      len = 6;
318
0
    }
319
0
    else if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_0) {
320
0
      pin_key_info = (const u8*)"\xC1\x04\x81\x82"; /* Max 2 PINs supported */
321
0
      len = 4;
322
0
    }
323
0
    else {
324
      /* Pin/key info: define 4 pins, no keys */
325
0
      if(file->path.len == 2)
326
0
        pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84\xC2\x00"; /* root-MF: use local pin-file */
327
0
      else
328
0
        pin_key_info = (const u8 *)"\xC1\x04\x01\x02\x03\x04\xC2\x00"; /* sub-DF: use parent pin-file in root-MF */
329
0
      len = 8;
330
0
    }
331
0
    sc_asn1_put_tag(0xA5, pin_key_info, len, p, *outlen - (p - out), &p);
332
0
  }
333
334
  /* Length */
335
0
  out[1] = p - out - 2;
336
337
0
  *outlen = p - out;
338
0
  return 0;
339
0
}
340
341
static int setcos_construct_fci(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
342
0
{
343
0
  if (card->type == SC_CARD_TYPE_SETCOS_44 ||
344
0
      card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
345
0
      SETCOS_IS_EID_APPLET(card))
346
0
    return setcos_construct_fci_44(card, file, out, outlen);
347
0
  else
348
0
    return iso_ops->construct_fci(card, file, out, outlen);
349
0
}
350
351
static u8 acl_to_byte(const sc_acl_entry_t *e)
352
0
{
353
0
  switch (e->method) {
354
0
  case SC_AC_NONE:
355
0
    return 0x00;
356
0
  case SC_AC_CHV:
357
0
    switch (e->key_ref) {
358
0
    case 1:
359
0
      return 0x01;
360
0
      break;
361
0
    case 2:
362
0
      return 0x02;
363
0
      break;
364
0
    default:
365
0
      return 0x00;
366
0
    }
367
0
    break;
368
0
  case SC_AC_TERM:
369
0
    return 0x04;
370
0
  case SC_AC_NEVER:
371
0
    return 0x0F;
372
0
  }
373
0
  return 0x00;
374
0
}
375
376
static unsigned int acl_to_byte_44(const struct sc_acl_entry *e, u8* p_bNumber)
377
0
{
378
  /* Handle special fixed values */
379
0
  if (e == (sc_acl_entry_t *) 1)           /* SC_AC_NEVER */
380
0
    return SC_AC_NEVER;
381
0
  else if ((e == (sc_acl_entry_t *) 2) ||  /* SC_AC_NONE */
382
0
           (e == (sc_acl_entry_t *) 3) ||  /* SC_AC_UNKNOWN */
383
0
           (e == (sc_acl_entry_t *) 0))
384
0
    return SC_AC_NONE;
385
386
  /* Handle standard values */
387
0
  *p_bNumber = e->key_ref;
388
0
  return(e->method);
389
0
}
390
391
/* If pin is present in the pins list, return it's index.
392
 * If it's not yet present, add it to the list and return the index. */
393
static int setcos_pin_index_44(int *pins, int len, int pin)
394
0
{
395
0
  int i;
396
0
  for (i = 0; i < len; i++) {
397
0
    if (pins[i] == pin)
398
0
      return i;
399
0
    if (pins[i] == -1) {
400
0
      pins[i] = pin;
401
0
      return i;
402
0
    }
403
0
  }
404
0
  assert(i != len); /* Too much PINs, shouldn't happen */
405
0
  return 0;
406
0
}
407
408
/* The ACs are always for the SETEC_LCSI_ACTIVATED state, even if
409
 * we have to create the file in the SC_FILE_STATUS_INITIALISATION state. */
410
static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
411
0
{
412
0
  const u8 bFileStatus = file->status == SC_FILE_STATUS_CREATION ?
413
0
    SETEC_LCSI_CREATE : SETEC_LCSI_ACTIVATED;
414
0
  u8 bCommands_always = 0;
415
0
  int pins[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
416
0
  u8 bCommands_pin[sizeof(pins)/sizeof(pins[0])]; /* both 7 entries big */
417
0
  u8 bCommands_key = 0;
418
0
  u8 bNumber = 0;
419
0
  u8 bKeyNumber = 0;
420
0
  unsigned int bMethod = 0;
421
422
  /* -1 means RFU */
423
0
  const int df_idx[8] = {  /* byte 1 = OpenSC type of AC Bit0,  byte 2 = OpenSC type of AC Bit1 ...*/
424
0
    SC_AC_OP_DELETE, SC_AC_OP_CREATE, SC_AC_OP_CREATE,
425
0
    SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
426
0
    SC_AC_OP_LOCK, SC_AC_OP_DELETE, -1};
427
0
  const int ef_idx[8] = {  /* note: SC_AC_OP_SELECT to be ignored, actually RFU */
428
0
    SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
429
0
    SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
430
0
    -1, SC_AC_OP_ERASE, -1};
431
0
  const int efi_idx[8] = {  /* internal EF used for RSA keys */
432
0
    SC_AC_OP_READ, SC_AC_OP_ERASE, SC_AC_OP_UPDATE,
433
0
    SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
434
0
    -1, SC_AC_OP_ERASE, -1};
435
436
  /* Set file creation status  */
437
0
  sc_file_set_prop_attr(file, &bFileStatus, 1);
438
439
  /* Build ACL from local structure = get AC for each operation group */
440
0
  if (file->sec_attr_len == 0) {
441
0
    const int* p_idx;
442
0
    int        i;
443
0
    int        len = 0;
444
0
    u8         bBuf[64];
445
446
    /* Get specific operation groups for specified file-type */
447
0
    switch (file->type){
448
0
    case SC_FILE_TYPE_DF:           /* DF */
449
0
      p_idx = df_idx;
450
0
      break;
451
0
    case SC_FILE_TYPE_INTERNAL_EF:  /* EF for RSA keys */
452
0
      p_idx = efi_idx;
453
0
      break;
454
0
    default:                        /* SC_FILE_TYPE_WORKING_EF */
455
0
      p_idx = ef_idx;
456
0
      break;
457
0
    }
458
459
    /* Get enabled commands + required Keys/Pins  */
460
0
    memset(bCommands_pin, 0, sizeof(bCommands_pin));
461
0
    for (i = 7; i >= 0; i--) {  /* for each AC Setcos operation */
462
0
      bCommands_always <<= 1;
463
0
      bCommands_key <<= 1;
464
465
0
      if (p_idx[i] == -1)  /* -1 means that bit is RFU -> set to 0 */
466
0
        continue;
467
468
0
      bMethod = acl_to_byte_44(file->acl[ p_idx[i] ], &bNumber);
469
      /* Convert to OpenSc-index, convert to pin/key number */
470
0
      switch(bMethod){
471
0
      case SC_AC_NONE:     /* always allowed */
472
0
        bCommands_always |= 1;
473
0
        break;
474
0
      case SC_AC_CHV:       /* pin */
475
0
        if ((bNumber & 0x7F) == 0 || (bNumber & 0x7F) > 7) {
476
0
          sc_log(card->ctx,  "SetCOS 4.4 PIN refs can only be 1..7\n");
477
0
          return SC_ERROR_INVALID_ARGUMENTS;
478
0
        }
479
0
        bCommands_pin[setcos_pin_index_44(pins, sizeof(pins)/sizeof(pins[0]), (int) bNumber)] |= 1 << i;
480
0
        break;
481
0
      case SC_AC_TERM:     /* key */
482
0
        bKeyNumber = bNumber; /* There should be only 1 key */
483
0
        bCommands_key |= 1;
484
0
        break;
485
0
      }
486
0
    }
487
488
    /* Add the commands that are always allowed */
489
0
    if (bCommands_always) {
490
0
      bBuf[len++] = 1;
491
0
      bBuf[len++] = bCommands_always;
492
0
    }
493
    /* Add commands that require pins */
494
0
    for (i = 0; i < (int)sizeof(bCommands_pin) && pins[i] != -1; i++) {
495
0
      bBuf[len++] = 2;
496
0
      bBuf[len++] = bCommands_pin[i];
497
0
      if (SETCOS_IS_EID_APPLET(card))
498
0
        bBuf[len++] = pins[i];  /* pin ref */
499
0
      else
500
0
        bBuf[len++] = pins[i] & 0x07;  /* pin ref */
501
0
    }
502
    /* Add commands that require the key */
503
0
    if (bCommands_key) {
504
0
      bBuf[len++] = 2 | 0x20;     /* indicate keyNumber present */
505
0
      bBuf[len++] = bCommands_key;
506
0
      bBuf[len++] = bKeyNumber;
507
0
    }
508
    /* RSA signing/decryption requires AC adaptive coding,  can't be put
509
       in AC simple coding. Only implemented for pins, not for a key. */
510
0
    if ( (file->type == SC_FILE_TYPE_INTERNAL_EF) &&
511
0
         (acl_to_byte_44(file->acl[SC_AC_OP_CRYPTO], &bNumber) == SC_AC_CHV) ) {
512
0
      bBuf[len++] = 0x83;
513
0
      bBuf[len++] = 0x01;
514
0
      bBuf[len++] = 0x2A;  /* INS byte for the sign/decrypt APDU */
515
0
      bBuf[len++] = bNumber & 0x07;  /* pin ref */
516
0
    }
517
518
0
    sc_file_set_sec_attr(file, bBuf, len);
519
0
  }
520
521
0
  return iso_ops->create_file(card, file);
522
0
}
523
524
static int setcos_create_file(sc_card_t *card, sc_file_t *file)
525
0
{
526
0
  if (card->type == SC_CARD_TYPE_SETCOS_44 || SETCOS_IS_EID_APPLET(card))
527
0
    return setcos_create_file_44(card, file);
528
529
0
  if (file->prop_attr_len == 0)
530
0
    sc_file_set_prop_attr(file, (const u8 *) "\x03\x00\x00", 3);
531
0
  if (file->sec_attr_len == 0) {
532
0
    int idx[6], i;
533
0
    u8 buf[6];
534
535
0
    if (file->type == SC_FILE_TYPE_DF) {
536
0
      const int df_idx[6] = {
537
0
        SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
538
0
        SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
539
0
        SC_AC_OP_INVALIDATE
540
0
      };
541
0
      for (i = 0; i < 6; i++)
542
0
        idx[i] = df_idx[i];
543
0
    } else {
544
0
      const int ef_idx[6] = {
545
0
        SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
546
0
        SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
547
0
        SC_AC_OP_INVALIDATE
548
0
      };
549
0
      for (i = 0; i < 6; i++)
550
0
        idx[i] = ef_idx[i];
551
0
    }
552
0
    for (i = 0; i < 6; i++) {
553
0
      const struct sc_acl_entry *entry;
554
0
      entry = sc_file_get_acl_entry(file, idx[i]);
555
0
      buf[i] = acl_to_byte(entry);
556
0
    }
557
558
0
    sc_file_set_sec_attr(file, buf, 6);
559
0
  }
560
561
0
  return iso_ops->create_file(card, file);
562
0
}
563
564
static int setcos_set_security_env2(sc_card_t *card,
565
            const sc_security_env_t *env, int se_num)
566
0
{
567
0
  sc_apdu_t apdu;
568
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
569
0
  u8 *p;
570
0
  int r, locked = 0;
571
572
0
  assert(card != NULL && env != NULL);
573
574
0
  if (card->type == SC_CARD_TYPE_SETCOS_44 ||
575
0
      card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
576
0
      SETCOS_IS_EID_APPLET(card)) {
577
0
    if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) {
578
0
      sc_log(card->ctx,  "symmetric keyref not supported.\n");
579
0
      return SC_ERROR_NOT_SUPPORTED;
580
0
    }
581
0
    if (se_num > 0) {
582
0
      sc_log(card->ctx,  "restore security environment not supported.\n");
583
0
      return SC_ERROR_NOT_SUPPORTED;
584
0
    }
585
0
  }
586
587
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
588
0
  switch (env->operation) {
589
0
  case SC_SEC_OPERATION_DECIPHER:
590
    /* Should be 0x81 */
591
0
    apdu.p1 = 0x41;
592
0
    apdu.p2 = 0xB8;
593
0
    break;
594
0
  case SC_SEC_OPERATION_SIGN:
595
    /* Should be 0x41 */
596
0
    apdu.p1 = ((card->type == SC_CARD_TYPE_SETCOS_FINEID_V2) ||
597
0
               (card->type == SC_CARD_TYPE_SETCOS_FINEID_V2_2048) ||
598
0
               (card->type == SC_CARD_TYPE_SETCOS_44) ||
599
0
         (card->type == SC_CARD_TYPE_SETCOS_NIDEL) ||
600
0
         SETCOS_IS_EID_APPLET(card)) ? 0x41 : 0x81;
601
0
    apdu.p2 = 0xB6;
602
0
    break;
603
0
  default:
604
0
    return SC_ERROR_INVALID_ARGUMENTS;
605
0
  }
606
0
  apdu.le = 0;
607
0
  p = sbuf;
608
0
  if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
609
0
    *p++ = 0x80;  /* algorithm reference */
610
0
    *p++ = 0x01;
611
0
    *p++ = env->algorithm_ref & 0xFF;
612
0
  }
613
0
  if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {
614
0
    *p++ = 0x81;
615
0
    *p++ = env->file_ref.len;
616
0
    memcpy(p, env->file_ref.value, env->file_ref.len);
617
0
    p += env->file_ref.len;
618
0
  }
619
0
  if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT &&
620
0
      !(card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
621
0
        card->type == SC_CARD_TYPE_SETCOS_FINEID_V2_2048)) {
622
0
    if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC)
623
0
      *p++ = 0x83;
624
0
    else
625
0
      *p++ = 0x84;
626
0
    *p++ = env->key_ref_len;
627
0
    memcpy(p, env->key_ref, env->key_ref_len);
628
0
    p += env->key_ref_len;
629
0
  }
630
0
  r = (int)(p - sbuf);
631
0
  apdu.lc = r;
632
0
  apdu.datalen = r;
633
0
  apdu.data = sbuf;
634
0
  apdu.resplen = 0;
635
0
  if (se_num > 0) {
636
0
    r = sc_lock(card);
637
0
    LOG_TEST_RET(card->ctx, r, "sc_lock() failed");
638
0
    locked = 1;
639
0
  }
640
0
  if (apdu.datalen != 0) {
641
0
    r = sc_transmit_apdu(card, &apdu);
642
0
    if (r) {
643
0
      sc_log(card->ctx,
644
0
        "%s: APDU transmit failed", sc_strerror(r));
645
0
      goto err;
646
0
    }
647
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
648
0
    if (r) {
649
0
      sc_log(card->ctx,
650
0
        "%s: Card returned error", sc_strerror(r));
651
0
      goto err;
652
0
    }
653
0
  }
654
0
  if (se_num <= 0)
655
0
    return 0;
656
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num);
657
0
  r = sc_transmit_apdu(card, &apdu);
658
0
  sc_unlock(card);
659
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
660
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
661
0
err:
662
0
  if (locked)
663
0
    sc_unlock(card);
664
0
  return r;
665
0
}
666
667
static int setcos_set_security_env(sc_card_t *card,
668
           const sc_security_env_t *env, int se_num)
669
0
{
670
0
  if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
671
0
    sc_security_env_t tmp;
672
673
0
    tmp = *env;
674
0
    tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
675
0
    tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
676
0
    if (tmp.algorithm != SC_ALGORITHM_RSA) {
677
0
      sc_log(card->ctx,  "Only RSA algorithm supported.\n");
678
0
      return SC_ERROR_NOT_SUPPORTED;
679
0
    }
680
0
    switch (card->type) {
681
0
    case SC_CARD_TYPE_SETCOS_PKI:
682
0
    case SC_CARD_TYPE_SETCOS_FINEID:
683
0
    case SC_CARD_TYPE_SETCOS_FINEID_V2_2048:
684
0
    case SC_CARD_TYPE_SETCOS_NIDEL:
685
0
    case SC_CARD_TYPE_SETCOS_44:
686
0
    case SC_CARD_TYPE_SETCOS_EID_V2_0:
687
0
    case SC_CARD_TYPE_SETCOS_EID_V2_1:
688
0
      break;
689
0
    default:
690
0
      sc_log(card->ctx,  "Card does not support RSA.\n");
691
0
      return SC_ERROR_NOT_SUPPORTED;
692
0
      break;
693
0
    }
694
0
    tmp.algorithm_ref = 0x00;
695
    /* potential FIXME: return an error, if an unsupported
696
     * pad or hash was requested, although this shouldn't happen.
697
     */
698
0
    if ((env->operation == SC_SEC_OPERATION_SIGN && env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01) ||
699
0
        (env->operation == SC_SEC_OPERATION_DECIPHER && env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02))
700
0
      tmp.algorithm_ref = 0x02;
701
0
    if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
702
0
      tmp.algorithm_ref |= 0x10;
703
0
    return setcos_set_security_env2(card, &tmp, se_num);
704
0
  }
705
0
  return setcos_set_security_env2(card, env, se_num);
706
0
}
707
708
static void add_acl_entry(sc_file_t *file, int op, u8 byte)
709
0
{
710
0
  unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
711
712
0
  switch (byte >> 4) {
713
0
  case 0:
714
0
    method = SC_AC_NONE;
715
0
    break;
716
0
  case 1:
717
0
    method = SC_AC_CHV;
718
0
    key_ref = 1;
719
0
    break;
720
0
  case 2:
721
0
    method = SC_AC_CHV;
722
0
    key_ref = 2;
723
0
    break;
724
0
  case 4:
725
0
    method = SC_AC_TERM;
726
0
    break;
727
0
  case 15:
728
0
    method = SC_AC_NEVER;
729
0
    break;
730
0
  default:
731
0
    method = SC_AC_UNKNOWN;
732
0
    break;
733
0
  }
734
0
  sc_file_add_acl_entry(file, op, method, key_ref);
735
0
}
736
737
static void parse_sec_attr(sc_file_t *file, const u8 * buf, size_t len)
738
0
{
739
0
  int i;
740
0
  int idx[6];
741
742
0
  if (len < 6)
743
0
    return;
744
0
  if (file->type == SC_FILE_TYPE_DF) {
745
0
    const int df_idx[6] = {
746
0
      SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
747
0
      SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
748
0
      SC_AC_OP_INVALIDATE
749
0
    };
750
0
    for (i = 0; i < 6; i++)
751
0
      idx[i] = df_idx[i];
752
0
  } else {
753
0
    const int ef_idx[6] = {
754
0
      SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
755
0
      SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
756
0
      SC_AC_OP_INVALIDATE
757
0
    };
758
0
    for (i = 0; i < 6; i++)
759
0
      idx[i] = ef_idx[i];
760
0
  }
761
0
  for (i = 0; i < 6; i++)
762
0
    add_acl_entry(file, idx[i], buf[i]);
763
0
}
764
765
static void parse_sec_attr_44(sc_file_t *file, const u8 *buf, size_t len)
766
0
{
767
  /* OpenSc Operation values for each command operation-type */
768
0
  const int df_idx[8] = {  /* byte 1 = OpenSC type of AC Bit0,  byte 2 = OpenSC type of AC Bit1 ...*/
769
0
    SC_AC_OP_DELETE, SC_AC_OP_CREATE, SC_AC_OP_CREATE,
770
0
    SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
771
0
    SC_AC_OP_LOCK, SC_AC_OP_DELETE, -1};
772
0
  const int ef_idx[8] = {
773
0
    SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
774
0
    SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
775
0
    -1, SC_AC_OP_ERASE, -1};
776
0
  const int efi_idx[8] = { /* internal EF used for RSA keys */
777
0
    SC_AC_OP_READ, SC_AC_OP_ERASE, SC_AC_OP_UPDATE,
778
0
    SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
779
0
    -1, SC_AC_OP_ERASE, -1};
780
781
0
  u8    bValue;
782
0
  int   i;
783
0
  int   iKeyRef = 0;
784
0
  int   iMethod;
785
0
  int   iPinCount;
786
0
  int   iOffset = 0;
787
0
  int   iOperation;
788
0
  const int*  p_idx;
789
790
  /* Check all sub-AC definitions within the total AC */
791
0
  while (len > 1 && (size_t)iOffset < len) { /* minimum length = 2 */
792
0
    size_t iACLen   = buf[iOffset] & 0x0F;
793
0
    if (iACLen >= len)
794
0
      break;
795
796
0
    iMethod = SC_AC_NONE;   /* default no authentication required */
797
798
0
    if (buf[iOffset] & 0X80) { /* AC in adaptive coding */
799
      /* Evaluates only the command-byte, not the optional P1/P2/Option bytes */
800
0
      size_t  iParmLen = 1;     /* command-byte is always present */
801
0
      size_t  iKeyLen  = 0;     /* Encryption key is optional */
802
803
0
      if (buf[iOffset]   & 0x20) iKeyLen++;
804
0
      if (buf[iOffset+1] & 0x40) iParmLen++;
805
0
      if (buf[iOffset+1] & 0x20) iParmLen++;
806
0
      if (buf[iOffset+1] & 0x10) iParmLen++;
807
0
      if (buf[iOffset+1] & 0x08) iParmLen++;
808
809
      /* Get KeyNumber if available */
810
0
      if(iKeyLen) {
811
0
        int iSC;
812
0
        if (len < 1 + iACLen)
813
0
          break;
814
0
        iSC = buf[iOffset+iACLen];
815
816
0
        switch( (iSC>>5) & 0x03 ){
817
0
        case 0:
818
0
          iMethod = SC_AC_TERM;   /* key authentication */
819
0
          break;
820
0
        case 1:
821
0
          iMethod = SC_AC_AUT;   /* key authentication  */
822
0
          break;
823
0
        case 2:
824
0
        case 3:
825
0
          iMethod = SC_AC_PRO;   /* secure messaging */
826
0
          break;
827
0
        }
828
0
        iKeyRef = iSC & 0x1F;     /* get key number */
829
0
      }
830
831
      /* Get PinNumber if available */
832
0
      if (iACLen > (1+iParmLen+iKeyLen)) {  /* check via total length if pin is present */
833
0
        if (len < 1+1+1+(size_t)iParmLen)
834
0
          break;
835
0
        iKeyRef = buf[iOffset+1+1+iParmLen];  /* PTL + AM-header + parameter-bytes */
836
0
        iMethod = SC_AC_CHV;
837
0
      }
838
839
      /* Convert SETCOS command to OpenSC command group */
840
0
      if (len < 1+2)
841
0
        break;
842
0
      switch(buf[iOffset+2]){
843
0
      case 0x2A:      /* crypto operation */
844
0
        iOperation = SC_AC_OP_CRYPTO;
845
0
        break;
846
0
      case 0x46:      /* key-generation operation */
847
0
        iOperation = SC_AC_OP_UPDATE;
848
0
        break;
849
0
      default:
850
0
        iOperation = SC_AC_OP_SELECT;
851
0
        break;
852
0
      }
853
0
      sc_file_add_acl_entry(file, iOperation, iMethod, iKeyRef);
854
0
    }
855
0
    else { /* AC in simple coding */
856
         /* Initial AC is treated as an operational AC */
857
858
      /* Get specific Cmd groups for specified file-type */
859
0
      switch (file->type) {
860
0
      case SC_FILE_TYPE_DF:            /* DF */
861
0
        p_idx = df_idx;
862
0
        break;
863
0
      case SC_FILE_TYPE_INTERNAL_EF:   /* EF for RSA keys */
864
0
        p_idx = efi_idx;
865
0
        break;
866
0
      default:                         /* EF */
867
0
        p_idx = ef_idx;
868
0
        break;
869
0
      }
870
871
      /* Encryption key present ? */
872
0
      iPinCount = iACLen > 0 ? (int)iACLen - 1 : 0;
873
874
0
      if (buf[iOffset] & 0x20) {
875
0
        int iSC;
876
0
        if (len < 1 + (size_t)iACLen)
877
0
          break;
878
0
        iSC = buf[iOffset + iACLen];
879
880
0
        switch( (iSC>>5) & 0x03 ) {
881
0
        case 0:
882
0
          iMethod = SC_AC_TERM;   /* key authentication */
883
0
          break;
884
0
        case 1:
885
0
          iMethod = SC_AC_AUT;   /* key authentication  */
886
0
          break;
887
0
        case 2:
888
0
        case 3:
889
0
          iMethod = SC_AC_PRO;   /* secure messaging */
890
0
          break;
891
0
        }
892
0
        iKeyRef = iSC & 0x1F;     /* get key number */
893
894
0
        iPinCount--;        /* one byte used for keyReference  */
895
0
      }
896
897
      /* Pin present ? */
898
0
      if ( iPinCount > 0 ) {
899
0
        if (len < 1 + 2)
900
0
          break;
901
0
        iKeyRef = buf[iOffset + 2]; /* pin ref */
902
0
        iMethod = SC_AC_CHV;
903
0
      }
904
905
      /* Add AC for each command-operationType into OpenSc structure */
906
0
      bValue = buf[iOffset + 1];
907
0
      for (i = 0; i < 8; i++) {
908
0
        if((bValue & 1) && (p_idx[i] >= 0))
909
0
          sc_file_add_acl_entry(file, p_idx[i], iMethod, iKeyRef);
910
0
        bValue >>= 1;
911
0
      }
912
0
    }
913
    /* Current field treated, get next AC sub-field */
914
0
    iOffset += iACLen +1;   /* AC + PTL-byte */
915
0
    len     -= iACLen +1;
916
0
  }
917
0
}
918
919
static int setcos_select_file(sc_card_t *card,
920
            const sc_path_t *in_path, sc_file_t **file)
921
0
{
922
0
  int r;
923
924
0
  r = iso_ops->select_file(card, in_path, file);
925
  /* Certain FINeID cards for organisations return 6A88 instead of 6A82 for missing files */
926
0
  if (card->flags & _FINEID_BROKEN_SELECT_FLAG && r == SC_ERROR_DATA_OBJECT_NOT_FOUND)
927
0
    return SC_ERROR_FILE_NOT_FOUND;
928
0
  if (r)
929
0
    return r;
930
0
  if (file != NULL) {
931
0
    if (card->type == SC_CARD_TYPE_SETCOS_44 ||
932
0
        card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
933
0
        SETCOS_IS_EID_APPLET(card))
934
0
      parse_sec_attr_44(*file, (*file)->sec_attr, (*file)->sec_attr_len);
935
0
    else
936
0
      parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
937
0
  }
938
0
  return 0;
939
0
}
940
941
static int setcos_list_files(sc_card_t *card, u8 * buf, size_t buflen)
942
0
{
943
0
  sc_apdu_t apdu;
944
0
  int r;
945
946
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
947
0
  if (card->type == SC_CARD_TYPE_SETCOS_44 ||
948
0
      card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
949
0
      SETCOS_IS_EID_APPLET(card))
950
0
    apdu.cla = 0x80;
951
0
  apdu.resp = buf;
952
0
  apdu.resplen = buflen;
953
0
  apdu.le = buflen > 256 ? 256 : buflen;
954
0
  r = sc_transmit_apdu(card, &apdu);
955
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
956
0
  if (card->type == SC_CARD_TYPE_SETCOS_44 && apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
957
0
    return 0; /* no files found */
958
0
  if (apdu.resplen == 0)
959
0
    return sc_check_sw(card, apdu.sw1, apdu.sw2);
960
0
  return (int)apdu.resplen;
961
0
}
962
963
static int setcos_process_fci(sc_card_t *card, sc_file_t *file,
964
           const u8 *buf, size_t buflen)
965
0
{
966
0
  int r = iso_ops->process_fci(card, file, buf, buflen);
967
968
  /* SetCOS 4.4: RSA key file is an internal EF but it's
969
   * file descriptor doesn't seem to follow ISO7816. */
970
0
  if (r >= 0 && (card->type == SC_CARD_TYPE_SETCOS_44 ||
971
0
                 SETCOS_IS_EID_APPLET(card))) {
972
0
    const u8 *tag;
973
0
    size_t taglen = 1;
974
0
    tag = (u8 *) sc_asn1_find_tag(card->ctx, buf, buflen, 0x82, &taglen);
975
0
    if (tag != NULL && taglen == 1 && *tag == 0x11)
976
0
      file->type = SC_FILE_TYPE_INTERNAL_EF;
977
0
  }
978
979
0
  return r;
980
0
}
981
982
/* Write internal data, e.g. add default pin-records to pin-file */
983
static int setcos_putdata(struct sc_card *card, struct sc_cardctl_setcos_data_obj* data_obj)
984
0
{
985
0
  int       r;
986
0
  struct sc_apdu      apdu;
987
988
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
989
990
0
  memset(&apdu, 0, sizeof(apdu));
991
0
  apdu.cse     = SC_APDU_CASE_3_SHORT;
992
0
  apdu.cla     = 0x00;
993
0
  apdu.ins     = 0xDA;
994
0
  apdu.p1      = data_obj->P1;
995
0
  apdu.p2      = data_obj->P2;
996
0
  apdu.lc      = data_obj->DataLen;
997
0
  apdu.datalen = data_obj->DataLen;
998
0
  apdu.data    = data_obj->Data;
999
1000
0
  r = sc_transmit_apdu(card, &apdu);
1001
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1002
1003
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1004
0
  LOG_TEST_RET(card->ctx, r, "PUT_DATA returned error");
1005
1006
0
  LOG_FUNC_RETURN(card->ctx, r);
1007
0
}
1008
1009
/* Read internal data, e.g. get RSA public key */
1010
static int setcos_getdata(struct sc_card *card, struct sc_cardctl_setcos_data_obj* data_obj)
1011
0
{
1012
0
  int       r;
1013
0
  struct sc_apdu      apdu;
1014
1015
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1016
1017
0
  memset(&apdu, 0, sizeof(apdu));
1018
0
  apdu.cse     = SC_APDU_CASE_2_SHORT;
1019
0
  apdu.cla     = 0x00;
1020
0
  apdu.ins     = 0xCA;      /* GET DATA */
1021
0
  apdu.p1      = data_obj->P1;
1022
0
  apdu.p2      = data_obj->P2;
1023
0
  apdu.lc      = 0;
1024
0
  apdu.datalen = 0;
1025
0
  apdu.data    = data_obj->Data;
1026
1027
0
  apdu.le      = 256;
1028
0
  apdu.resp    = data_obj->Data;
1029
0
  apdu.resplen = data_obj->DataLen;
1030
1031
0
  r = sc_transmit_apdu(card, &apdu);
1032
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1033
1034
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1035
0
  LOG_TEST_RET(card->ctx, r, "GET_DATA returned error");
1036
1037
0
  if (apdu.resplen > data_obj->DataLen)
1038
0
    r = SC_ERROR_WRONG_LENGTH;
1039
0
  else
1040
0
    data_obj->DataLen = apdu.resplen;
1041
1042
0
  LOG_FUNC_RETURN(card->ctx, r);
1043
0
}
1044
1045
/* Generate or store a key */
1046
static int setcos_generate_store_key(sc_card_t *card,
1047
  struct sc_cardctl_setcos_gen_store_key_info *data)
1048
0
{
1049
0
  struct  sc_apdu apdu;
1050
0
  u8  sbuf[SC_MAX_APDU_BUFFER_SIZE];
1051
0
  int r, len;
1052
1053
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1054
1055
  /* Setup key-generation parameters */
1056
0
  len = 0;
1057
0
  if (data->op_type == OP_TYPE_GENERATE)
1058
0
    sbuf[len++] = 0x92; /* algo ID: RSA CRT */
1059
0
  else
1060
0
    sbuf[len++] = 0x9A; /* algo ID: EXTERNALLY GENERATED RSA CRT */
1061
0
  sbuf[len++] = 0x00;
1062
0
  sbuf[len++] = data->mod_len / 256;  /* 2 bytes for modulus bitlength */
1063
0
  sbuf[len++] = data->mod_len % 256;
1064
1065
0
  sbuf[len++] = data->pubexp_len / 256;   /* 2 bytes for pubexp bitlength */
1066
0
  sbuf[len++] = data->pubexp_len % 256;
1067
0
  memcpy(sbuf + len, data->pubexp, BYTES4BITS(data->pubexp_len));
1068
0
  len += BYTES4BITS(data->pubexp_len);
1069
1070
0
  if (data->op_type == OP_TYPE_STORE) {
1071
0
    sbuf[len++] = data->primep_len / 256;
1072
0
    sbuf[len++] = data->primep_len % 256;
1073
0
    memcpy(sbuf + len, data->primep, BYTES4BITS(data->primep_len));
1074
0
    len += BYTES4BITS(data->primep_len);
1075
0
    sbuf[len++] = data->primeq_len / 256;
1076
0
    sbuf[len++] = data->primeq_len % 256;
1077
0
    memcpy(sbuf + len, data->primeq, BYTES4BITS(data->primeq_len));
1078
0
    len += BYTES4BITS(data->primeq_len);
1079
0
  }
1080
1081
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00);
1082
0
  apdu.cla = 0x00;
1083
0
  apdu.data = sbuf;
1084
0
  apdu.datalen = len;
1085
0
  apdu.lc = len;
1086
1087
0
  r = sc_transmit_apdu(card, &apdu);
1088
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1089
1090
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1091
0
  LOG_TEST_RET(card->ctx, r, "STORE/GENERATE_KEY returned error");
1092
1093
0
  LOG_FUNC_RETURN(card->ctx, r);
1094
0
}
1095
1096
static int setcos_activate_file(sc_card_t *card)
1097
0
{
1098
0
  int r;
1099
0
  u8 sbuf[2];
1100
0
  sc_apdu_t apdu;
1101
1102
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x44, 0x00, 0x00);
1103
0
  apdu.data = sbuf;
1104
1105
0
  r = sc_transmit_apdu(card, &apdu);
1106
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1107
1108
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1109
0
  LOG_TEST_RET(card->ctx, r, "ACTIVATE_FILE returned error");
1110
1111
0
  LOG_FUNC_RETURN(card->ctx, r);
1112
0
}
1113
1114
static int setcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
1115
0
{
1116
0
  if (card->type != SC_CARD_TYPE_SETCOS_44 && !SETCOS_IS_EID_APPLET(card))
1117
0
    return SC_ERROR_NOT_SUPPORTED;
1118
1119
0
  switch(cmd) {
1120
0
  case SC_CARDCTL_SETCOS_PUTDATA:
1121
0
    return setcos_putdata(card,
1122
0
        (struct sc_cardctl_setcos_data_obj*) ptr);
1123
0
    break;
1124
0
  case SC_CARDCTL_SETCOS_GETDATA:
1125
0
    return setcos_getdata(card,
1126
0
        (struct sc_cardctl_setcos_data_obj*) ptr);
1127
0
    break;
1128
0
  case SC_CARDCTL_SETCOS_GENERATE_STORE_KEY:
1129
0
    return setcos_generate_store_key(card,
1130
0
        (struct sc_cardctl_setcos_gen_store_key_info *) ptr);
1131
0
  case SC_CARDCTL_SETCOS_ACTIVATE_FILE:
1132
0
    return setcos_activate_file(card);
1133
0
  }
1134
1135
0
  return SC_ERROR_NOT_SUPPORTED;
1136
0
}
1137
1138
static struct sc_card_driver *sc_get_driver(void)
1139
3.19k
{
1140
3.19k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
1141
1142
3.19k
  setcos_ops = *iso_drv->ops;
1143
3.19k
  setcos_ops.match_card = setcos_match_card;
1144
3.19k
  setcos_ops.init = setcos_init;
1145
3.19k
  if (iso_ops == NULL)
1146
1
    iso_ops = iso_drv->ops;
1147
3.19k
  setcos_ops.create_file = setcos_create_file;
1148
3.19k
  setcos_ops.set_security_env = setcos_set_security_env;
1149
3.19k
  setcos_ops.select_file = setcos_select_file;
1150
3.19k
  setcos_ops.list_files = setcos_list_files;
1151
3.19k
  setcos_ops.process_fci = setcos_process_fci;
1152
3.19k
  setcos_ops.construct_fci = setcos_construct_fci;
1153
3.19k
  setcos_ops.card_ctl = setcos_card_ctl;
1154
1155
3.19k
  return &setcos_drv;
1156
3.19k
}
1157
1158
struct sc_card_driver *sc_get_setcos_driver(void)
1159
3.19k
{
1160
3.19k
  return sc_get_driver();
1161
3.19k
}