Coverage Report

Created: 2026-01-09 06:46

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.16k
#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.43k
#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
723
#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
7.62k
#define IS_V34(card) card->type == SC_CARD_TYPE_STARCOS_V3_4 || card->type == SC_CARD_TYPE_STARCOS_V3_4_ESIGN
120
2.28k
#define IS_V35(card) card->type == SC_CARD_TYPE_STARCOS_V3_5 || card->type == SC_CARD_TYPE_STARCOS_V3_5_ESIGN
121
10.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
8.82k
{
126
8.82k
  int i;
127
128
8.82k
  i = _sc_match_atr(card, starcos_atrs, &card->type);
129
8.82k
  if (i < 0)
130
8.10k
    return 0;
131
723
  return 1;
132
8.82k
}
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
3.44k
#define TAG_STARCOS35_PIN_REFERENCE         0x88
146
450
#define TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag    0x7B
147
24
#define TAG_STARCOS3X_CTRL_REF_TEMPLATE       0xA4
148
24
#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
450
{
159
450
  struct sc_context *ctx = card->ctx;
160
450
  const unsigned char *supported_sec_mechanisms_tag = NULL;
161
450
  size_t taglen;
162
163
450
  LOG_FUNC_CALLED(ctx);
164
165
450
  supported_sec_mechanisms_tag = sc_asn1_find_tag(ctx, buf, buflen, TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag, &taglen);
166
450
  if (supported_sec_mechanisms_tag != NULL && taglen >= 1)   {
167
24
    const unsigned char *tx_fmt_tag = NULL;
168
24
    const unsigned char *ctrl_ref_template_tag = NULL;
169
24
    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
24
    ctrl_ref_template_tag = sc_asn1_find_tag(ctx, supported_sec_mechanisms_tag, taglen, TAG_STARCOS3X_CTRL_REF_TEMPLATE, &taglen);
173
24
    if ( ctrl_ref_template_tag == NULL || taglen == 0 ) {
174
16
      ctrl_ref_template_tag = supported_sec_mechanisms_tag;
175
16
      taglen = supported_sec_mechanisms_taglen;
176
16
    }
177
178
24
    tx_fmt_tag = sc_asn1_find_tag(ctx, ctrl_ref_template_tag, taglen, TAG_STARCOS3X_TRANSMISSION_FORMAT, &taglen);
179
24
    if ( tx_fmt_tag != NULL && taglen >= 1 ) {
180
11
      ctrl_ref_template->transmission_format = *(tx_fmt_tag + 0);
181
11
      LOG_FUNC_RETURN(ctx, SC_SUCCESS);
182
11
    }
183
24
  }
184
185
439
  LOG_FUNC_RETURN(ctx, SC_ERROR_TEMPLATE_NOT_FOUND);
186
439
}
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
77
  if ( (rv = sc_read_record(card, rec_no, 0, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
205
38
    starcos_ctrl_ref_template ctrl_ref_template;
206
38
    memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
207
38
    rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
208
38
    if ( rv == SC_SUCCESS ) {
209
11
      *pin_format = ctrl_ref_template.transmission_format;
210
11
      sc_log(ctx, "Determined StarCOS 3.4 PIN format: 0x%x", *pin_format);
211
27
    } else {
212
27
      sc_log(ctx, "Failed to parse record %d of EF.PWD, err=%d", rec_no, rv);
213
27
      retval = rv;
214
27
    }
215
39
  } else {
216
39
    sc_log(ctx, "Failed to read record %d of EF.PWDD, err=%d", rec_no, rv);
217
39
    retval = rv;
218
39
  }
219
220
77
  sc_file_free(file);
221
77
  LOG_FUNC_RETURN(ctx, retval);
222
77
}
223
224
static int starcos_determine_pin_format35(sc_card_t *card, unsigned int * pin_format)
225
162
{
226
162
  struct sc_context *ctx = card->ctx;
227
162
  struct sc_path path;
228
162
  struct sc_file *file;
229
162
  unsigned char buf[256];
230
162
  int rv;
231
162
  int retval = SC_ERROR_RECORD_NOT_FOUND;
232
162
  int rec_no=1;
233
162
  starcos_ctrl_ref_template ctrl_ref_template;
234
235
162
  LOG_FUNC_CALLED(ctx);
236
237
162
  sc_format_path(starcos_ef_keyd, &path);
238
162
  rv = sc_select_file(card, &path, &file);
239
162
  LOG_TEST_RET(ctx, rv, "Cannot select EF.KEYD file");
240
241
3.58k
  while ( (rv = sc_read_record(card, rec_no++, 0, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
242
3.44k
    if ( buf[0] != TAG_STARCOS35_PIN_REFERENCE ) continue;
243
244
412
    memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
245
412
    rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
246
412
    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
412
    } else {
253
412
      sc_log(ctx, "Failed to parse record %d of EF.KEYD, err=%d", rec_no-1, rv);
254
412
      retval = rv;
255
412
    }
256
412
  }
257
258
143
  sc_file_free(file);
259
143
  LOG_FUNC_RETURN(ctx, retval);
260
143
}
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
723
{
270
723
  unsigned int pin_format = PIN_FORMAT_DEFAULT;
271
723
  unsigned int encoding = PIN_ENCODING_DETERMINE;
272
273
723
  if ( IS_V34(card) ) {
274
460
    starcos_determine_pin_format34(card, &pin_format);
275
460
  } else if ( IS_V35(card) ) {
276
162
    starcos_determine_pin_format35(card, &pin_format);
277
162
  }
278
279
723
  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
713
  case PIN_FORMAT_F2:
289
713
    encoding = SC_PIN_ENCODING_GLP;
290
713
    break;
291
723
  }
292
293
723
  sc_log(card->ctx, "Determined PIN encoding: %d", encoding);
294
723
  return encoding;
295
723
}
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
53
static int starcos_probe_reader_for_ext_apdu(sc_card_t * card) {
302
53
  sc_apdu_t apdu;
303
53
  int rv;
304
  /* try to read STARCOS3X_PROBE_APDU_LENGTH bytes */
305
53
  u8 data[STARCOS3X_PROBE_APDU_LENGTH];
306
307
  /* Get Data: Get Chip Serial Number */
308
53
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, 0xCA, 0x9F, 0x6C);
309
53
  apdu.cla = 0xA0;
310
53
  apdu.resp = data;
311
53
  apdu.resplen = sizeof(data);
312
53
  apdu.le = apdu.resplen;
313
53
  rv = sc_transmit_apdu(card, &apdu);
314
53
  LOG_TEST_RET(card->ctx, rv, "Failed to send Get Data ext. APDU");
315
46
  return (apdu.sw1 == 0x90 && apdu.sw2 == 0x00);
316
53
}
317
318
461
static int starcos_select_mf(sc_card_t * card) {
319
461
  sc_apdu_t apdu;
320
461
  const u8 mf_buf[2] = {0x3f, 0x00};
321
322
461
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
323
461
  apdu.le = 0;
324
461
  apdu.lc = 2;
325
461
  apdu.data    = mf_buf;
326
461
  apdu.datalen = 2;
327
461
  apdu.resplen = 0;
328
329
461
  return sc_transmit_apdu(card, &apdu);
330
461
}
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
459
    u8 aid[SC_MAX_PATH_SIZE];
