Coverage Report

Created: 2025-07-01 06:08

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