Coverage Report

Created: 2026-08-31 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-starcos.c
Line
Count
Source
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include "asn1.h"
30
#include "cardctl.h"
31
#include "internal.h"
32
#include "iso7816.h"
33
34
// clang-format off
35
static const struct sc_atr_table starcos_atrs[] = {
36
  { "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 },
37
  { "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 },
38
  { "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 },
39
  { "3b:d8:18:ff:81:b1:fe:45:1f:03:80:64:04:1a:b4:03:81:05:61", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
40
  { "3b:d3:96:ff:81:b1:fe:45:1f:07:80:81:05:2d", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
41
  { "3B:9B:96:C0:0A:31:FE:45:80:67:04:1E:B5:01:00:89:4C:81:05:45", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
42
  { "3B:DB:96:FF:81:31:FE:45:80:67:05:34:B5:02:01:C0:A1:81:05:3C", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
43
  { "3B:D9:96:FF:81:31:FE:45:80:31:B8:73:86:01:C0:81:05:02", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
44
  { "3B:DF:96:FF:81:31:FE:45:80:5B:44:45:2E:42:4E:4F:54:4B:31:31:31:81:05:A0", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
45
  { "3B:DF:96:FF:81:31:FE:45:80:5B:44:45:2E:42:4E:4F:54:4B:31:30:30:81:05:A0", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
46
  { "3B:D9:96:FF:81:31:FE:45:80:31:B8:73:86:01:E0:81:05:22", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
47
  { "3B:D0:97:FF:81:B1:FE:45:1F:07:2B", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
48
  { "3B:D0:96:FF:81:B1:FE:45:1F:07:2A", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
49
  { "3b:df:96:ff:81:31:fe:45:80:5b:44:45:2e:42:41:5f:53:43:33:35:32:81:05:b5", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5_ESIGN, 0, NULL },
50
  { NULL, NULL, NULL, 0, 0, NULL }
51
};
52
// clang-format on
53
54
static struct sc_card_operations starcos_ops;
55
static struct sc_card_operations *iso_ops = NULL;
56
57
static struct sc_card_driver starcos_drv = {
58
  "STARCOS",
59
  "starcos",
60
  &starcos_ops,
61
  NULL, 0, NULL
62
};
63
64
static const struct sc_card_error starcos_errors[] =
65
{
66
  { 0x6600, SC_ERROR_INCORRECT_PARAMETERS, "Error setting the security env"},
67
  { 0x66F0, SC_ERROR_INCORRECT_PARAMETERS, "No space left for padding"},
68
  { 0x69F0, SC_ERROR_NOT_ALLOWED,          "Command not allowed"},
69
  { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS,  "Files exists"},
70
  { 0x6A8A, SC_ERROR_FILE_ALREADY_EXISTS,  "Application exists"},
71
  { 0x6F01, SC_ERROR_CARD_CMD_FAILED, "public key not complete"},
72
  { 0x6F02, SC_ERROR_CARD_CMD_FAILED, "data overflow"},
73
  { 0x6F03, SC_ERROR_CARD_CMD_FAILED, "invalid command sequence"},
74
  { 0x6F05, SC_ERROR_CARD_CMD_FAILED, "security environment invalid"},
75
  { 0x6F07, SC_ERROR_FILE_NOT_FOUND, "key part not found"},
76
  { 0x6F08, SC_ERROR_CARD_CMD_FAILED, "signature failed"},
77
  { 0x6F0A, SC_ERROR_INCORRECT_PARAMETERS, "key format does not match key length"},
78
  { 0x6F0B, SC_ERROR_INCORRECT_PARAMETERS, "length of key component inconsistent with algorithm"},
79
  { 0x6F81, SC_ERROR_CARD_CMD_FAILED, "system error"}
80
};
81
82
/* internal structure to save the current security environment */
83
typedef struct starcos_ex_data_st {
84
  int    sec_ops; /* the currently selected security operation,
85
       * i.e. SC_SEC_OPERATION_AUTHENTICATE etc. */
86
  unsigned long    fix_digestInfo;
87
  unsigned int    pin_encoding;
88
} starcos_ex_data;
89
90
/*
91
   This constant allows signing or
92
   decrypting with RSA keys up to 4096 bits.
93
*/
94
#define STARCOS3X_PROBE_APDU_LENGTH 512
95
96
2.62k
#define PIN_ENCODING_DETERMINE  0
97
#define PIN_ENCODING_DEFAULT  SC_PIN_ENCODING_GLP
98
99
// known pin formats for StarCOS 3.x cards
100
1
#define PIN_FORMAT_F1     0x11
101
1.74k
#define PIN_FORMAT_F2     0x12
102
#define PIN_FORMAT_RSA      0x1230
103
1
#define PIN_FORMAT_BCD      0x13
104
2
#define PIN_FORMAT_ASCII    0x14
105
1
#define PIN_FORMAT_PW_ASCII   0x21
106
// default is the Format 2 PIN Block which is GLP in OpenSC
107
875
#define PIN_FORMAT_DEFAULT    PIN_FORMAT_F2
108
109
#define CHECK_NOT_SUPPORTED_V3_4(card) \
110
12
  do { \
111
12
    if ((card)->type == SC_CARD_TYPE_STARCOS_V3_4) { \
112
0
      sc_log((card)->ctx,  \
113
0
        "not supported for STARCOS 3.4 cards"); \
114
0
      return SC_ERROR_NOT_SUPPORTED; \
115
0
    } \
116
12
  } while (0);
117
118
/* card type helpers */
119
23.2k
#define IS_V34(card) card->type == SC_CARD_TYPE_STARCOS_V3_4 || card->type == SC_CARD_TYPE_STARCOS_V3_4_ESIGN
120
12.1k
#define IS_V35(card) card->type == SC_CARD_TYPE_STARCOS_V3_5 || card->type == SC_CARD_TYPE_STARCOS_V3_5_ESIGN
121
36.6k
#define IS_V3x(card) IS_V34(card) || IS_V35(card)
122
123
/* the starcos part */
124
static int starcos_match_card(sc_card_t *card)
125
13.9k
{
126
13.9k
  int i;
127
128
13.9k
  i = _sc_match_atr(card, starcos_atrs, &card->type);
129
13.9k
  if (i < 0)
130
13.1k
    return 0;
131
875
  return 1;
132
13.9k
}
133
134
135
typedef struct starcos_ctrl_ref_template_st {
136
  unsigned int  transmission_format;
137
#if 0
138
  // not relevant values for now
139
  unsigned int  se_reference;
140
  unsigned int  ssec_initial_value;
141
#endif
142
} starcos_ctrl_ref_template;
143
144
// tags
145
1.89k
#define TAG_STARCOS35_PIN_REFERENCE         0x88
146
125
#define TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag    0x7B
147
9
#define TAG_STARCOS3X_CTRL_REF_TEMPLATE       0xA4
148
9
#define TAG_STARCOS3X_TRANSMISSION_FORMAT     0x89
149
150
static const char * starcos_ef_pwdd = "3F000015";
151
static const char * starcos_ef_keyd = "3F000013";
152
153
/**
154
 * Parses supported security mechanisms record data.
155
 * It returns SC_SUCCESS and the ctrl_ref_template structure data on success
156
 */
157
static int starcos_parse_supported_sec_mechanisms(struct sc_card *card, const unsigned char * buf, size_t buflen, starcos_ctrl_ref_template * ctrl_ref_template)
158
125
{
159
125
  struct sc_context *ctx = card->ctx;
160
125
  const unsigned char *supported_sec_mechanisms_tag = NULL;
161
125
  size_t taglen;
162
163
125
  LOG_FUNC_CALLED(ctx);
164
165
125
  supported_sec_mechanisms_tag = sc_asn1_find_tag(ctx, buf, buflen, TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag, &taglen);
166
125
  if (supported_sec_mechanisms_tag != NULL && taglen >= 1)   {
167
9
    const unsigned char *tx_fmt_tag = NULL;
168
9
    const unsigned char *ctrl_ref_template_tag = NULL;
169
9
    size_t supported_sec_mechanisms_taglen = taglen;
170
171
    // control-reference template is either included in the supported security mechanisms tag or it can be the CRT tag itself (EF.PWDD)
172
9
    ctrl_ref_template_tag = sc_asn1_find_tag(ctx, supported_sec_mechanisms_tag, taglen, TAG_STARCOS3X_CTRL_REF_TEMPLATE, &taglen);
173
9
    if ( ctrl_ref_template_tag == NULL || taglen == 0 ) {
174
8
      ctrl_ref_template_tag = supported_sec_mechanisms_tag;
175
8
      taglen = supported_sec_mechanisms_taglen;
176
8
    }
177
178
9
    tx_fmt_tag = sc_asn1_find_tag(ctx, ctrl_ref_template_tag, taglen, TAG_STARCOS3X_TRANSMISSION_FORMAT, &taglen);
179
9
    if ( tx_fmt_tag != NULL && taglen >= 1 ) {
180
5
      ctrl_ref_template->transmission_format = *(tx_fmt_tag + 0);
181
5
      LOG_FUNC_RETURN(ctx, SC_SUCCESS);
182
5
    }
183
9
  }
184
185
120
  LOG_FUNC_RETURN(ctx, SC_ERROR_TEMPLATE_NOT_FOUND);
186
120
}
187
188
static int starcos_determine_pin_format34(sc_card_t *card, unsigned int * pin_format)
189
460
{
190
460
  struct sc_context *ctx = card->ctx;
191
460
  struct sc_path path;
192
460
  struct sc_file *file;
193
460
  unsigned char buf[256];
194
460
  int rv;
195
460
  int retval = SC_SUCCESS;
196
460
  int rec_no=1;
197
198
460
  LOG_FUNC_CALLED(ctx);
199
200
460
  sc_format_path(starcos_ef_pwdd, &path);
201
460
  rv = sc_select_file(card, &path, &file);
202
460
  LOG_TEST_RET(ctx, rv, "Cannot select EF.PWDD file");
203
204
59
  if ( (rv = sc_read_record(card, rec_no, 0, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
205
21
    starcos_ctrl_ref_template ctrl_ref_template;
206
21
    memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
207
21
    rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
208
21
    if ( rv == SC_SUCCESS ) {
209
5
      *pin_format = ctrl_ref_template.transmission_format;
210
5
      sc_log(ctx, "Determined StarCOS 3.4 PIN format: 0x%x", *pin_format);
211
16
    } else {
212
16
      sc_log(ctx, "Failed to parse record %d of EF.PWD, err=%d", rec_no, rv);
213
16
      retval = rv;
214
16
    }
215
38
  } else {
216
38
    sc_log(ctx, "Failed to read record %d of EF.PWDD, err=%d", rec_no, rv);
217
38
    retval = rv;
218
38
  }
219
220
59
  sc_file_free(file);
221
59
  LOG_FUNC_RETURN(ctx, retval);
222
59
}
223
224
static int starcos_determine_pin_format35(sc_card_t *card, unsigned int * pin_format)
225
86
{
226
86
  struct sc_context *ctx = card->ctx;
227
86
  struct sc_path path;
228
86
  struct sc_file *file;
229
86
  unsigned char buf[256];
230
86
  int rv;
231
86
  int retval = SC_ERROR_RECORD_NOT_FOUND;
232
86
  int rec_no=1;
233
86
  starcos_ctrl_ref_template ctrl_ref_template;
234
235
86
  LOG_FUNC_CALLED(ctx);
236
237
86
  sc_format_path(starcos_ef_keyd, &path);
238
86
  rv = sc_select_file(card, &path, &file);
239
86
  LOG_TEST_RET(ctx, rv, "Cannot select EF.KEYD file");
240
241
1.95k
  while ( (rv = sc_read_record(card, rec_no++, 0, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
242
1.89k
    if ( buf[0] != TAG_STARCOS35_PIN_REFERENCE ) continue;
243
244
104
    memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
245
104
    rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
246
104
    if ( rv == SC_SUCCESS ) {
247
0
      *pin_format = ctrl_ref_template.transmission_format;
248
0
      sc_log(ctx, "Determined StarCOS 3.5 PIN format: 0x%x", *pin_format);
249
0
      retval = rv;
250
      // assuming that all PINs and PUKs have the same transmission format
251
0
      break;
252
104
    } else {
253
104
      sc_log(ctx, "Failed to parse record %d of EF.KEYD, err=%d", rec_no-1, rv);
254
104
      retval = rv;
255
104
    }
256
104
  }
257
258
59
  sc_file_free(file);
259
59
  LOG_FUNC_RETURN(ctx, retval);
260
59
}
261
262
/**
263
 * Determine v3.x PIN encoding by parsing either
264
 * EF.PWDD (for v3.4) or EF.KEYD (for v3.5)
265
 *
266
 * It returns an OpenSC PIN encoding, using the default value on failure
267
 */
268
static unsigned int starcos_determine_pin_encoding(sc_card_t *card)
269
875
{
270
875
  unsigned int pin_format = PIN_FORMAT_DEFAULT;
271
875
  unsigned int encoding = PIN_ENCODING_DETERMINE;
272
273
875
  if ( IS_V34(card) ) {
274
460
    starcos_determine_pin_format34(card, &pin_format);
275
460
  } else if ( IS_V35(card) ) {
276
86
    starcos_determine_pin_format35(card, &pin_format);
277
86
  }
278
279
875
  switch (pin_format) {
280
1
  case PIN_FORMAT_PW_ASCII:
281
2
  case PIN_FORMAT_ASCII:
282
2
    encoding = SC_PIN_ENCODING_ASCII;
283
2
    break;
284
1
  case PIN_FORMAT_BCD:
285
1
    encoding = SC_PIN_ENCODING_BCD;
286
1
    break;
287
1
  case PIN_FORMAT_F1:
288
871
  case PIN_FORMAT_F2:
289
871
    encoding = SC_PIN_ENCODING_GLP;
290
871
    break;
291
875
  }
292
293
875
  sc_log(card->ctx, "Determined PIN encoding: %d", encoding);
294
875
  return encoding;
295
875
}
296
297
/**
298
 * Returns 1 if an extended APDU can be sent to the card
299
 * with the given card reader. Otherwise returns 0.
300
 */
301
24
static int starcos_probe_reader_for_ext_apdu(sc_card_t * card) {
302
24
  sc_apdu_t apdu;
303
24
  int rv;
304
  /* try to read STARCOS3X_PROBE_APDU_LENGTH bytes */
305
24
  u8 data[STARCOS3X_PROBE_APDU_LENGTH];
306
307
  /* Get Data: Get Chip Serial Number */
308
24
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, 0xCA, 0x9F, 0x6C);
309
24
  apdu.cla = 0xA0;
310
24
  apdu.resp = data;
311
24
  apdu.resplen = sizeof(data);
312
24
  apdu.le = apdu.resplen;
313
24
  rv = sc_transmit_apdu(card, &apdu);
314
24
  LOG_TEST_RET(card->ctx, rv, "Failed to send Get Data ext. APDU");
315
23
  return (apdu.sw1 == 0x90 && apdu.sw2 == 0x00);
316
24
}
317
318
523
static int starcos_select_mf(sc_card_t * card) {
319
523
  sc_apdu_t apdu;
320
523
  const u8 mf_buf[2] = {0x3f, 0x00};
321
322
523
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
323
523
  apdu.le = 0;
324
523
  apdu.lc = 2;
325
523
  apdu.data    = mf_buf;
326
523
  apdu.datalen = 2;
327
523
  apdu.resplen = 0;
328
329
523
  return sc_transmit_apdu(card, &apdu);
330
523
}
331
332
static int starcos_select_aid(sc_card_t *card,
333
            const u8 aid[16], size_t len,
334
            sc_file_t **file_out);
335
336
/* returns 1 if the card has the eSign app with AID A0:00:00:02:45:53:69:67:6E
337
   otherwise returns 0
338
 */
339
460
static int starcos_has_esign_app(sc_card_t * card) {
340
460
  static const char * starcos_esign_aid = "A0:00:00:02:45:53:69:67:6E";
341
460
  int rv;
342
343
460
  rv = starcos_select_mf(card);
344
460
  if ( rv == SC_SUCCESS ) {
345
449
    u8 aid[SC_MAX_PATH_SIZE];
346
449
    size_t len = sizeof(aid);
347
348
449
    rv = sc_hex_to_bin(starcos_esign_aid, aid, &len);
349
449
    LOG_TEST_RET(card->ctx, rv, "Failed to convert eSing AID");
350
449
    rv = starcos_select_aid(card, aid, len, NULL);
351
449
    if ( rv == SC_SUCCESS ) {
352
63
      starcos_select_mf(card);
353
63
    }
354
449
  }
355
460
  return ( rv == SC_SUCCESS );
356
460
}
357
358
static int starcos_init(sc_card_t *card)
359
875
{
360
875
  unsigned int flags;
361
875
  starcos_ex_data *ex_data;
362
363
875
  ex_data = calloc(1, sizeof(starcos_ex_data));
364
875
  if (ex_data == NULL)
365
0
    return SC_ERROR_OUT_OF_MEMORY;
366
367
875
  card->name = "STARCOS";
368
875
  card->cla  = 0x00;
369
875
  card->drv_data = (void *)ex_data;
370
875
  ex_data->pin_encoding = PIN_ENCODING_DETERMINE;
371
372
875
  flags = SC_ALGORITHM_RSA_PAD_PKCS1
373
875
    | SC_ALGORITHM_ONBOARD_KEY_GEN
374
875
    | SC_ALGORITHM_RSA_PAD_ISO9796
375
875
    | SC_ALGORITHM_RSA_HASH_NONE
376
875
    | SC_ALGORITHM_RSA_HASH_SHA1
377
875
    | SC_ALGORITHM_RSA_HASH_MD5
378
875
    | SC_ALGORITHM_RSA_HASH_RIPEMD160
379
875
    | SC_ALGORITHM_RSA_HASH_MD5_SHA1;
380
381
875
  card->caps = SC_CARD_CAP_RNG;
382
383
875
  if ( IS_V3x(card) ) {
384
385
546
    flags |= SC_CARD_FLAG_RNG
386
546
      | SC_ALGORITHM_RSA_HASH_SHA224
387
546
      | SC_ALGORITHM_RSA_HASH_SHA256
388
546
      | SC_ALGORITHM_RSA_HASH_SHA384
389
546
      | SC_ALGORITHM_RSA_HASH_SHA512
390
546
      | SC_ALGORITHM_RSA_PAD_PSS;
391
392
546
    _sc_card_add_rsa_alg(card, 512, flags, 0x10001);
393
546
    _sc_card_add_rsa_alg(card, 768, flags, 0x10001);
394
546
    _sc_card_add_rsa_alg(card,1024, flags, 0x10001);
395
546
    _sc_card_add_rsa_alg(card,1728, flags, 0x10001);
396
546
    _sc_card_add_rsa_alg(card,1976, flags, 0x10001);
397
546
    _sc_card_add_rsa_alg(card,2048, flags, 0x10001);
398
546
    if ( IS_V34(card) ) {
399
460
      card->name = "STARCOS 3.4";
400
460
      card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
401
460
    } else {
402
86
      card->name = "STARCOS 3.5";
403
86
      _sc_card_add_rsa_alg(card,3072, flags, 0x10001);
404
86
    }
405
546
    card->max_send_size = 255;
406
546
    card->max_recv_size = 256;
407
546
  } else {
408
329
    _sc_card_add_rsa_alg(card, 512, flags, 0x10001);
409
329
    _sc_card_add_rsa_alg(card, 768, flags, 0x10001);
410
329
    _sc_card_add_rsa_alg(card,1024, flags, 0x10001);
411
412
    /* we need read_binary&friends with max 128 bytes per read */
413
329
    card->max_send_size = 128;
414
329
    card->max_recv_size = 128;
415
329
  }
416
417
875
  if (sc_parse_ef_atr(card) == SC_SUCCESS) {
418
72
    size_t max_recv_size = 0;
419
72
    size_t max_send_size = 0;
420
421
    /* Add max. length values from IAS/ECC specific issuer data */
422
72
    if ( card->ef_atr->issuer_data_len >= 4 ) {
423
20
      max_recv_size = bebytes2ushort(card->ef_atr->issuer_data);
424
20
      max_send_size = bebytes2ushort(card->ef_atr->issuer_data + 2);
425
20
    }
426
    /* which could be overridden with ISO7816 EF.ATR options, if present */
427
72
    if (card->ef_atr->max_response_apdu > 0) {
428
17
      max_recv_size = card->ef_atr->max_response_apdu;
429
17
    }
430
72
    if (card->ef_atr->max_command_apdu > 0) {
431
19
      max_send_size = card->ef_atr->max_command_apdu;
432
19
    }
433
434
72
    if ( max_send_size > 256 && max_recv_size > 256 ) {
435
24
      size_t max_recv_size_prev = card->max_recv_size;
436
24
      size_t max_send_size_prev = card->max_send_size;
437
      /* allow SC_CARD_CAP_APDU_EXT independent of ef_atr->caps, see IAS/ECC issuer data above */
438
24
      card->caps |= SC_CARD_CAP_APDU_EXT;
439
      /* the received data should not exceed max_recv_size including the sw1/sw2 */
440
24
      card->max_recv_size = max_recv_size - 2;
441
      /* the sent APDU should not exceed max_send_size including the 4 bytes of the APDU and 2 * 3 bytes Lc/Le */
442
24
      card->max_send_size = max_send_size - 10;
443
      /* probe reader for extended APDU support */
444
24
      if ( starcos_probe_reader_for_ext_apdu(card) ) {
445
1
        sc_log(card->ctx, "Successfully probed extended APDU, enabling extended APDU with max send/recv %d/%d",
446
1
          (int)card->max_send_size, (int)card->max_recv_size);
447
23
      } else {
448
23
        card->caps &= ~(SC_CARD_CAP_APDU_EXT);
449
23
        card->max_recv_size = max_recv_size_prev;
450
23
        card->max_send_size = max_send_size_prev;
451
23
        sc_log(card->ctx, "Ext APDU probing failed, the actual reader does not support ext APDU");
452
23
      }
453
24
    }
454
72
  }
455
456
875
  if ( ex_data->pin_encoding == PIN_ENCODING_DETERMINE ) {
457
    // about to determine PIN encoding
458
875
    ex_data->pin_encoding = starcos_determine_pin_encoding(card);
459
875
  }
460
461
875
  if ( card->type == SC_CARD_TYPE_STARCOS_V3_4 && starcos_has_esign_app(card) ) {
462
63
    card->type = SC_CARD_TYPE_STARCOS_V3_4_ESIGN;
463
63
    sc_log(card->ctx, "Card has eSign app, card type changed to %d", card->type);
464
63
  }
465
466
875
  return 0;
467
875
}
468
469
static int starcos_finish(sc_card_t *card)
470
875
{
471
875
  if (card->drv_data)
472
875
    free((starcos_ex_data *)card->drv_data);
473
875
  return 0;
474
875
}
475
476
static int process_fci(sc_context_t *ctx, sc_file_t *file,
477
           const u8 *buf, size_t buflen)
478
379
{
479
  /* NOTE: According to the Starcos S 2.1 manual it's possible
480
   *       that a SELECT DF returns as a FCI arbitrary data which
481
   *       is stored in a object file (in the corresponding DF)
482
   *       with the tag 0x6f.
483
   */
484
485
379
  size_t taglen, len = buflen;
486
379
  const u8 *tag = NULL, *p;
487
488
379
  sc_log(ctx,  "processing FCI bytes\n");
489
490
379
  if (buflen < 2)
491
59
    return SC_ERROR_INTERNAL;
492
320
  if (buf[0] != 0x6f)
493
38
    return SC_ERROR_INVALID_DATA;
494
282
  len = (size_t)buf[1];
495
282
  if (buflen - 2 < len)
496
37
    return SC_ERROR_INVALID_DATA;
497
245
  p = buf + 2;
498
499
  /* defaults */
500
245
  file->type = SC_FILE_TYPE_WORKING_EF;
501
245
  file->ef_structure = SC_FILE_EF_UNKNOWN;
502
245
  file->shareable = 0;
503
245
  file->record_length = 0;
504
245
  file->size = 0;
505
506
245
  tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
507
245
  if (tag != NULL && taglen >= 2) {
508
20
    int bytes = (tag[0] << 8) + tag[1];
509
20
    sc_log(ctx,
510
20
      "  bytes in file: %d\n", bytes);
511
20
    file->size = bytes;
512
20
  }
513
514
245
  tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
515
245
  if (tag != NULL) {
516
63
    const char *type = "unknown";
517
63
    const char *structure = "unknown";
518
519
63
    if (taglen == 1 && tag[0] == 0x01) {
520
      /* transparent EF */
521
12
      type = "working EF";
522
12
      structure = "transparent";
523
12
      file->type = SC_FILE_TYPE_WORKING_EF;
524
12
      file->ef_structure = SC_FILE_EF_TRANSPARENT;
525
51
    } else if (taglen == 1 && tag[0] == 0x11) {
526
      /* object EF */
527
3
      type = "working EF";
528
3
      structure = "object";
529
3
      file->type = SC_FILE_TYPE_WORKING_EF;
530
3
      file->ef_structure = SC_FILE_EF_TRANSPARENT; /* TODO */
531
48
    } else if (taglen == 3 && tag[1] == 0x21) {
532
21
      type = "working EF";
533
21
      file->record_length = tag[2];
534
21
      file->type = SC_FILE_TYPE_WORKING_EF;
535
      /* linear fixed, cyclic or compute */
536
21
      switch ( tag[0] )
537
21
      {
538
1
        case 0x02:
539
1
          structure = "linear fixed";
540
1
          file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
541
1
          break;
542
6
        case 0x07:
543
6
          structure = "cyclic";
544
6
          file->ef_structure = SC_FILE_EF_CYCLIC;
545
6
          break;
546
8
        case 0x17:
547
8
          structure = "compute";
548
8
          file->ef_structure = SC_FILE_EF_UNKNOWN;
549
8
          break;
550
6
        default:
551
6
          structure = "unknown";
552
6
          file->ef_structure = SC_FILE_EF_UNKNOWN;
553
6
          file->record_length = 0;
554
6
          break;
555
21
      }
556
21
    }
557
558
63
    sc_log(ctx,
559
63
      "  type: %s\n", type);
560
63
    sc_log(ctx,
561
63
      "  EF structure: %s\n", structure);
562
63
  }
563
245
  file->magic = SC_FILE_MAGIC;
564
565
245
  return SC_SUCCESS;
566
245
}
567
568
static int process_fci_v3_4(sc_context_t *ctx, sc_file_t *file,
569
           const u8 *buf, size_t buflen)
570
0
{
571
0
  size_t taglen, len = buflen;
572
0
  const u8 *tag = NULL, *p;
573
574
0
  sc_log(ctx, "processing %zu FCI bytes\n", buflen);
575
576
0
  if (buflen < 2)
577
0
    return SC_ERROR_INTERNAL;
578
0
  if (buf[0] != 0x6f)
579
0
    return SC_ERROR_INVALID_DATA;
580
0
  len = (size_t)buf[1];
581
0
  if (buflen - 2 < len)
582
0
    return SC_ERROR_INVALID_DATA;
583
584
  /* defaults */
585
0
  file->type = SC_FILE_TYPE_WORKING_EF;
586
0
  if (len == 0) {
587
0
    SC_FUNC_RETURN(ctx, 2, SC_SUCCESS);
588
0
  }
589
590
0
  p = buf + 2;
591
0
  file->ef_structure = SC_FILE_TYPE_DF;
592
0
  file->shareable = 1;
593
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
594
0
  if (tag != NULL && taglen > 0 && taglen <= 16) {
595
0
    memcpy(file->name, tag, taglen);
596
0
    file->namelen = taglen;
597
0
    sc_log(ctx,  "filename %s",
598
0
      sc_dump_hex(file->name, file->namelen));
599
0
  }
600
0
  return SC_SUCCESS;
601
0
}
602
603
static int process_fcp_v3_4(sc_context_t *ctx, sc_file_t *file,
604
           const u8 *buf, size_t buflen)
605
409
{
606
409
  size_t taglen, len = buflen;
607
409
  const u8 *tag = NULL, *p;
608
609
409
  sc_log(ctx, "processing %zu FCP bytes\n", buflen);
610
611
409
  if (buflen < 2)
612
76
    return SC_ERROR_INTERNAL;
613
333
  if (buf[0] != 0x62)
614
20
    return SC_ERROR_INVALID_DATA;
615
313
  len = (size_t)buf[1];
616
313
  if (buflen - 2 < len)
617
13
    return SC_ERROR_INVALID_DATA;
618
300
  p = buf + 2;
619
620
300
  tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
621
300
  if (tag != NULL && taglen >= 2) {
622
15
    int bytes = (tag[0] << 8) + tag[1];
623
15
    sc_log(ctx,
624
15
      "  bytes in file: %d\n", bytes);
625
15
    file->size = bytes;
626
15
  }
627
628
300
  tag = sc_asn1_find_tag(ctx, p, len, 0xc5, &taglen);
629
300
  if (tag != NULL && taglen >= 2) {
630
11
    int bytes = (tag[0] << 8) + tag[1];
631
11
    sc_log(ctx,
632
11
      "  bytes in file 2: %d\n", bytes);
633
11
    file->size = bytes;
634
11
  }
635
636
300
  tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
637
300
  if (tag != NULL) {
638
110
    const char *type = "unknown";
639
110
    const char *structure = "unknown";
640
641
110
    if (taglen >= 1) {
642
75
      unsigned char byte = tag[0];
643
75
      if (byte & 0x40) {
644
35
        file->shareable = 1;
645
35
      }
646
75
      if (byte == 0x38) {
647
10
        type = "DF";
648
10
        file->type = SC_FILE_TYPE_DF;
649
10
        file->shareable = 1;
650
10
      }
651
75
      switch (byte & 7) {
652
12
      case 1:
653
        /* transparent EF */
654
12
        type = "working EF";
655
12
        structure = "transparent";
656
12
        file->type = SC_FILE_TYPE_WORKING_EF;
657
12
        file->ef_structure = SC_FILE_EF_TRANSPARENT;
658
12
        break;
659
10
      case 2:
660
        /* linear fixed EF */
661
10
        type = "working EF";
662
10
        structure = "linear fixed";
663
10
        file->type = SC_FILE_TYPE_WORKING_EF;
664
10
        file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
665
10
        break;
666
12
      case 4:
667
        /* linear variable EF */
668
12
        type = "working EF";
669
12
        structure = "linear variable";
670
12
        file->type = SC_FILE_TYPE_WORKING_EF;
671
12
        file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
672
12
        break;
673
16
      case 6:
674
        /* cyclic EF */
675
16
        type = "working EF";
676
16
        structure = "cyclic";
677
16
        file->type = SC_FILE_TYPE_WORKING_EF;
678
16
        file->ef_structure = SC_FILE_EF_CYCLIC;
679
16
        break;
680
25
      default:
681
        /* use defaults from above */
682
25
        break;
683
75
      }
684
75
    }
685
110
    sc_log(ctx,
686
110
      "  type: %s\n", type);
687
110
    sc_log(ctx,
688
110
      "  EF structure: %s\n", structure);
689
110
    if (taglen >= 2) {
690
66
      if (tag[1] != 0x41 || taglen != 5) {
691
66
        SC_FUNC_RETURN(ctx, 2,SC_ERROR_INVALID_DATA);
692
66
      }
693
      /* formatted EF */
694
0
      file->record_length = (tag[2] << 8) + tag[3];
695
0
      file->record_count = tag[4];
696
0
      sc_log(ctx, "  rec_len: %zu  rec_cnt: %zu", file->record_length, file->record_count);
697
0
    }
698
110
  }
699
700
234
  tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
701
234
  if (tag != NULL && taglen >= 2) {
702
3
    file->id = (tag[0] << 8) | tag[1];
703
3
    sc_log(ctx,  "  file identifier: 0x%02X%02X\n",
704
3
      tag[0], tag[1]);
705
3
  }
706
707
234
  tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
708
234
  if (tag != NULL && taglen > 0 && taglen <= 16) {
709
11
    memcpy(file->name, tag, taglen);
710
11
    file->namelen = taglen;
711
11
    sc_log(ctx,  "  filename %s",
712
11
      sc_dump_hex(file->name, file->namelen));
713
11
  }
714
715
234
  tag = sc_asn1_find_tag(ctx, p, len, 0x8a, &taglen);
716
234
  if (tag != NULL && taglen == 1) {
717
6
    char* status = "unknown";
718
6
    switch (tag[0]) {
719
1
    case 1:
720
1
      status = "creation";
721
1
      file->status = SC_FILE_STATUS_CREATION;
722
1
      break;
723
2
    case 5:
724
2
      status = "operational active";
725
2
      file->status = SC_FILE_STATUS_ACTIVATED;
726
2
      break;
727
1
    case 12:
728
2
    case 13:
729
2
      status = "creation";
730
2
      file->status = SC_FILE_STATUS_INVALIDATED;
731
2
      break;
732
1
    default:
733
1
      break;
734
6
    }
735
6
    sc_log(ctx,  "  file status: %s\n", status);
736
6
  }
737
738
234
  file->magic = SC_FILE_MAGIC;
739
234
  return SC_SUCCESS;
740
234
}
741
742
static int starcos_select_aid(sc_card_t *card,
743
            const u8 aid[16], size_t len,
744
            sc_file_t **file_out)
745
2.67k
{
746
2.67k
  sc_apdu_t apdu;
747
2.67k
  int r;
748
2.67k
  size_t i = 0;
749
750
2.67k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
751
2.67k
  apdu.lc = len;
752
2.67k
  apdu.data = (u8*)aid;
753
2.67k
  apdu.datalen = len;
754
2.67k
  apdu.resplen = 0;
755
2.67k
  apdu.le = 0;
756
2.67k
  r = sc_transmit_apdu(card, &apdu);
757
2.67k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
758
759
  /* check return value */
760
2.65k
  if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 )
761
1.95k
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
762
763
700
  if (file_out) {
764
0
    sc_file_t *file = sc_file_new();
765
0
    if (!file)
766
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
767
0
    file->type = SC_FILE_TYPE_DF;
768
0
    file->ef_structure = SC_FILE_EF_UNKNOWN;
769
0
    file->path.len = 0;
770
0
    file->size = 0;
771
    /* AID */
772
0
    for (i = 0; i < len; i++)
773
0
      file->name[i] = aid[i];
774
0
    file->namelen = len;
775
0
    file->id = 0x0000;
776
0
    file->magic = SC_FILE_MAGIC;
777
778
0
    *file_out = file;
779
0
  }
780
700
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
781
700
}
782
783
static int starcos_select_fid(sc_card_t *card,
784
            unsigned int id_hi, unsigned int id_lo,
785
            sc_file_t **file_out, int is_file)
786
7.10k
{
787
7.10k
  sc_apdu_t apdu;
788
7.10k
  u8 data[] = {id_hi & 0xff, id_lo & 0xff};
789
7.10k
  u8 resp[SC_MAX_APDU_BUFFER_SIZE];
790
7.10k
  int bIsDF = 0, r;
791
7.10k
  int isFCP = 0;
792
7.10k
  int isMF = 0;
793
794
  /* request FCI to distinguish between EFs and DFs */
795
7.10k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00);
796
7.10k
  apdu.p2   = 0x00;
797
7.10k
  apdu.resp = (u8*)resp;
798
7.10k
  apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
799
7.10k
  apdu.le = 256;
800
7.10k
  apdu.lc = 2;
801
7.10k
  apdu.data = (u8*)data;
802
7.10k
  apdu.datalen = 2;
803
804
7.10k
  if ( IS_V3x(card) ) {
805
3.79k
    if (id_hi == 0x3f && id_lo == 0x0) {
806
3.03k
      apdu.p1 = 0x0;
807
3.03k
      apdu.p2 = 0x0C;
808
3.03k
      apdu.le = 0;
809
3.03k
      apdu.resplen = 0;
810
3.03k
      apdu.resp = NULL;
811
3.03k
      apdu.cse = SC_APDU_CASE_3_SHORT;
812
3.03k
      isMF = 1;
813
3.03k
    } else if (file_out || is_file) {
814
      // last component (i.e. file or path)
815
700
      apdu.p1 = 0x2;
816
700
      apdu.p2 = 0x4;
817
700
    } else {
818
      // path component
819
63
      apdu.p1 = 0x1;
820
63
      apdu.p2 = 0x0;
821
63
    }
822
3.79k
  }
823
824
7.10k
  r = sc_transmit_apdu(card, &apdu);
825
7.10k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
826
827
6.94k
  if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) {
828
    /* no FCI => we have a DF (see comment in process_fci()) */
829
31
    bIsDF = 1;
830
31
    apdu.p2 = 0x0C;
831
31
    apdu.cse = SC_APDU_CASE_3_SHORT;
832
31
    apdu.resplen = 0;
833
31
    apdu.le = 0;
834
31
    r = sc_transmit_apdu(card, &apdu);
835
31
    LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
836
6.91k
  } else if ((IS_V3x(card))
837
3.73k
      && apdu.p2 == 0x4 && apdu.sw1 == 0x6a && apdu.sw2 == 0x82) {
838
    /* not a file, could be a path */
839
121
    bIsDF = 1;
840
121
    apdu.p1 = 0x1;
841
121
    apdu.p2 = 0x0;
842
121
    apdu.resplen = sizeof(resp);
843
121
    apdu.le = 256;
844
121
    apdu.lc = 2;
845
121
    r = sc_transmit_apdu(card, &apdu);
846
121
    LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
847
6.79k
  } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && !isMF)) {
848
    /* SELECT returned some data (possible FCI) =>
849
     * try a READ BINARY to see if a EF is selected */
850
2.05k
    sc_apdu_t apdu2;
851
2.05k
    u8 resp2[2];
852
2.05k
    sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0);
853
2.05k
    apdu2.resp = (u8*)resp2;
854
2.05k
    apdu2.resplen = 2;
855
2.05k
    apdu2.le = 1;
856
2.05k
    apdu2.lc = 0;
857
2.05k
    r = sc_transmit_apdu(card, &apdu2);
858
2.05k
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
859
1.99k
    if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86) {
860
      /* no current EF is selected => we have a DF */
861
51
      bIsDF = 1;
862
1.94k
    } else {
863
1.94k
      isFCP = 1;
864
1.94k
    }
865
1.99k
  }
866
867
6.85k
  if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00))
868
4.04k
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
869
870
2.81k
  if (file_out) {
871
924
    sc_file_t *file = sc_file_new();
872
924
    if (!file)
873
924
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
874
924
    file->id = (id_hi << 8) + id_lo;
875
876
924
    if (bIsDF || isMF) {
877
      /* we have a DF */
878
136
      file->type = SC_FILE_TYPE_DF;
879
136
      file->ef_structure = SC_FILE_EF_UNKNOWN;
880
136
      file->size = 0;
881
136
      file->namelen = 0;
882
136
      file->magic = SC_FILE_MAGIC;
883
136
      *file_out = file;
884
788
    } else {
885
      /* ok, assume we have a EF */
886
788
      if ( IS_V3x(card) ) {
887
409
        if (isFCP) {
888
409
          r = process_fcp_v3_4(card->ctx, file, apdu.resp,
889
409
              apdu.resplen);
890
409
        } else {
891
0
          r = process_fci_v3_4(card->ctx, file, apdu.resp,
892
0
              apdu.resplen);
893
0
        }
894
409
      } else {
895
379
        r = process_fci(card->ctx, file, apdu.resp,
896
379
            apdu.resplen);
897
379
      }
898
788
      if (r != SC_SUCCESS) {
899
309
        sc_file_free(file);
900
309
        return r;
901
309
      }
902
903
479
      *file_out = file;
904
479
    }
905
924
  }
906
907
2.50k
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
908
2.50k
}
909
910
static int starcos_select_file(sc_card_t *card,
911
             const sc_path_t *in_path,
912
             sc_file_t **file_out)
913
7.68k
{
914
7.68k
  u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
915
7.68k
  int    r, pathtype;
916
7.68k
  size_t i, pathlen;
917
918
7.68k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
919
920
7.68k
  if ( in_path->len > sizeof(pathbuf) ) {
921
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_BUFFER_TOO_SMALL);
922
0
  }
923
7.68k
  memcpy(path, in_path->value, in_path->len);
924
7.68k
  pathlen = in_path->len;
925
7.68k
  pathtype = in_path->type;
926
927
7.68k
  if (in_path->aid.len) {
928
195
    if (!pathlen) {
929
0
      if ( in_path->aid.len > sizeof(pathbuf) ) {
930
0
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_BUFFER_TOO_SMALL);
931
0
      }
932
0
      memcpy(path, in_path->aid.value, in_path->aid.len);
933
0
      pathlen = in_path->aid.len;
934
0
      pathtype = SC_PATH_TYPE_DF_NAME;
935
195
    } else {
936
195
      r = starcos_select_aid(card, in_path->aid.value, in_path->aid.len, NULL);
937
195
      LOG_TEST_RET(card->ctx, r, "Could not select AID!");
938
939
127
      if (pathtype == SC_PATH_TYPE_DF_NAME) {
940
0
        pathtype = SC_PATH_TYPE_FILE_ID;
941
0
      }
942
127
    }
943
195
  }
944
945
7.62k
  if (pathtype == SC_PATH_TYPE_FILE_ID)
946
3
  { /* SELECT EF/DF with ID */
947
    /* Select with 2byte File-ID */
948
3
    if (pathlen != 2)
949
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
950
3
    r = starcos_select_fid(card, path[0],
951
3
        path[1], path[0] == 0x3F && path[1] == 0x00 ? NULL : file_out, 1);
952
3
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
953
3
  }
954
7.61k
  else if (pathtype == SC_PATH_TYPE_DF_NAME)
955
2.03k
  { /* SELECT DF with AID */
956
    /* Select with 1-16byte Application-ID */
957
2.03k
    r = starcos_select_aid(card, pathbuf, pathlen, file_out);
958
2.03k
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
959
2.03k
  }
960
5.58k
  else if (pathtype == SC_PATH_TYPE_PATH)
961
5.58k
  {
962
5.58k
    u8 n_pathbuf[SC_MAX_PATH_SIZE];
963
964
    /* Select with path (sequence of File-IDs) */
965
    /* Starcos (S 2.1 and SPK 2.3) only supports one
966
     * level of subdirectories, therefore a path is
967
     * at most 3 FID long (the last one being the FID
968
     * of a EF) => pathlen must be even and less than 6
969
     */
970
5.58k
    if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
971
11
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
972
    /* if pathlen == 6 then the first FID must be MF (== 3F00) */
973
5.57k
    if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
974
21
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
975
976
5.55k
    if ( IS_V3x(card) ) {
977
      /* unify path (the first FID should be MF) */
978
3.03k
      if (path[0] != 0x3f || path[1] != 0x00)
979
146
      {
980
146
        n_pathbuf[0] = 0x3f;
981
146
        n_pathbuf[1] = 0x00;
982
146
        memcpy(n_pathbuf+2, path, pathlen);
983
146
        path = n_pathbuf;
984
146
        pathlen += 2;
985
146
      }
986
3.03k
    }
987
988
7.10k
    for ( i=0; i<pathlen-2; i+=2 )
989
5.58k
    {
990
5.58k
      r = starcos_select_fid(card, path[i], path[i+1], NULL, 0);
991
5.58k
      LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
992
5.58k
    }
993
1.51k
    r = starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out, 1);
994
1.51k
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
995
1.51k
  }
996
0
  else
997
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
998
7.62k
}
999
1000
static int starcos_get_challenge(struct sc_card *card, unsigned char *rnd, size_t len)
1001
294
{
1002
294
  LOG_FUNC_CALLED(card->ctx);
1003
1004
294
  if (len > 8) {
1005
256
    len = 8;
1006
256
  }
1007
1008
294
  LOG_FUNC_RETURN(card->ctx, iso_ops->get_challenge(card, rnd, len));
1009
294
}
1010
1011
0
#define STARCOS_AC_ALWAYS 0x9f
1012
0
#define STARCOS_AC_NEVER  0x5f
1013
0
#define STARCOS_PINID2STATE(a)  ((((a) & 0x0f) == 0x01) ? ((a) & 0x0f) : (0x0f - ((0x0f & (a)) >> 1)))
1014
1015
static u8 process_acl_entry(sc_file_t *in, unsigned int method, unsigned int in_def)
1016
0
{
1017
0
  u8 def = (u8)in_def;
1018
0
  const sc_acl_entry_t *entry = sc_file_get_acl_entry(in, method);
1019
0
  if (!entry)
1020
0
    return def;
1021
0
  else if (entry->method & SC_AC_CHV) {
1022
0
    unsigned int key_ref = entry->key_ref;
1023
0
    if (key_ref == SC_AC_KEY_REF_NONE)
1024
0
      return def;
1025
0
    else if ((key_ref & 0x0f) == 1)
1026
      /* SOPIN */
1027
0
      return (key_ref & 0x80 ? 0x10 : 0x00) | 0x01;
1028
0
    else
1029
0
      return (key_ref & 0x80 ? 0x10 : 0x00) | STARCOS_PINID2STATE(key_ref);
1030
0
  } else if (entry->method & SC_AC_NEVER)
1031
0
    return STARCOS_AC_NEVER;
1032
0
  else
1033
0
    return def;
1034
0
}
1035
1036
/** starcos_process_acl
1037
 * \param card pointer to the sc_card object
1038
 * \param file pointer to the sc_file object
1039
 * \param data pointer to a sc_starcos_create_data structure
1040
 * \return SC_SUCCESS if no error occurred otherwise error code
1041
 *
1042
 * This function tries to create a somewhat usable Starcos spk 2.3 acl
1043
 * from the OpenSC internal acl (storing the result in the supplied
1044
 * sc_starcos_create_data structure).
1045
 */
1046
static int starcos_process_acl(sc_card_t *card, sc_file_t *file,
1047
  sc_starcos_create_data *data)
1048
0
{
1049
0
  u8     tmp, *p;
1050
0
  static const u8 def_key[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
1051
1052
0
  if (file->type == SC_FILE_TYPE_DF && file->id == 0x3f00) {
1053
0
    p    = data->data.mf.header;
1054
0
    memcpy(p, def_key, 8);
1055
0
    p   += 8;
1056
0
    *p++ = (file->size >> 8) & 0xff;
1057
0
    *p++ = file->size & 0xff;
1058
    /* guess isf size (mf_size / 4) */
1059
0
    *p++ = (file->size >> 10) & 0xff;
1060
0
    *p++ = (file->size >> 2)  & 0xff;
1061
    /* ac create ef  */
1062
0
    *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
1063
    /* ac create key */
1064
0
    *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
1065
    /* ac create df  */
1066
0
    *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
1067
    /* use the same ac for register df and create df */
1068
0
    *p++ = data->data.mf.header[14];
1069
    /* if sm is required use combined mode */
1070
0
    if (file->acl[SC_AC_OP_CREATE] && (sc_file_get_acl_entry(file, SC_AC_OP_CREATE))->method & SC_AC_PRO)
1071
0
      tmp = 0x03; /* combined mode */
1072
0
    else
1073
0
      tmp = 0x00; /* no sm */
1074
0
    *p++ = tmp; /* use the same sm mode for all ops */
1075
0
    *p++ = tmp;
1076
0
    *p = tmp;
1077
0
    data->type = SC_STARCOS_MF_DATA;
1078
1079
0
    return SC_SUCCESS;
1080
0
  } else if (file->type == SC_FILE_TYPE_DF){
1081
0
    p    = data->data.df.header;
1082
0
    *p++ = (file->id >> 8) & 0xff;
1083
0
    *p++ = file->id & 0xff;
1084
0
    if (file->namelen) {
1085
      /* copy aid */
1086
0
      *p++ = file->namelen & 0xff;
1087
0
      memset(p, 0, 16);
1088
0
      memcpy(p, file->name, (u8)file->namelen);
1089
0
      p   += 16;
1090
0
    } else {
1091
      /* use the fid as aid */
1092
0
      *p++ = 2;
1093
0
      memset(p, 0, 16);
1094
0
      *p++ = (file->id >> 8) & 0xff;
1095
0
      *p++ = file->id & 0xff;
1096
0
      p   += 14;
1097
0
    }
1098
    /* guess isf size */
1099
0
    *p++ = (file->size >> 10) & 0xff; /* ISF space */
1100
0
    *p++ = (file->size >> 2)  & 0xff; /* ISF space */
1101
    /* ac create ef  */
1102
0
    *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
1103
    /* ac create key */
1104
0
    *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS);
1105
    /* set sm byte (same for keys and ef) */
1106
0
    if (file->acl[SC_AC_OP_CREATE] &&
1107
0
        (sc_file_get_acl_entry(file, SC_AC_OP_CREATE)->method &
1108
0
         SC_AC_PRO))
1109
0
      tmp = 0x03;
1110
0
    else
1111
0
      tmp = 0x00;
1112
0
    *p++ = tmp; /* SM CR  */
1113
0
    *p = tmp; /* SM ISF */
1114
1115
0
    data->data.df.size[0] = (file->size >> 8) & 0xff;
1116
0
    data->data.df.size[1] = file->size & 0xff;
1117
0
    data->type = SC_STARCOS_DF_DATA;
1118
1119
0
    return SC_SUCCESS;
1120
0
  } else if (file->type == SC_FILE_TYPE_WORKING_EF) {
1121
0
    p    = data->data.ef.header;
1122
0
    *p++ = (file->id >> 8) & 0xff;
1123
0
    *p++ = file->id & 0xff;
1124
    /* ac read  */
1125
0
    *p++ = process_acl_entry(file, SC_AC_OP_READ,STARCOS_AC_ALWAYS);
1126
    /* ac write */
1127
0
    *p++ = process_acl_entry(file, SC_AC_OP_WRITE,STARCOS_AC_ALWAYS);
1128
    /* ac erase */
1129
0
    *p++ = process_acl_entry(file, SC_AC_OP_ERASE,STARCOS_AC_ALWAYS);
1130
0
    *p++ = STARCOS_AC_ALWAYS; /* AC LOCK     */
1131
0
    *p++ = STARCOS_AC_ALWAYS; /* AC UNLOCK   */
1132
0
    *p++ = STARCOS_AC_ALWAYS; /* AC INCREASE */
1133
0
    *p++ = STARCOS_AC_ALWAYS; /* AC DECREASE */
1134
0
    *p++ = 0x00;      /* rfu         */
1135
0
    *p++ = 0x00;      /* rfu         */
1136
    /* use sm (in combined mode) if wanted */
1137
0
    if ((file->acl[SC_AC_OP_READ]   && (sc_file_get_acl_entry(file, SC_AC_OP_READ)->method & SC_AC_PRO)) ||
1138
0
        (file->acl[SC_AC_OP_UPDATE] && (sc_file_get_acl_entry(file, SC_AC_OP_UPDATE)->method & SC_AC_PRO)) ||
1139
0
        (file->acl[SC_AC_OP_WRITE]  && (sc_file_get_acl_entry(file, SC_AC_OP_WRITE)->method & SC_AC_PRO)) )
1140
0
      tmp = 0x03;
1141
0
    else
1142
0
      tmp = 0x00;
1143
0
    *p++ = tmp;     /* SM byte     */
1144
0
    *p++ = 0x00;      /* use the least significant 5 bits
1145
             * of the FID as SID */
1146
0
    switch (file->ef_structure)
1147
0
    {
1148
0
    case SC_FILE_EF_TRANSPARENT:
1149
0
      *p++ = 0x81;
1150
0
      *p++ = (file->size >> 8) & 0xff;
1151
0
      *p = file->size & 0xff;
1152
0
      break;
1153
0
    case SC_FILE_EF_LINEAR_FIXED:
1154
0
      *p++ = 0x82;
1155
0
      *p++ = file->record_count  & 0xff;
1156
0
      *p = file->record_length & 0xff;
1157
0
      break;
1158
0
    case SC_FILE_EF_CYCLIC:
1159
0
      *p++ = 0x84;
1160
0
      *p++ = file->record_count  & 0xff;
1161
0
      *p = file->record_length & 0xff;
1162
0
      break;
1163
0
    default:
1164
0
      return SC_ERROR_INVALID_ARGUMENTS;
1165
0
    }
1166
0
    data->type = SC_STARCOS_EF_DATA;
1167
1168
0
    return SC_SUCCESS;
1169
0
  } else
1170
0
                return SC_ERROR_INVALID_ARGUMENTS;
1171
0
}
1172
1173
/** starcos_create_mf
1174
 * internal function to create the MF
1175
 * \param card pointer to the sc_card structure
1176
 * \param data pointer to a sc_starcos_create_data object
1177
 * \return SC_SUCCESS or error code
1178
 *
1179
 * This function creates the MF based on the information stored
1180
 * in the sc_starcos_create_data.mf structure. Note: CREATE END must be
1181
 * called separately to activate the ACs.
1182
 */
1183
static int starcos_create_mf(sc_card_t *card, sc_starcos_create_data *data)
1184
0
{
1185
0
  int    r;
1186
0
  sc_apdu_t       apdu;
1187
0
  sc_context_t   *ctx = card->ctx;
1188
1189
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1190
1191
0
  sc_log(ctx,  "creating MF \n");
1192
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
1193
0
  apdu.cla |= 0x80;
1194
0
  apdu.lc   = 19;
1195
0
  apdu.datalen = 19;
1196
0
  apdu.data = (u8 *) data->data.mf.header;
1197
1198
0
  r = sc_transmit_apdu(card, &apdu);
1199
0
  LOG_TEST_RET(ctx, r, "APDU transmit failed");
1200
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
1201
0
}
1202
1203
/** starcos_create_df
1204
 * internal function to create a DF
1205
 * \param card pointer to the sc_card structure
1206
 * \param data pointer to a sc_starcos_create_data object
1207
 * \return SC_SUCCESS or error code
1208
 *
1209
 * This functions registers and creates a DF based in the information
1210
 * stored in a sc_starcos_create_data.df data structure. Note: CREATE END must
1211
 * be called separately to activate the ACs.
1212
 */
1213
static int starcos_create_df(sc_card_t *card, sc_starcos_create_data *data)
1214
0
{
1215
0
  int    r;
1216
0
  size_t len;
1217
0
  sc_apdu_t       apdu;
1218
0
  sc_context_t   *ctx = card->ctx;
1219
1220
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1221
1222
0
  sc_log(ctx,  "creating DF\n");
1223
  /* first step: REGISTER DF */
1224
0
  sc_log(ctx,  "calling REGISTER DF\n");
1225
1226
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x52,
1227
0
           data->data.df.size[0], data->data.df.size[1]);
1228
0
  len  = 3 + data->data.df.header[2];
1229
0
  apdu.cla |= 0x80;
1230
0
  apdu.lc   = len;
1231
0
  apdu.datalen = len;
1232
0
  apdu.data = data->data.df.header;
1233
1234
0
  r = sc_transmit_apdu(card, &apdu);
1235
0
  LOG_TEST_RET(ctx, r, "APDU transmit failed");
1236
  /* second step: CREATE DF */
1237
0
  sc_log(ctx,  "calling CREATE DF\n");
1238
1239
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x01, 0x00);
1240
0
  apdu.cla |= 0x80;
1241
0
  apdu.lc   = 25;
1242
0
  apdu.datalen = 25;
1243
0
  apdu.data = data->data.df.header;
1244
1245
0
  r = sc_transmit_apdu(card, &apdu);
1246
0
  LOG_TEST_RET(ctx, r, "APDU transmit failed");
1247
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
1248
0
}
1249
1250
/** starcos_create_ef
1251
 * internal function to create a EF
1252
 * \param card pointer to the sc_card structure
1253
 * \param data pointer to a sc_starcos_create_data object
1254
 * \return SC_SUCCESS or error code
1255
 *
1256
 * This function creates a EF based on the information stored in
1257
 * the sc_starcos_create_data.ef data structure.
1258
 */
1259
static int starcos_create_ef(sc_card_t *card, sc_starcos_create_data *data)
1260
0
{
1261
0
  int    r;
1262
0
  sc_apdu_t       apdu;
1263
0
  sc_context_t   *ctx = card->ctx;
1264
1265
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1266
1267
0
  sc_log(ctx,  "creating EF\n");
1268
1269
0
  sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT,0xE0,0x03,0x00);
1270
0
  apdu.cla |= 0x80;
1271
0
  apdu.lc   = 16;
1272
0
  apdu.datalen = 16;
1273
0
  apdu.data = (u8 *) data->data.ef.header;
1274
1275
0
  r = sc_transmit_apdu(card, &apdu);
1276
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1277
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
1278
0
}
1279
1280
/** starcos_create_end
1281
 * internal function to activate the ACs
1282
 * \param card pointer to the sc_card structure
1283
 * \param file pointer to a sc_file object
1284
 * \return SC_SUCCESS or error code
1285
 *
1286
 * This function finishes the creation of a DF (or MF) and activates
1287
 * the ACs.
1288
 */
1289
static int starcos_create_end(sc_card_t *card, sc_file_t *file)
1290
0
{
1291
0
  int r;
1292
0
  u8  fid[2];
1293
0
  sc_apdu_t       apdu;
1294
1295
0
  if (file->type != SC_FILE_TYPE_DF)
1296
0
    return SC_ERROR_INVALID_ARGUMENTS;
1297
1298
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1299
1300
0
  fid[0] = (file->id >> 8) & 0xff;
1301
0
  fid[1] = file->id & 0xff;
1302
0
  sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT, 0xE0, 0x02, 0x00);
1303
0
  apdu.cla |= 0x80;
1304
0
  apdu.lc   = 2;
1305
0
  apdu.datalen = 2;
1306
0
  apdu.data = fid;
1307
0
  r = sc_transmit_apdu(card, &apdu);
1308
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1309
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
1310
0
}
1311
1312
/** starcos_create_file
1313
 * \param card pointer to the sc_card structure
1314
 * \param file pointer to a sc_file object
1315
 * \return SC_SUCCESS or error code
1316
 *
1317
 * This function creates MF, DF or EF based on the supplied
1318
 * information in the sc_file structure (using starcos_process_acl).
1319
 */