346
459
    size_t len = sizeof(aid);
347
348
459
    rv = sc_hex_to_bin(starcos_esign_aid, aid, &len);
349
459
    LOG_TEST_RET(card->ctx, rv, "Failed to convert eSing AID");
350
459
    rv = starcos_select_aid(card, aid, len, NULL);
351
459
    if ( rv == SC_SUCCESS ) {
352
1
      starcos_select_mf(card);
353
1
    }
354
459
  }
355
460
  return ( rv == SC_SUCCESS );
356
460
}
357
358
static int starcos_init(sc_card_t *card)
359
723
{
360
723
  unsigned int flags;
361
723
  starcos_ex_data *ex_data;
362
363
723
  ex_data = calloc(1, sizeof(starcos_ex_data));
364
723
  if (ex_data == NULL)
365
0
    return SC_ERROR_OUT_OF_MEMORY;
366
367
723
  card->name = "STARCOS";
368
723
  card->cla  = 0x00;
369
723
  card->drv_data = (void *)ex_data;
370
723
  ex_data->pin_encoding = PIN_ENCODING_DETERMINE;
371
372
723
  flags = SC_ALGORITHM_RSA_PAD_PKCS1
373
723
    | SC_ALGORITHM_ONBOARD_KEY_GEN
374
723
    | SC_ALGORITHM_RSA_PAD_ISO9796
375
723
    | SC_ALGORITHM_RSA_HASH_NONE
376
723
    | SC_ALGORITHM_RSA_HASH_SHA1
377
723
    | SC_ALGORITHM_RSA_HASH_MD5
378
723
    | SC_ALGORITHM_RSA_HASH_RIPEMD160
379
723
    | SC_ALGORITHM_RSA_HASH_MD5_SHA1;
380
381
723
  card->caps = SC_CARD_CAP_RNG;
382
383
723
  if ( IS_V3x(card) ) {
384
385
622
    flags |= SC_CARD_FLAG_RNG
386
622
      | SC_ALGORITHM_RSA_HASH_SHA224
387
622
      | SC_ALGORITHM_RSA_HASH_SHA256
388
622
      | SC_ALGORITHM_RSA_HASH_SHA384
389
622
      | SC_ALGORITHM_RSA_HASH_SHA512
390
622
      | SC_ALGORITHM_RSA_PAD_PSS;
391
392
622
    _sc_card_add_rsa_alg(card, 512, flags, 0x10001);
393
622
    _sc_card_add_rsa_alg(card, 768, flags, 0x10001);
394
622
    _sc_card_add_rsa_alg(card,1024, flags, 0x10001);
395
622
    _sc_card_add_rsa_alg(card,1728, flags, 0x10001);
396
622
    _sc_card_add_rsa_alg(card,1976, flags, 0x10001);
397
622
    _sc_card_add_rsa_alg(card,2048, flags, 0x10001);
398
622
    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
162
      card->name = "STARCOS 3.5";
403
162
      _sc_card_add_rsa_alg(card,3072, flags, 0x10001);
404
162
    }
405
622
    card->max_send_size = 255;
406
622
    card->max_recv_size = 256;
407
622
  } else {
408
101
    _sc_card_add_rsa_alg(card, 512, flags, 0x10001);
409
101
    _sc_card_add_rsa_alg(card, 768, flags, 0x10001);
410
101
    _sc_card_add_rsa_alg(card,1024, flags, 0x10001);
411
412
    /* we need read_binary&friends with max 128 bytes per read */
413
101
    card->max_send_size = 128;
414
101
    card->max_recv_size = 128;
415
101
  }
