Coverage Report

Created: 2025-07-18 06:10

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