1320
static int starcos_create_file(sc_card_t *card, sc_file_t *file)
1321
0
{
1322
0
  int    r;
1323
0
  sc_starcos_create_data data;
1324
1325
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1326
1327
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1328
1329
0
  if (file->type == SC_FILE_TYPE_DF) {
1330
0
    if (file->id == 0x3f00) {
1331
      /* CREATE MF */
1332
0
      r = starcos_process_acl(card, file, &data);
1333
0
      if (r != SC_SUCCESS)
1334
0
        return r;
1335
0
      return starcos_create_mf(card, &data);
1336
0
    } else {
1337
      /* CREATE DF */
1338
0
      r = starcos_process_acl(card, file, &data);
1339
0
      if (r != SC_SUCCESS)
1340
0
        return r;
1341
0
      return starcos_create_df(card, &data);
1342
0
    }
1343
0
  } else if (file->type == SC_FILE_TYPE_WORKING_EF) {
1344
    /* CREATE EF */
1345
0
    r = starcos_process_acl(card, file, &data);
1346
0
    if (r != SC_SUCCESS)
1347
0
      return r;
1348
0
    return starcos_create_ef(card, &data);
1349
0
  } else
1350
0
    return SC_ERROR_INVALID_ARGUMENTS;
1351
0
}
1352
1353
/** starcos_erase_card
1354
 * internal function to restore the delivery state
1355
 * \param card pointer to the sc_card object
1356
 * \return SC_SUCCESS or error code
1357
 *
1358
 * This function deletes the MF (for 'test cards' only).
1359
 */