416
417
723
  if (sc_parse_ef_atr(card) == SC_SUCCESS) {
418
167
    size_t max_recv_size = 0;
419
167
    size_t max_send_size = 0;
420
421
    /* Add max. length values from IAS/ECC specific issuer data */
422
167
    if ( card->ef_atr->issuer_data_len >= 4 ) {
423
55
      max_recv_size = bebytes2ushort(card->ef_atr->issuer_data);
424
55
      max_send_size = bebytes2ushort(card->ef_atr->issuer_data + 2);
425
55
    }
426
    /* which could be overridden with ISO7816 EF.ATR options, if present */
427
167
    if (card->ef_atr->max_response_apdu > 0) {
428
11
      max_recv_size = card->ef_atr->max_response_apdu;
429
11
    }
430
167
    if (card->ef_atr->max_command_apdu > 0) {
431
12
      max_send_size = card->ef_atr->max_command_apdu;
432
12
    }
433
434
167
    if ( max_send_size > 256 && max_recv_size > 256 ) {
435
53
      size_t max_recv_size_prev = card->max_recv_size;
436
53
      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
53
      card->caps |= SC_CARD_CAP_APDU_EXT;
439
      /* the received data should not exceed max_recv_size including the sw1/sw2 */
440
53
      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
53
      card->max_send_size = max_send_size - 10;
443
      /* probe reader for extended APDU support */
444
53
      if ( starcos_probe_reader_for_ext_apdu(card) ) {
445
15
        sc_log(card->ctx, "Successfully probed extended APDU, enabling extended APDU with max send/recv %d/%d",
446
15
          (int)card->max_send_size, (int)card->max_recv_size);
447
38
      } else {
448
38
        card->caps &= ~(SC_CARD_CAP_APDU_EXT);
449
38
        card->max_recv_size = max_recv_size_prev;
450
38
        card->max_send_size = max_send_size_prev;
451
38
        sc_log(card->ctx, "Ext APDU probing failed, the actual reader does not support ext APDU");
452
38
      }
453
53
    }
454
167
  }
455
456
723
  if ( ex_data->pin_encoding == PIN_ENCODING_DETERMINE ) {
457
    // about to determine PIN encoding
458
723
    ex_data->pin_encoding = starcos_determine_pin_encoding(card);
459
723
  }
460
461
723
  if ( card->type == SC_CARD_TYPE_STARCOS_V3_4 && starcos_has_esign_app(card) ) {
462
1
    card->type = SC_CARD_TYPE_STARCOS_V3_4_ESIGN;
463
1
    sc_log(card->ctx, "Card has eSign app, card type changed to %d", card->type);
464
1
  }
