Coverage Report

Created: 2026-09-03 06:08

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