1360
static int starcos_erase_card(sc_card_t *card)
1361
0
{ /* restore the delivery state */
1362
0
  int r;
1363
0
  u8  sbuf[2];
1364
0
  sc_apdu_t apdu = {0};
1365
1366
0
  sbuf[0] = 0x3f;
1367
0
  sbuf[1] = 0x00;
1368
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
1369
0
  apdu.cla |= 0x80;
1370
0
  apdu.lc   = 2;
1371
0
  apdu.datalen = 2;
1372
0
  apdu.data = sbuf;
1373
1374
0
  r = sc_transmit_apdu(card, &apdu);
1375
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1376
0
  if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85)
1377
    /* no MF to delete, ignore error */
1378
0
    return SC_SUCCESS;
1379
0
  else return sc_check_sw(card, apdu.sw1, apdu.sw2);
1380
0
}
1381
1382
0
#define STARCOS_WKEY_CSIZE  124
1383
1384
/** starcos_write_key
1385
 * set key in isf
1386
 * \param card pointer to the sc_card object
1387
 * \param data pointer to a sc_starcos_wkey_data structure
1388
 * \return SC_SUCCESS or error code
1389
 *
1390
 * This function installs a key header in the ISF (based on the
1391
 * information supplied in the sc_starcos_wkey_data structure)
1392
 * and set a supplied key (depending on the mode).
1393
 */