465
466
723
  return 0;
467
723
}
468
469
static int starcos_finish(sc_card_t *card)
470
723
{
471
723
  if (card->drv_data)
472
723
    free((starcos_ex_data *)card->drv_data);
473
723
  return 0;
474
723
}
475
476
static int process_fci(sc_context_t *ctx, sc_file_t *file,
477
           const u8 *buf, size_t buflen)
478
49
{
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
49
  size_t taglen, len = buflen;
486
49
  const u8 *tag = NULL, *p;
487
488
49
  sc_log(ctx,  "processing FCI bytes\n");
489
490
49
  if (buflen < 2)
491
1
    return SC_ERROR_INTERNAL;
492
48
  if (buf[0] != 0x6f)
493
2
    return SC_ERROR_INVALID_DATA;
494
46
  len = (size_t)buf[1];
495
46
  if (buflen - 2 < len)
496
8
    return SC_ERROR_INVALID_DATA;
497
38
  p = buf + 2;
498
499
  /* defaults */
500
38
  file->type = SC_FILE_TYPE_WORKING_EF;
501
38
  file->ef_structure = SC_FILE_EF_UNKNOWN;
502
38
  file->shareable = 0;
503
38
  file->record_length = 0;
504
38
  file->size = 0;
505
506
38
  tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
507
38
  if (tag != NULL && taglen >= 2) {
508
2
    int bytes = (tag[0] << 8) + tag[1];
509
2
    sc_log(ctx,
510
2
      "  bytes in file: %d\n", bytes);
511
2
    file->size = bytes;
512
2
  }
513
514
38
  tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
515
38
  if (tag != NULL) {
516
24
    const char *type = "unknown";
517
24
    const char *structure = "unknown";
518
519
24
    if (taglen == 1 && tag[0] == 0x01) {
520
      /* transparent EF */
521
1
      type = "working EF";
522
1
      structure = "transparent";
523
1
      file->type = SC_FILE_TYPE_WORKING_EF;
524
1
      file->ef_structure = SC_FILE_EF_TRANSPARENT;
525
23
    } else if (taglen == 1 && tag[0] == 0x11) {
526
      /* object EF */
527
1
      type = "working EF";
528
1
      structure = "object";
529
1
      file->type = SC_FILE_TYPE_WORKING_EF;
530
1
      file->ef_structure = SC_FILE_EF_TRANSPARENT; /* TODO */
531
22
    } else if (taglen == 3 && tag[1] == 0x21) {
532
4
      type = "working EF";
533
4
      file->record_length = tag[2];
534
4
      file->type = SC_FILE_TYPE_WORKING_EF;
535
      /* linear fixed, cyclic or compute */
536
4
      switch ( tag[0] )
537
4
      {
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
1
        default:
551
1
          structure = "unknown";
552
1
          file->ef_structure = SC_FILE_EF_UNKNOWN;
553
1
          file->record_length = 0;
554
1
          break;
555
4
      }
556
4
    }
557
558
24
    sc_log(ctx,
559
24
      "  type: %s\n", type);
560
24
    sc_log(ctx,
561
24
      "  EF structure: %s\n", structure);
562
24
  }
563
38
  file->magic = SC_FILE_MAGIC;
564
565
38
  return SC_SUCCESS;
566
38
}
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
191
{
607
191
  size_t taglen, len = buflen;
608
191
  const u8 *tag = NULL, *p;
609
610
191
  sc_log(ctx,
611
191
     "processing %"SC_FORMAT_LEN_SIZE_T"u FCP bytes\n", buflen);
612
613
191
  if (buflen < 2)
614
16
    return SC_ERROR_INTERNAL;
615
175
  if (buf[0] != 0x62)
616
15
    return SC_ERROR_INVALID_DATA;
617
160
  len = (size_t)buf[1];
618
160
  if (buflen - 2 < len)
619
5
    return SC_ERROR_INVALID_DATA;
620
155
  p = buf + 2;
621
622
155
  tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
623
155
  if (tag != NULL && taglen >= 2) {
624
21
    int bytes = (tag[0] << 8) + tag[1];
625
21
    sc_log(ctx,
626
21
      "  bytes in file: %d\n", bytes);
627
21
    file->size = bytes;
628
21
  }
629
630
155
  tag = sc_asn1_find_tag(ctx, p, len, 0xc5, &taglen);
631
155
  if (tag != NULL && taglen >= 2) {
632
8
    int bytes = (tag[0] << 8) + tag[1];
633
8
    sc_log(ctx,
634
8
      "  bytes in file 2: %d\n", bytes);
635
8
    file->size = bytes;
636
8
  }
637
638
155
  tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
639
155
  if (tag != NULL) {
640
39
    const char *type = "unknown";
641
39
    const char *structure = "unknown";
642
643
39
    if (taglen >= 1) {
644
34
      unsigned char byte = tag[0];
645
34
      if (byte & 0x40) {
646
13
        file->shareable = 1;
647
13
      }
648
34
      if (byte == 0x38) {
649
4
        type = "DF";
650
4
        file->type = SC_FILE_TYPE_DF;
651
4
        file->shareable = 1;
652
4
      }
653
34
      switch (byte & 7) {
654
5
      case 1:
655
        /* transparent EF */
656
5
        type = "working EF";
657
5
        structure = "transparent";
658
5
        file->type = SC_FILE_TYPE_WORKING_EF;
659
5
        file->ef_structure = SC_FILE_EF_TRANSPARENT;
660
5
        break;
661
4
      case 2:
662
        /* linear fixed EF */
663
4
        type = "working EF";
664
4
        structure = "linear fixed";
665
4
        file->type = SC_FILE_TYPE_WORKING_EF;
666
4
        file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
667
4
        break;
668
4
      case 4:
669
        /* linear variable EF */
670
4
        type = "working EF";
671
4
        structure = "linear variable";
672
4
        file->type = SC_FILE_TYPE_WORKING_EF;
673
4
        file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
674
4
        break;
675
7
      case 6:
676
        /* cyclic EF */
677
7
        type = "working EF";
678
7
        structure = "cyclic";
679
7
        file->type = SC_FILE_TYPE_WORKING_EF;
680
7
        file->ef_structure = SC_FILE_EF_CYCLIC;
681
7
        break;
682
14
      default:
683
        /* use defaults from above */
684
14
        break;
685
34
      }
686
34
    }
687
39
    sc_log(ctx,
688
39
      "  type: %s\n", type);
689
39
    sc_log(ctx,
690
39
      "  EF structure: %s\n", structure);
691
39
    if (taglen >= 2) {
692
31
      if (tag[1] != 0x41 || taglen != 5) {
693
31
        SC_FUNC_RETURN(ctx, 2,SC_ERROR_INVALID_DATA);
694
31
      }
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
39
  }
703
704
124
  tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
705
124
  if (tag != NULL && taglen >= 2) {
706
3
    file->id = (tag[0] << 8) | tag[1];
707
3
    sc_log(ctx,  "  file identifier: 0x%02X%02X\n",
708
3
      tag[0], tag[1]);
709
3
  }
710
711
124
  tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
712
124
  if (tag != NULL && taglen > 0 && taglen <= 16) {
713
3
    memcpy(file->name, tag, taglen);
714
3
    file->namelen = taglen;
715
3
    sc_log(ctx,  "  filename %s",
716
3
      sc_dump_hex(file->name, file->namelen));
717
3
  }
718
719
124
  tag = sc_asn1_find_tag(ctx, p, len, 0x8a, &taglen);
720
124
  if (tag != NULL && taglen == 1) {
721
16
    char* status = "unknown";
722
16
    switch (tag[0]) {
723
4
    case 1:
724
4
      status = "creation";
725
4
      file->status = SC_FILE_STATUS_CREATION;
726
4
      break;
727
3
    case 5:
728
3
      status = "operational active";
729
3
      file->status = SC_FILE_STATUS_ACTIVATED;
730
3
      break;
731
3
    case 12:
732
6
    case 13:
733
6
      status = "creation";
734
6
      file->status = SC_FILE_STATUS_INVALIDATED;
735
6
      break;
736
3
    default:
737
3
      break;
738
16
    }
739
16
    sc_log(ctx,  "  file status: %s\n", status);
740
16
  }
741
742
124
  file->magic = SC_FILE_MAGIC;
743
124
  return SC_SUCCESS;
744
124
}
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
459
{
750
459
  sc_apdu_t apdu;
751
459
  int r;
752
459
  size_t i = 0;
753
754
459
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
755
459
  apdu.lc = len;
756
459
  apdu.data = (u8*)aid;
757
459
  apdu.datalen = len;
758
459
  apdu.resplen = 0;
759
459
  apdu.le = 0;
760
459
  r = sc_transmit_apdu(card, &apdu);
761
459
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
762
763
  /* check return value */
764
458
  if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 )
765
457
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
766
767
1
  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
1
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
785
1
}
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
1.99k
{
791
1.99k
  sc_apdu_t apdu;
792
1.99k
  u8 data[] = {id_hi & 0xff, id_lo & 0xff};
793
1.99k
  u8 resp[SC_MAX_APDU_BUFFER_SIZE];
794
1.99k
  int bIsDF = 0, r;
795
1.99k
  int isFCP = 0;
796
1.99k
  int isMF = 0;
797
798
  /* request FCI to distinguish between EFs and DFs */
799
1.99k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00);
800
1.99k
  apdu.p2   = 0x00;