1394
static int starcos_write_key(sc_card_t *card, sc_starcos_wkey_data *data)
1395
0
{
1396
0
  int       r;
1397
0
  u8        sbuf[SC_MAX_APDU_BUFFER_SIZE];
1398
0
  const u8 *p;
1399
0
  size_t    len = sizeof(sbuf), tlen, offset = 0;
1400
0
  sc_apdu_t       apdu;
1401
1402
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1403
1404
0
  if (data->mode == 0) { /* mode == 0 => install */
1405
    /* install key header */
1406
0
    sbuf[0] = 0xc1; /* key header tag    */
1407
0
    sbuf[1] = 0x0c; /* key header length */
1408
0
    memcpy(sbuf + 2, data->key_header, 12);
1409
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xf4,
1410
0
             data->mode, 0x00);
1411
0
    apdu.cla |= 0x80;
1412
0
    apdu.lc   = 14;
1413
0
    apdu.datalen = 14;
1414
0
    apdu.data = sbuf;
1415
1416
0
    r = sc_transmit_apdu(card, &apdu);
1417
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1418
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1419
0
      return sc_check_sw(card, apdu.sw1, apdu.sw2);
1420
0
    if (data->key == NULL)
1421
0
      return SC_SUCCESS;
1422
0
  }
1423
1424
0
  if (data->key == NULL)
1425
0
    return SC_ERROR_INVALID_ARGUMENTS;
1426
1427
0
  p    = data->key;
1428
0
  tlen = data->key_len;
1429
0
  while (tlen != 0) {
1430
    /* transmit the key in chunks of STARCOS_WKEY_CSIZE bytes */
1431
0
    u8 c_len = tlen < STARCOS_WKEY_CSIZE ? tlen : STARCOS_WKEY_CSIZE;
1432
0
    sbuf[0] = 0xc2;
1433
0
    sbuf[1] = 3 + c_len;
1434
0
    sbuf[2] = data->kid;
1435
0
    sbuf[3] = (offset >> 8) & 0xff;
1436
0
    sbuf[4] = offset & 0xff;
1437
0
    memcpy(sbuf+5, p, c_len);
1438
0
    len = 5 + c_len;
1439
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xf4, data->mode, 0x00);
1440
0
    apdu.cla    |= 0x80;
1441
0
    apdu.lc      = len;
1442
0
    apdu.datalen = len;
1443
0
    apdu.data    = sbuf;
1444
1445
0
    r = sc_transmit_apdu(card, &apdu);
1446
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1447
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1448
0
      return sc_check_sw(card, apdu.sw1, apdu.sw2);
1449
0
    offset += c_len;