801
1.99k
  apdu.resp = (u8*)resp;
802
1.99k
  apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
803
1.99k
  apdu.le = 256;
804
1.99k
  apdu.lc = 2;
805
1.99k
  apdu.data = (u8*)data;
806
1.99k
  apdu.datalen = 2;
807
808
1.99k
  if ( IS_V3x(card) ) {
809
1.83k
    if (id_hi == 0x3f && id_lo == 0x0) {
810
1.24k
      apdu.p1 = 0x0;
811
1.24k
      apdu.p2 = 0x0C;
812
1.24k
      apdu.le = 0;
813
1.24k
      apdu.resplen = 0;
814
1.24k
      apdu.resp = NULL;
815
1.24k
      apdu.cse = SC_APDU_CASE_3_SHORT;
816
1.24k
      isMF = 1;
817
1.24k
    } else if (file_out || is_file) {
818
      // last component (i.e. file or path)
819
586
      apdu.p1 = 0x2;
820
586
      apdu.p2 = 0x4;
821
586
    } else {
822
      // path component
823
0
      apdu.p1 = 0x1;
824
0
      apdu.p2 = 0x0;
825
0
    }
826
1.83k
  }
827
828
1.99k
  r = sc_transmit_apdu(card, &apdu);
829
1.99k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
830
831
1.98k
  if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) {
832
    /* no FCI => we have a DF (see comment in process_fci()) */
833
4
    bIsDF = 1;
834
4
    apdu.p2 = 0x0C;
835
4
    apdu.cse = SC_APDU_CASE_3_SHORT;
836
4
    apdu.resplen = 0;
837
4
    apdu.le = 0;
838
4
    r = sc_transmit_apdu(card, &apdu);
839
4
    LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
840
1.97k
  } else if ((IS_V3x(card))
841
1.82k
      && apdu.p2 == 0x4 && apdu.sw1 == 0x6a && apdu.sw2 == 0x82) {
842
    /* not a file, could be a path */
843
207
    bIsDF = 1;
844
207
    apdu.p1 = 0x1;
845
207
    apdu.p2 = 0x0;
846
207
    apdu.resplen = sizeof(resp);
847
207
    apdu.le = 256;
848
207
    apdu.lc = 2;
849
207
    r = sc_transmit_apdu(card, &apdu);
850
207
    LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
851
1.77k
  } 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