1450
0
    p      += c_len;
1451
0
    tlen   -= c_len;
1452
0
  }
1453
0
  return SC_SUCCESS;
1454
0
}
1455
1456
/** starcos_gen_key
1457
 * generate public key pair
1458
 * \param card pointer to the sc_card object
1459
 * \param data pointer to a sc_starcos_gen_key_data structure
1460
 * \return SC_SUCCESS or error code
1461
 *
1462
 * This function generates a public key pair and stores the created
1463
 * private key in the ISF (specified by the KID).
1464
 */
1465
static int starcos_gen_key(sc_card_t *card, sc_starcos_gen_key_data *data)
1466
0
{
1467
0
  int r;
1468
0
  size_t  i, len = data->key_length >> 3;
1469
0
  sc_apdu_t apdu;
1470
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
1471
0
  u8 sbuf[2], *p, *q;
1472
1473
0
  CHECK_NOT_SUPPORTED_V3_4(card);
1474
1475
  /* generate key */
1476
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46,  0x00,
1477
0
      data->key_id);
1478
0
  apdu.le      = 0;
1479
0
  sbuf[0] = (u8)(data->key_length >> 8);
1480
0
  sbuf[1] = (u8)(data->key_length);
1481
0
  apdu.data    = sbuf;
1482
0
  apdu.lc      = 2;
1483
0
  apdu.datalen = 2;
1484
0
  r = sc_transmit_apdu(card, &apdu);
1485
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1486
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1487
0
    return sc_check_sw(card, apdu.sw1, apdu.sw2);
1488
  /* read public key via READ PUBLIC KEY */
1489
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xf0,  0x9c, 0x00);
1490
0
  sbuf[0]      = data->key_id;
1491
0
  apdu.cla    |= 0x80;
1492
0
  apdu.data    = sbuf;
1493
0
  apdu.datalen = 1;
1494
0
  apdu.lc      = 1;
1495
0
  apdu.resp    = rbuf;
1496
0
  apdu.resplen = sizeof(rbuf);
1497
0
  apdu.le      = 256;
1498
0
  r = sc_transmit_apdu(card, &apdu);
1499
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1500
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1501
0
    return sc_check_sw(card, apdu.sw1, apdu.sw2);
1502
1503
0
  if (len > sizeof(rbuf) - 18 || apdu.resplen < 18 + len) {
1504
0
    sc_log(card->ctx, "READ PUBLIC KEY response too short/invalid: got %zu need >= %zu",
1505
0
        apdu.resplen, 18 + len);
1506
0
    return SC_ERROR_INVALID_DATA;
1507
0
  }
1508
1509
0
  data->modulus = malloc(len);
1510
0
  if (!data->modulus)
1511
0
    return SC_ERROR_OUT_OF_MEMORY;
1512
0
  p = data->modulus;
1513
  /* XXX use tags to find starting position of the modulus */
1514
0
  q = &rbuf[18];
1515
  /* LSB to MSB -> MSB to LSB */
1516
0
  for (i = len; i != 0; i--)
1517
0
    *p++ = q[i - 1];
1518
1519
0
  return SC_SUCCESS;
1520
0
}
1521
1522
/** starcos_set_security_env
1523
 * sets the security environment
1524
 * \param card pointer to the sc_card object
1525
 * \param env pointer to a sc_security_env object
1526
 * \param se_num not used here
1527
 * \return SC_SUCCESS on success or an error code
1528
 *
1529
 * This function sets the security environment (using the starcos spk 2.3
1530
 * command MANAGE SECURITY ENVIRONMENT). In case a COMPUTE SIGNATURE
1531
 * operation is requested , this function tries to detect whether
1532
 * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE must be used for signature
1533
 * calculation.
1534
 */
1535
static int starcos_set_security_env(sc_card_t *card,
1536
            const sc_security_env_t *env,
1537
            int se_num)
1538
46
{
1539
46
  u8              *p, *pp;
1540
46
  int              r, operation = env->operation;
1541
46
  sc_apdu_t   apdu;
1542
46
  u8               sbuf[SC_MAX_APDU_BUFFER_SIZE];
1543
46
  starcos_ex_data *ex_data = (starcos_ex_data *)card->drv_data;
1544
1545
46
  p     = sbuf;
1546
1547
46
  if ( IS_V3x(card) ) {
1548
10
    u8 algorithm_supported = (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) ||
1549
0
                (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS);
1550
10
    if (!algorithm_supported ||
1551
10
      !(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || env->key_ref_len != 1) {
1552
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1553
0
    }
1554
1555
    /* Tag '84' (length 1) denotes key name or key reference */
1556
10
    *p++ = 0x84;
1557
10
    *p++ = 0x01;
1558
10
    if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {
1559
0
      *p++ = *env->key_ref | 0x80;
1560
10
    } else {
1561
10
      *p++ = *env->key_ref;
1562
10
    }
1563
1564
10
    switch (operation) {
1565
3
      case SC_SEC_OPERATION_SIGN:
1566
3
        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB6);
1567
1568
        /* algorithm / cipher selector? */
1569
        /* algorithm: 13.23 PKCS#1 signature with RSA (standard) */
1570
        /* algorithm: 13.33.30 PKCS#1-PSS signature with SHA-256 */
1571
3
        *p++ = 0x89;
1572
3
        if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS) {
1573
0
          *p++ = 0x03;
1574
0
          *p++ = 0x13;
1575
0
          *p++ = 0x33;
1576
0
          *p++ = 0x30;
1577
3
        } else {
1578
          // fall back, RSA PKCS1 Padding
1579
3
          *p++ = 0x02;
1580
3
          *p++ = 0x13;
1581
3
          *p++ = 0x23;
1582
3
        }
1583
3
        break;
1584
1585
7
      case SC_SEC_OPERATION_DECIPHER:
1586
7
        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8);
1587
1588
        /* algorithm / cipher selector? */
1589
        /* algorithm: 11.3  Encipherment RSA (standard) */
1590
        /* algorithm: 11.31 Encipherment RSA (standard) with PKCS#1 padding */
1591
        /* algorithm: 11.32 Encipherment RSA OAEP padding */
1592
7
        *p++ = 0x89;
1593
7
        *p++ = 0x02;
1594
7
        *p++ = 0x11;
1595
7
        if ( IS_V34(card) )
1596
7
          *p++ = 0x30;
1597
0
        else
1598
0
          *p++ = 0x31;
1599
7
        break;
1600
1601
0
      default:
1602
0
        sc_log(card->ctx,
1603
0
            "not supported for STARCOS 3.4 cards");
1604
0
        return SC_ERROR_NOT_SUPPORTED;
1605
10
    }
1606
1607
10
    apdu.data    = sbuf;
1608
10
    apdu.datalen = p - sbuf;
1609
10
    apdu.lc      = p - sbuf;
1610
10
    apdu.le      = 0;
1611
10
    r = sc_transmit_apdu(card, &apdu);
1612
10
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1613
9
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1614
5
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
1615
1616
4
    if ((operation == SC_SEC_OPERATION_SIGN && env->algorithm_flags == SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01)
1617
4
      || (operation == SC_SEC_OPERATION_DECIPHER && env->algorithm_flags == SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02)) {
1618
      // input data will be already padded
1619
2
      ex_data->fix_digestInfo = 0;
1620
2
    } else {
1621
2
      ex_data->fix_digestInfo = env->algorithm_flags;
1622
2
    }
1623
4
    ex_data->sec_ops        = SC_SEC_OPERATION_SIGN;
1624
4
    return SC_SUCCESS;
1625
9
  }
1626
1627
  /* copy key reference, if present */
1628
36
  if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
1629
36
    if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC)
1630
0
      *p++ = 0x83;
1631
36
    else
1632
36
      *p++ = 0x84;
1633
36
    *p++ = env->key_ref_len;
1634
36
    memcpy(p, env->key_ref, env->key_ref_len);
1635
36
    p += env->key_ref_len;
1636
36
  }
1637
36
  pp = p;
1638
36
  if (operation == SC_SEC_OPERATION_DECIPHER){
1639
0
    if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02) {
1640
0
      *p++ = 0x80;
1641
0
      *p++ = 0x01;
1642
0
      *p++ = 0x02;
1643
0
    } else
1644
0
      return SC_ERROR_INVALID_ARGUMENTS;
1645
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81,
1646
0
                   0xb8);
1647
0
    apdu.data    = sbuf;
1648
0
    apdu.datalen = p - sbuf;
1649
0
    apdu.lc      = p - sbuf;
1650
0
    apdu.le      = 0;
1651
0
    r = sc_transmit_apdu(card, &apdu);
1652
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1653
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1654
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
1655
0
    return SC_SUCCESS;
1656
0
  }
1657
  /* try COMPUTE SIGNATURE */
1658
36
  if (operation == SC_SEC_OPERATION_SIGN && (
1659
36
      env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01 ||
1660
36
      env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796)) {
1661
36
    if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
1662
0
      *p++ = 0x80;
1663
0
      *p++ = 0x01;
1664
0
      *p++ = env->algorithm_ref & 0xFF;
1665
36
    } else if (env->flags & SC_SEC_ENV_ALG_PRESENT &&
1666
36
                env->algorithm == SC_ALGORITHM_RSA) {
1667
      /* set the method to use based on the algorithm_flags */
1668
36
      *p++ = 0x80;
1669
36
      *p++ = 0x01;
1670
36
      if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01) {
1671
36
        if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
1672
4
          *p++ = 0x12;
1673
32
        else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160)
1674
1
          *p++ = 0x22;
1675
31
        else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
1676
28
          *p++ = 0x32;
1677
3
        else {
1678
          /* can't use COMPUTE SIGNATURE =>
1679
           * try INTERNAL AUTHENTICATE */
1680
3
          p = pp;
1681
3
          operation = SC_SEC_OPERATION_AUTHENTICATE;
1682
3
          goto try_authenticate;
1683
3
        }
1684
36
      } else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796) {
1685
0
        if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
1686
0
          *p++ = 0x11;
1687
0
        else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160)
1688
0
          *p++ = 0x21;
1689
0
        else
1690
0
          return SC_ERROR_INVALID_ARGUMENTS;
1691
0
      } else
1692
0
        return SC_ERROR_INVALID_ARGUMENTS;
1693
36
    }
1694
33
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xb6);
1695
33
    apdu.data    = sbuf;
1696
33
    apdu.datalen = p - sbuf;
1697
33
    apdu.lc      = p - sbuf;
1698
33
    apdu.le      = 0;
1699
    /* we don't know whether to use
1700
     * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE */
1701
33
    r = sc_transmit_apdu(card, &apdu);
1702
33
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1703
32
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
1704
13
      ex_data->fix_digestInfo = 0;
1705
13
      ex_data->sec_ops        = SC_SEC_OPERATION_SIGN;
1706
13
      return SC_SUCCESS;
1707
13
    }
1708
    /* reset pointer */
1709
19
    p = pp;
1710
    /* doesn't work => try next op */
1711
19
    operation = SC_SEC_OPERATION_AUTHENTICATE;
1712
19
  }
1713
22
try_authenticate:
1714
  /* try INTERNAL AUTHENTICATE */
1715
22
  if (operation == SC_SEC_OPERATION_AUTHENTICATE &&
1716
22
      env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
1717
22
    *p++ = 0x80;
1718
22
    *p++ = 0x01;
1719
22
    *p++ = 0x01;
1720
22
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41,
1721
22
                   0xa4);
1722
22
    apdu.data    = sbuf;
1723
22
    apdu.datalen = p - sbuf;
1724
22
    apdu.lc      = p - sbuf;
1725
22
    apdu.le      = 0;
1726
22
    r = sc_transmit_apdu(card, &apdu);
1727
22
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1728
21
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1729
9
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
1730
12
    ex_data->fix_digestInfo = env->algorithm_flags;
1731
12
    ex_data->sec_ops        = SC_SEC_OPERATION_AUTHENTICATE;
1732
12
    return SC_SUCCESS;
1733
21
  }
1734
1735
0
  return SC_ERROR_INVALID_ARGUMENTS;
1736
22
}
1737
1738
static int starcos_compute_signature(sc_card_t *card,
1739
             const u8 * data, size_t datalen,
1740
             u8 * out, size_t outlen)
1741
27
{
1742
27
  int r;
1743
27
  sc_apdu_t apdu;
1744
27
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
1745
27
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
1746
27
  starcos_ex_data *ex_data = (starcos_ex_data *)card->drv_data;
1747
1748
27
  if (datalen > SC_MAX_APDU_BUFFER_SIZE)
1749
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1750
1751
27
  if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) {
1752
    /* compute signature with the COMPUTE SIGNATURE command */
1753
1754
15
    if ( IS_V3x(card) ) {
1755
2
      size_t tmp_len;
1756
1757
2
      sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A,
1758
2
             0x9E, 0x9A);
1759
2
      apdu.resp = out;
1760
2
      apdu.resplen = outlen;
1761
2
      apdu.le = outlen;
1762
2
      if (ex_data->fix_digestInfo) {
1763
        // need to pad data
1764
2
        unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES;
1765
2
        if (flags == 0x00) {
1766
0
          flags = SC_ALGORITHM_RSA_HASH_NONE;
1767
0
        }
1768
2
        tmp_len = sizeof(sbuf);
1769
2
        if (ex_data->fix_digestInfo & SC_ALGORITHM_RSA_PAD_PSS) {
1770
0
          r = sc_pkcs1_strip_digest_info_prefix(NULL, data, datalen, sbuf, &tmp_len);
1771
2
        } else {
1772
2
          r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)*8, NULL);
1773
2
        }
1774
2
        LOG_TEST_RET(card->ctx, r, "sc_pkcs1_encode failed");
1775
2
      } else {
1776
0
        memcpy(sbuf, data, datalen);
1777
0
        tmp_len = datalen;
1778
0
      }
1779
1780
2
      apdu.data = sbuf;
1781
2
      apdu.datalen = tmp_len;
1782
2
      apdu.lc = tmp_len;
1783
1784
2
      r = sc_transmit_apdu(card, &apdu);
1785
2
      LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1786
13
    } else {
1787
      /* set the hash value     */
1788
13
      sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A,
1789
13
             0x90, 0x81);
1790
13
      apdu.resp = rbuf;
1791
13
      apdu.resplen = sizeof(rbuf);
1792
13
      apdu.le = 0;
1793
13
      memcpy(sbuf, data, datalen);
1794
13
      apdu.data = sbuf;
1795
13
      apdu.lc = datalen;
1796
13
      apdu.datalen = datalen;
1797
13
      r = sc_transmit_apdu(card, &apdu);
1798
13
      LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1799
12
      if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
1800
3
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,
1801
12
               sc_check_sw(card, apdu.sw1, apdu.sw2));
1802
1803
      /* call COMPUTE SIGNATURE */
1804
9
      sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A,
1805
9
             0x9E, 0x9A);
1806
9
      apdu.resp = rbuf;
1807
9
      apdu.resplen = sizeof(rbuf);
1808
9
      apdu.le = 256;
1809
1810
9
      apdu.lc = 0;
1811
9
      apdu.datalen = 0;
1812
9
      r = sc_transmit_apdu(card, &apdu);
1813
9
      LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1814
9
    }
1815
8
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
1816
2
      size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
1817
2
      if ( out != apdu.resp ) {
1818
2
        memcpy(out, apdu.resp, len);
1819
2
      }
1820
2
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
1821
2
    }
1822
12
  } else if (ex_data->sec_ops == SC_SEC_OPERATION_AUTHENTICATE) {
1823
12
    size_t tmp_len;
1824
12
    CHECK_NOT_SUPPORTED_V3_4(card);
1825
    /* call INTERNAL AUTHENTICATE */
1826
12
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x10, 0x00);
1827
    /* fix/create DigestInfo structure (if necessary) */
1828
12
    if (ex_data->fix_digestInfo) {
1829
12
      unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES;
1830
12
      if (flags == 0x0)
1831
        /* XXX: assume no hash is wanted */
1832
0
        flags = SC_ALGORITHM_RSA_HASH_NONE;
1833
12
      tmp_len = sizeof(sbuf);
1834
12
      r = sc_pkcs1_encode(card->ctx, flags, data, datalen,
1835
12
          sbuf, &tmp_len, sizeof(sbuf)*8, NULL);
1836
12
      if (r < 0)
1837
0
        return r;
1838
12
    } else {
1839
0
      memcpy(sbuf, data, datalen);
1840
0
      tmp_len = datalen;
1841
0
    }
1842
12
    apdu.lc = tmp_len;
1843
12
    apdu.data = sbuf;
1844
12
    apdu.datalen = tmp_len;
1845
12
    apdu.resp = rbuf;
1846
12
    apdu.resplen = sizeof(rbuf);
1847
12
    apdu.le = 256;
1848
12
    r = sc_transmit_apdu(card, &apdu);