456
    sc_apdu_t apdu2;
855
456
    u8 resp2[2];
856
456
    sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0);
857
456
    apdu2.resp = (u8*)resp2;
858
456
    apdu2.resplen = 2;
859
456
    apdu2.le = 1;
860
456
    apdu2.lc = 0;
861
456
    r = sc_transmit_apdu(card, &apdu2);
862
456
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
863
448
    if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86) {
864
      /* no current EF is selected => we have a DF */
865
148
      bIsDF = 1;
866
300
    } else {
867
300
      isFCP = 1;
868
300
    }
869
448
  }
870
871
1.97k
  if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00))
872
735
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
873
874
1.23k
  if (file_out) {
875
589
    sc_file_t *file = sc_file_new();
876
589
    if (!file)
877
589
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
878
589
    file->id = (id_hi << 8) + id_lo;
879
880
589
    if (bIsDF || isMF) {
881
      /* we have a DF */
882
349
      file->type = SC_FILE_TYPE_DF;
883
349
      file->ef_structure = SC_FILE_EF_UNKNOWN;
884
349
      file->size = 0;
885
349
      file->namelen = 0;
886
349
      file->magic = SC_FILE_MAGIC;
887
349
      *file_out = file;
888
349
    } else {
889
      /* ok, assume we have a EF */
890
240
      if ( IS_V3x(card) ) {
891
191
        if (isFCP) {
892
191
          r = process_fcp_v3_4(card->ctx, file, apdu.resp,
893
191
              apdu.resplen);
894
191
        } else {
895
0
          r = process_fci_v3_4(card->ctx, file, apdu.resp,
896
0
              apdu.resplen);
897
0
        }
898
191
      } else {
899
49
        r = process_fci(card->ctx, file, apdu.resp,
900
49
            apdu.resplen);
901
49
      }
902
240
      if (r != SC_SUCCESS) {
903
78
        sc_file_free(file);
904
78
        return r;
905
78
      }
906
907
162
      *file_out = file;
908
162
    }
909
589
  }