1849
12
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1850
11
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
1851
2
      size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
1852
1853
2
      memcpy(out, apdu.resp, len);
1854
2
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
1855
2
    }
1856
11
  } else
1857
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1858
1859
  /* clear old state */
1860
15
  ex_data->sec_ops = 0;
1861
15
  ex_data->fix_digestInfo = 0;
1862
1863
15
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
1864
15
}
1865
1866
static int starcos_decipher(struct sc_card *card,
1867
    const u8 * crgram, size_t crgram_len,
1868
    u8 * out, size_t outlen)
1869
2
{
1870
2
  int r;
1871
2
  size_t card_max_send_size = card->max_send_size;
1872
2
  size_t reader_max_send_size = card->reader->max_send_size;
1873
2
  size_t card_max_recv_size = card->max_recv_size;
1874
2
  size_t reader_max_recv_size = card->reader->max_recv_size;
1875
1876
2
  if (sc_get_max_send_size(card) < crgram_len + 1) {
1877
    /* Starcos doesn't support chaining for PSO:DEC, so we just _hope_
1878
     * that both, the reader and the card are able to send enough data.
1879
     * (data is prefixed with 1 byte padding content indicator) */
1880
0
    card->max_send_size = crgram_len + 1;
1881
0
    card->reader->max_send_size = crgram_len + 1;
1882
0
  }
1883
1884
2
  if (sc_get_max_recv_size(card) < outlen) {
1885
    /* Starcos doesn't support get response for PSO:DEC, so we just _hope_
1886
     * that both, the reader and the card are able to receive enough data.
1887
     */
1888
2
    if (0 == (card->caps & SC_CARD_CAP_APDU_EXT)
1889
2
        && outlen > 256) {
1890
2
      card->max_recv_size = 256;
1891
2
      card->reader->max_recv_size = 256;
1892
2
    } else {
1893
0
      card->max_recv_size = outlen;
1894
0
      card->reader->max_recv_size = outlen;
1895
0
    }
1896
2
  }
1897
1898
2
  if ( IS_V3x(card) ) {
1899
2
    sc_apdu_t apdu;
1900
1901
2
    u8 *sbuf = malloc(crgram_len + 1);
1902
2
    if (sbuf == NULL)
1903
0
      return SC_ERROR_OUT_OF_MEMORY;
1904
1905
2
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
1906
2
    apdu.resp    = out;
1907
2
    apdu.resplen = outlen;
1908
2
    apdu.le      = outlen;
1909
1910
2
    sbuf[0] = 0x81;
1911
2
    memcpy(sbuf + 1, crgram, crgram_len);
1912
2
    apdu.data = sbuf;
1913
2
    apdu.lc = crgram_len + 1;
1914
2
    apdu.datalen = crgram_len + 1;
1915
1916
2
    r = sc_transmit_apdu(card, &apdu);
1917
2
    sc_mem_clear(sbuf, crgram_len + 1);
1918
1919
2
    free(sbuf);
1920
1921
2
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1922
1923
0
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
1924
0
      r = (int)apdu.resplen;
1925
0
    else
1926
0
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1927
0
  } else {
1928
0
    r = iso_ops->decipher(card, crgram, crgram_len, out, outlen);
1929
0
  }
1930
1931
  /* reset whatever we've modified above */
1932
0
  card->max_send_size = card_max_send_size;
1933
0
  card->reader->max_send_size = reader_max_send_size;
1934
0
  card->max_recv_size = card_max_recv_size;
1935
0
  card->reader->max_recv_size = reader_max_recv_size;
1936
1937
0
  LOG_FUNC_RETURN(card->ctx, r);
1938
0
}
1939
1940
static int starcos_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
1941
12.8k
{
1942
12.8k
  const int err_count = sizeof(starcos_errors)/sizeof(starcos_errors[0]);
1943
12.8k
  int i;
1944
1945
12.8k
  sc_log(card->ctx,
1946
12.8k
    "sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
1947
1948
12.8k
  if (sw1 == 0x90 && sw2 == 0x00)
1949
4.93k
    return SC_SUCCESS;
1950
7.88k
  if (sw1 == 0x63 && (sw2 & ~0x0fU) == 0xc0 )
1951
39
  {
1952
39
    sc_log(card->ctx,  "Verification failed (remaining tries: %d)\n",
1953
39
    (sw2 & 0x0f));
1954
39
    return SC_ERROR_PIN_CODE_INCORRECT;
1955
39
  }
1956
1957
  /* check starcos error messages */
1958
116k
  for (i = 0; i < err_count; i++)
1959
109k
    if (starcos_errors[i].SWs == ((sw1 << 8) | sw2))
1960
47
    {
1961
47
      sc_log(card->ctx,  "%s\n", starcos_errors[i].errorstr);
1962
47
      return starcos_errors[i].errorno;
1963
47
    }
1964
1965
  /* iso error */
1966
7.79k
  return iso_ops->check_sw(card, sw1, sw2);
1967
7.84k
}
1968
1969
static int starcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
1970
299
{
1971
299
  int r;
1972
299
  u8  rbuf[SC_MAX_APDU_BUFFER_SIZE];
1973
299
  sc_apdu_t apdu;
1974
1975
299
  if (!serial)
1976
0
    return SC_ERROR_INVALID_ARGUMENTS;
1977
1978
  /* see if we have cached serial number */
1979
299
  if (card->serialnr.len) {
1980
31
    memcpy(serial, &card->serialnr, sizeof(*serial));
1981
31
    return SC_SUCCESS;
1982
31
  }
1983
1984
268
  if ( IS_V3x(card) ) {
1985
93
    card->serialnr.len = SC_MAX_SERIALNR;
1986
93
    r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0);
1987
93
    if (r < 0) {
1988
85
      card->serialnr.len = 0;
1989
85
      return r;
1990
85
    }
1991
175
  } else {
1992
    /* get serial number via GET CARD DATA */
1993
175
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00);
1994
175
    apdu.cla |= 0x80;
1995
175
    apdu.resp = rbuf;
1996
175
    apdu.resplen = sizeof(rbuf);
1997
175
    apdu.le   = 256;
1998
175
    apdu.lc   = 0;
1999
175
    apdu.datalen = 0;
2000
175
    r = sc_transmit_apdu(card, &apdu);
2001
175
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
2002
162
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
2003
36
      return SC_ERROR_INTERNAL;
2004
    /* cache serial number */
2005
126
    memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR));
2006
126
    card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR);
2007
126
  }
2008
2009
  /* copy and return serial number */
2010
134
  memcpy(serial, &card->serialnr, sizeof(*serial));
2011
2012
134
  return SC_SUCCESS;
2013
268
}
2014
2015
static int starcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
2016
500
{
2017
500
  sc_starcos_create_data *tmp;
2018
2019
500
  switch (cmd)
2020
500
  {
2021
0
  case SC_CARDCTL_STARCOS_CREATE_FILE:
2022
0
    tmp = (sc_starcos_create_data *) ptr;
2023
0
    if (tmp->type == SC_STARCOS_MF_DATA)
2024
0
      return starcos_create_mf(card, tmp);
2025
0
    else if (tmp->type == SC_STARCOS_DF_DATA)
2026
0
      return starcos_create_df(card, tmp);
2027
0
    else if (tmp->type == SC_STARCOS_EF_DATA)
2028
0
      return starcos_create_ef(card, tmp);
2029
0
    else
2030
0
      return SC_ERROR_INTERNAL;
2031
0
  case SC_CARDCTL_STARCOS_CREATE_END:
2032
0
    return starcos_create_end(card, (sc_file_t *)ptr);
2033
0
  case SC_CARDCTL_STARCOS_WRITE_KEY:
2034
0
    return starcos_write_key(card, (sc_starcos_wkey_data *)ptr);
2035
0
  case SC_CARDCTL_STARCOS_GENERATE_KEY:
2036
0
    return starcos_gen_key(card, (sc_starcos_gen_key_data *)ptr);
2037
0
  case SC_CARDCTL_ERASE_CARD:
2038
0
    return starcos_erase_card(card);
2039
299
  case SC_CARDCTL_GET_SERIALNR:
2040
299
    return starcos_get_serialnr(card, (sc_serial_number_t *)ptr);
2041
201
  default:
2042
201
    return SC_ERROR_NOT_SUPPORTED;
2043
500
  }
2044
500
}
2045
2046
static int starcos_logout_v3_x(sc_card_t *card)
2047
0
{
2048
0
  return SC_ERROR_NOT_SUPPORTED;
2049
0
}
2050
2051
static int starcos_logout(sc_card_t *card)
2052
0
{
2053
0
  int r;
2054
0
  sc_apdu_t apdu;
2055
0
  const u8 mf_buf[2] = {0x3f, 0x00};
2056
2057
0
  if ( IS_V3x(card) ) {
2058
0
    return starcos_logout_v3_x(card);
2059
0
  }
2060
2061
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
2062
0
  apdu.le = 0;
2063
0
  apdu.lc = 2;
2064
0
  apdu.data    = mf_buf;
2065
0
  apdu.datalen = 2;
2066
0
  apdu.resplen = 0;
2067
2068
0
  r = sc_transmit_apdu(card, &apdu);
2069
0
  LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
2070
2071
0
  if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85)
2072
    /* the only possible reason for this error here is, afaik,
2073
     * that no MF exists, but then there's no need to logout
2074
     * => return SC_SUCCESS
2075
     */
2076
0
    return SC_SUCCESS;
2077
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
2078
0
}
2079
2080
static int starcos_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data)
2081
211
{
2082
211
  int r;
2083
2084
211
  LOG_FUNC_CALLED(card->ctx);
2085
211
  starcos_ex_data * ex_data = (starcos_ex_data*)card->drv_data;
2086
211
  if ( IS_V3x(card) ) {
2087
144
    data->flags |= SC_PIN_CMD_NEED_PADDING;
2088
144
    data->pin1.encoding = ex_data->pin_encoding;
2089
144
  }
2090
211
  r = iso_ops->pin_cmd(card, data);
2091
211
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
2092
211
}
2093
2094
static struct sc_card_driver * sc_get_driver(void)
2095
15.7k
{
2096
15.7k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
2097
15.7k
  if (iso_ops == NULL)
2098
1
    iso_ops = iso_drv->ops;
2099
2100
15.7k
  starcos_ops = *iso_drv->ops;
2101
15.7k
  starcos_ops.match_card = starcos_match_card;
2102
15.7k
  starcos_ops.init   = starcos_init;
2103
15.7k
  starcos_ops.finish = starcos_finish;
2104
15.7k
  starcos_ops.select_file = starcos_select_file;
2105
15.7k
  starcos_ops.get_challenge = starcos_get_challenge;
2106
15.7k
  starcos_ops.check_sw    = starcos_check_sw;
2107
15.7k
  starcos_ops.create_file = starcos_create_file;
2108
15.7k
  starcos_ops.delete_file = NULL;
2109
15.7k
  starcos_ops.set_security_env  = starcos_set_security_env;
2110
15.7k
  starcos_ops.compute_signature = starcos_compute_signature;
2111
15.7k
  starcos_ops.decipher = starcos_decipher;
2112
15.7k
  starcos_ops.card_ctl    = starcos_card_ctl;
2113
15.7k
  starcos_ops.logout      = starcos_logout;
2114
15.7k
  starcos_ops.pin_cmd     = starcos_pin_cmd;
2115
2116
15.7k
  return &starcos_drv;
2117
15.7k
}
2118
2119
struct sc_card_driver * sc_get_starcos_driver(void)
2120
15.7k
{
2121
15.7k
  return sc_get_driver();
2122
15.7k
}