910
911
1.15k
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
912
1.15k
}
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
1.34k
{
918
1.34k
  u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
919
1.34k
  int    r, pathtype;
920
1.34k
  size_t i, pathlen;
921
922
1.34k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
923
924
1.34k
  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
1.34k
  memcpy(path, in_path->value, in_path->len);
928
1.34k
  pathlen = in_path->len;
929
1.34k
  pathtype = in_path->type;
930
931
1.34k
  if (in_path->aid.len) {
932
0
    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
0
    } else {
940
0
      r = starcos_select_aid(card, in_path->aid.value, in_path->aid.len, NULL);
941
0
      LOG_TEST_RET(card->ctx, r, "Could not select AID!");
942
943
0
      if (pathtype == SC_PATH_TYPE_DF_NAME) {
944
0
        pathtype = SC_PATH_TYPE_FILE_ID;
945
0
      }
946
0
    }
947
0
  }
948
949
1.34k
  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
1.34k
  else if (pathtype == SC_PATH_TYPE_DF_NAME)
959
0
  { /* SELECT DF with AID */
960
    /* Select with 1-16byte Application-ID */
961
0
    r = starcos_select_aid(card, pathbuf, pathlen, file_out);
962
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
963
0
  }
964
1.34k
  else if (pathtype == SC_PATH_TYPE_PATH)
965
1.34k
  {
966
1.34k
    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
1.34k
    if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
975
0
      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
1.34k
    if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
978
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
979
980
1.34k
    if ( IS_V3x(card) ) {
981
      /* unify path (the first FID should be MF) */
982
1.24k
      if (path[0] != 0x3f || path[1] != 0x00)
983
0
      {
984
0
        n_pathbuf[0] = 0x3f;
985
0
        n_pathbuf[1] = 0x00;
986
0
        memcpy(n_pathbuf+2, path, pathlen);
987
0
        path = n_pathbuf;
988
0
        pathlen += 2;
989
0
      }
990
1.24k
    }
991
992
1.99k
    for ( i=0; i<pathlen-2; i+=2 )
993
1.34k
    {
994
1.34k
      r = starcos_select_fid(card, path[i], path[i+1], NULL, 0);
995
1.34k
      LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
996
1.34k
    }
997
647
    r = starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out, 1);
998
647
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
999
647
  }
1000
0
  else
1001
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1002
1.34k
}
1003
1004
static int starcos_get_challenge(struct sc_card *card, unsigned char *rnd, size_t len)
1005
846
{
1006
846
  LOG_FUNC_CALLED(card->ctx);
1007
1008
846
  if (len > 8) {
1009
768
    len = 8;
1010
768
  }
1011
1012
846
  LOG_FUNC_RETURN(card->ctx, iso_ops->get_challenge(card, rnd, len));
1013
846
}
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
11.7k
{
1940
11.7k
  const int err_count = sizeof(starcos_errors)/sizeof(starcos_errors[0]);
1941
11.7k
  int i;
1942
1943
11.7k
  sc_log(card->ctx,
1944
11.7k
    "sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
1945
1946
11.7k
  if (sw1 == 0x90 && sw2 == 0x00)
1947
7.97k
    return SC_SUCCESS;
1948
3.75k
  if (sw1 == 0x63 && (sw2 & ~0x0fU) == 0xc0 )
1949
12
  {
1950
12
    sc_log(card->ctx,  "Verification failed (remaining tries: %d)\n",
1951
12
    (sw2 & 0x0f));
1952
12
    return SC_ERROR_PIN_CODE_INCORRECT;
1953
12
  }
1954
1955
  /* check starcos error messages */
1956
55.1k
  for (i = 0; i < err_count; i++)
1957
51.5k
    if (starcos_errors[i].SWs == ((sw1 << 8) | sw2))
1958
71
    {
1959
71
      sc_log(card->ctx,  "%s\n", starcos_errors[i].errorstr);
1960
71
      return starcos_errors[i].errorno;
1961
71
    }
1962
1963
  /* iso error */
1964
3.67k
  return iso_ops->check_sw(card, sw1, sw2);
1965
3.74k
}
1966
1967
static int starcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
1968
0
{
1969
0
  int r;
1970
0
  u8  rbuf[SC_MAX_APDU_BUFFER_SIZE];
1971
0
  sc_apdu_t apdu;
1972
1973
0
  if (!serial)
1974
0
    return SC_ERROR_INVALID_ARGUMENTS;
1975
1976
  /* see if we have cached serial number */
1977
0
  if (card->serialnr.len) {
1978
0
    memcpy(serial, &card->serialnr, sizeof(*serial));
1979
0
    return SC_SUCCESS;
1980
0
  }
1981
1982
0
  if ( IS_V3x(card) ) {
1983
0
    card->serialnr.len = SC_MAX_SERIALNR;
1984
0
    r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0);
1985
0
    if (r < 0) {
1986
0
      card->serialnr.len = 0;
1987
0
      return r;
1988
0
    }
1989
0
  } else {
1990
    /* get serial number via GET CARD DATA */
1991
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00);
1992
0
    apdu.cla |= 0x80;
1993
0
    apdu.resp = rbuf;
1994
0
    apdu.resplen = sizeof(rbuf);
1995
0
    apdu.le   = 256;
1996
0
    apdu.lc   = 0;
1997
0
    apdu.datalen = 0;
1998
0
    r = sc_transmit_apdu(card, &apdu);
1999
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
2000
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
2001
0
      return SC_ERROR_INTERNAL;
2002
    /* cache serial number */
2003
0
    memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR));
2004
0
    card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR);
2005
0
  }
2006
2007
  /* copy and return serial number */
2008
0
  memcpy(serial, &card->serialnr, sizeof(*serial));
2009
2010
0
  return SC_SUCCESS;
2011
0
}
2012
2013
static int starcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
2014
0
{
2015
0
  sc_starcos_create_data *tmp;
2016
2017
0
  switch (cmd)
2018
0
  {
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
0
  case SC_CARDCTL_GET_SERIALNR:
2038
0
    return starcos_get_serialnr(card, (sc_serial_number_t *)ptr);
2039
0
  default:
2040
0
    return SC_ERROR_NOT_SUPPORTED;
2041
0
  }
2042
0
}
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
0
{
2081
0
  int r;
2082
2083
0
  LOG_FUNC_CALLED(card->ctx);
2084
0
  starcos_ex_data * ex_data = (starcos_ex_data*)card->drv_data;
2085
0
  if ( IS_V3x(card) ) {
2086
0
    data->flags |= SC_PIN_CMD_NEED_PADDING;
2087
0
    data->pin1.encoding = ex_data->pin_encoding;
2088
0
  }
2089
0
  r = iso_ops->pin_cmd(card, data, tries_left);
2090
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
2091
0
}
2092
2093
static struct sc_card_driver * sc_get_driver(void)
2094
9.31k
{
2095
9.31k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
2096
9.31k
  if (iso_ops == NULL)
2097
1
    iso_ops = iso_drv->ops;
2098
2099
9.31k
  starcos_ops = *iso_drv->ops;
2100
9.31k
  starcos_ops.match_card = starcos_match_card;
2101
9.31k
  starcos_ops.init   = starcos_init;
2102
9.31k
  starcos_ops.finish = starcos_finish;
2103
9.31k
  starcos_ops.select_file = starcos_select_file;
2104
9.31k
  starcos_ops.get_challenge = starcos_get_challenge;
2105
9.31k
  starcos_ops.check_sw    = starcos_check_sw;
2106
9.31k
  starcos_ops.create_file = starcos_create_file;
2107
9.31k
  starcos_ops.delete_file = NULL;
2108
9.31k
  starcos_ops.set_security_env  = starcos_set_security_env;
2109
9.31k
  starcos_ops.compute_signature = starcos_compute_signature;
2110
9.31k
  starcos_ops.decipher = starcos_decipher;
2111
9.31k
  starcos_ops.card_ctl    = starcos_card_ctl;
2112
9.31k
  starcos_ops.logout      = starcos_logout;
2113
9.31k
  starcos_ops.pin_cmd     = starcos_pin_cmd;
2114
2115
9.31k
  return &starcos_drv;
2116
9.31k
}
2117
2118
struct sc_card_driver * sc_get_starcos_driver(void)
2119
9.31k
{
2120
9.31k
  return sc_get_driver();
2121
9.31k
}