Coverage Report

Created: 2025-11-13 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-asepcos.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2007  Athena Smartcard Solutions Inc.
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 */
18
19
#ifdef HAVE_CONFIG_H
20
#include "config.h"
21
#endif
22
23
#include <ctype.h>
24
#include <string.h>
25
26
#include "internal.h"
27
#include "asn1.h"
28
#include "cardctl.h"
29
30
static const struct sc_card_operations *iso_ops = NULL;
31
32
struct sc_card_operations asepcos_ops;
33
static struct sc_card_driver asepcos_drv = {
34
  "Athena ASEPCOS",
35
  "asepcos",
36
  &asepcos_ops,
37
  NULL, 0, NULL
38
};
39
40
static const struct sc_atr_table asepcos_atrs[] = {
41
  { "3b:d6:18:00:81:b1:80:7d:1f:03:80:51:00:61:10:30:8f", NULL, NULL, SC_CARD_TYPE_ASEPCOS_GENERIC, 0, NULL},
42
  { "3b:d6:18:00:81:b1:fe:7d:1f:03:41:53:45:37:35:35:01", NULL, NULL, SC_CARD_TYPE_ASEPCOS_JAVA, 0, NULL},
43
  { NULL, NULL, NULL, 0, 0, NULL }
44
};
45
46
static int asepcos_match_card(sc_card_t *card)
47
14.0k
{
48
14.0k
  int i = _sc_match_atr(card, asepcos_atrs, &card->type);
49
14.0k
  if (i < 0)
50
14.0k
    return 0;
51
0
  return 1;
52
14.0k
}
53
54
static int asepcos_select_asepcos_applet(sc_card_t *card)
55
0
{
56
0
  static const u8 asepcos_aid[] = {0xA0,0x00,0x00,0x01,0x64,0x41,0x53,0x45,0x50,0x43,0x4F,0x53,0x00};
57
0
  sc_path_t tpath;
58
0
  int       r;
59
60
0
  memset(&tpath, 0, sizeof(sc_path_t));
61
62
0
  tpath.type = SC_PATH_TYPE_DF_NAME;
63
0
  tpath.len  = sizeof(asepcos_aid);
64
0
  memcpy(tpath.value, asepcos_aid, sizeof(asepcos_aid));
65
66
0
  r = sc_select_file(card, &tpath, NULL);
67
0
  if (r != SC_SUCCESS) {
68
0
    sc_log(card->ctx,  "unable to select ASEPCOS applet");
69
0
    return r;
70
0
  }
71
72
0
  return SC_SUCCESS;
73
0
}
74
75
static int asepcos_init(sc_card_t *card)
76
0
{
77
0
  unsigned long flags;
78
79
0
  card->name = "Athena ASEPCOS";
80
0
  card->cla  = 0x00;
81
82
  /* in case of a Java card try to select the ASEPCOS applet */
83
0
  if (card->type == SC_CARD_TYPE_ASEPCOS_JAVA) {
84
0
    int r = asepcos_select_asepcos_applet(card);
85
0
    if (r != SC_SUCCESS)
86
0
      return SC_ERROR_INVALID_CARD;
87
0
  }
88
89
  /* Set up algorithm info. */
90
0
  flags = SC_ALGORITHM_RSA_RAW
91
0
    | SC_ALGORITHM_RSA_HASH_NONE
92
0
    | SC_ALGORITHM_ONBOARD_KEY_GEN
93
0
    ;
94
0
  _sc_card_add_rsa_alg(card,  512, flags, 0);
95
0
  _sc_card_add_rsa_alg(card,  768, flags, 0);
96
0
  _sc_card_add_rsa_alg(card, 1024, flags, 0);
97
0
  _sc_card_add_rsa_alg(card, 1536, flags, 0);
98
0
  _sc_card_add_rsa_alg(card, 1792, flags, 0);
99
0
  _sc_card_add_rsa_alg(card, 2048, flags, 0);
100
101
0
  card->caps |= SC_CARD_CAP_APDU_EXT | SC_CARD_CAP_USE_FCI_AC;
102
103
0
  return SC_SUCCESS;
104
0
}
105
106
/* tables to map the asepcos access mode bytes to the OpenSC
107
 * access mode flags */
108
109
typedef struct {
110
  unsigned int am;
111
  unsigned int sc;
112
} amode_entry_t;
113
114
static const amode_entry_t df_amode_table[] = {
115
  { 0x40, SC_AC_OP_DELETE_SELF }, /* DELETE self  */
116
  { 0x01, SC_AC_OP_DELETE },  /* DELETE child */
117
  { 0x10, SC_AC_OP_INVALIDATE },  /* DEACTIVATE FILE */
118
  { 0x08, SC_AC_OP_REHABILITATE },/* ACTIVATE FILE   */
119
  { 0x04, SC_AC_OP_CREATE },  /* CREATE DF    */
120
  { 0x02, SC_AC_OP_CREATE },  /* CREATE EF    */
121
  { 0, 0 }
122
};
123
124
static const amode_entry_t wef_amode_table[] = {
125
  { 0x04, SC_AC_OP_WRITE },
126
  { 0x02, SC_AC_OP_UPDATE },
127
  { 0x01, SC_AC_OP_READ },
128
  { 0, 0 },
129
};
130
131
static const amode_entry_t ief_amode_table[] = {
132
  { 0x90, SC_AC_OP_REHABILITATE },
133
  /* UPDATE is also used when a new key is generated */
134
  { 0x82, SC_AC_OP_UPDATE },
135
  { 0, 0 },
136
};
137
138
static int set_sec_attr(sc_file_t *file, unsigned int am, unsigned int ac,
139
  unsigned int meth)
140
0
{
141
0
  const amode_entry_t *table;
142
143
        /* CHV with reference '0' is the transport PIN
144
   * and is presented as 'AUT' key with reference '0'*/
145
0
  if (meth == SC_AC_CHV && ac == 0)
146
0
    meth = SC_AC_AUT;
147
148
0
  if (file->type == SC_FILE_TYPE_DF)
149
0
    table = df_amode_table;
150
0
  else if (file->type == SC_FILE_TYPE_WORKING_EF)
151
0
    table = wef_amode_table;
152
0
  else if (file->type == SC_FILE_TYPE_INTERNAL_EF)
153
0
    table = ief_amode_table;
154
0
  else
155
0
    return SC_ERROR_INVALID_ARGUMENTS;
156
0
  for (; table->am != 0; table++) {
157
0
    if (table->am & am)
158
0
      sc_file_add_acl_entry(file, table->sc, meth, ac);
159
0
  }
160
0
  return SC_SUCCESS;
161
0
}
162
163
/* Convert asepcos security attributes to opensc access conditions.
164
 */
165
static int asepcos_parse_sec_attr(sc_card_t *card, sc_file_t *file, const u8 *buf,
166
  size_t len)
167
0
{
168
0
  const u8 *p = buf;
169
170
0
  while (len > 0) {
171
0
    unsigned int amode, tlen = 3;
172
0
    if (len < 5 || p[0] != 0x80 || p[1] != 0x01) {
173
0
      sc_log(card->ctx,  "invalid access mode encoding");
174
0
      return SC_ERROR_INTERNAL;
175
0
    }
176
0
    amode = p[2];
177
0
    if (p[3] == 0x90 && p[4] == 0x00) {
178
0
      int r = set_sec_attr(file, amode, 0, SC_AC_NONE);
179
0
      if (r != SC_SUCCESS)
180
0
        return r;
181
0
      tlen += 2;
182
0
    } else if (p[3] == 0x97 && p[4] == 0x00) {
183
0
      int r = set_sec_attr(file, amode, 0, SC_AC_NEVER);
184
0
      if (r != SC_SUCCESS)
185
0
        return r;
186
0
      tlen += 2;
187
0
    } else if (p[3] == 0xA0 && len >= 5U + p[4]) {
188
0
      if (len < 6) {
189
0
        sc_log(card->ctx,  "invalid access mode encoding");
190
0
        return SC_ERROR_INTERNAL;
191
0
      }
192
      /* TODO: support OR expressions */
193
0
      int r = set_sec_attr(file, amode, p[5], SC_AC_CHV);
194
0
      if (r != SC_SUCCESS)
195
0
        return r;
196
0
      tlen += 2 + p[4]; /* FIXME */
197
0
    } else if (p[3] == 0xAF && len >= 5U + p[4]) {
198
0
      if (len < 6) {
199
0
        sc_log(card->ctx,  "invalid access mode encoding");
200
0
        return SC_ERROR_INTERNAL;
201
0
      }
202
      /* TODO: support AND expressions */
203
0
      int r = set_sec_attr(file, amode, p[5], SC_AC_CHV);
204
0
      if (r != SC_SUCCESS)
205
0
        return r;
206
0
      tlen += 2 + p[4]; /* FIXME */
207
0
    } else {
208
0
      sc_log(card->ctx,  "invalid security condition");
209
0
      return SC_ERROR_INTERNAL;
210
0
    }
211
0
    p   += tlen;
212
0
    len -= tlen;
213
0
  }
214
215
0
  return SC_SUCCESS;
216
0
}
217
218
/* sets a TLV encoded path as returned from GET DATA in a sc_path_t object
219
 */
220
static int asepcos_tlvpath_to_scpath(sc_path_t *out, const u8 *in, size_t in_len)
221
0
{
222
0
  int    r;
223
0
  size_t len = in_len;
224
225
0
  memset(out, 0, sizeof(sc_path_t));
226
227
0
  while (len != 0) {
228
0
    if (len < 4)
229
0
      return SC_ERROR_INTERNAL;
230
0
    if (in[0] != 0x8b || in[1] != 0x02)
231
0
      return SC_ERROR_INVALID_ASN1_OBJECT;
232
    /* append file id to the path */
233
0
    r = sc_append_path_id(out, &in[2], 2);
234
0
    if (r != SC_SUCCESS)
235
0
      return r;
236
0
    len -= 4;
237
0
    in  += 4;
238
0
  }
239
0
  out->type = SC_PATH_TYPE_PATH;
240
241
0
  return SC_SUCCESS;
242
0
}
243
244
/* returns the currently selected DF (if a EF is currently selected
245
 * it returns the path from the MF to the DF in which the EF is
246
 * located.
247
 * @param  card  sc_card_t object to use
248
 * @param  path  OUT path from the MF to the current DF
249
 * @return SC_SUCCESS on success and an error value otherwise
250
 */
251
static int asepcos_get_current_df_path(sc_card_t *card, sc_path_t *path)
252
0
{
253
0
  int r;
254
0
  sc_apdu_t apdu;
255
0
  u8        rbuf[SC_MAX_APDU_BUFFER_SIZE];
256
257
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x83);
258
0
  apdu.resp    = rbuf;
259
0
  apdu.resplen = sizeof(rbuf);
260
0
  apdu.le      = 256;
261
262
0
  r = sc_transmit_apdu(card, &apdu);
263
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
264
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
265
0
    return sc_check_sw(card, apdu.sw1, apdu.sw2);
266
0
  return asepcos_tlvpath_to_scpath(path, apdu.resp, apdu.resplen);
267
0
}
268
269
/* SELECT FILE: call the ISO SELECT FILE implementation and parse
270
 * asepcos specific security attributes.
271
 */
272
static int asepcos_select_file(sc_card_t *card, const sc_path_t *in_path,
273
  sc_file_t **file)
274
0
{
275
0
  int       r;
276
0
  sc_path_t npath = *in_path;
277
278
0
  LOG_FUNC_CALLED(card->ctx);
279
280
0
  if (in_path->type == SC_PATH_TYPE_PATH) {
281
    /* check the current DF to avoid unnecessary re-selection of
282
     * the MF (as this might invalidate a security status) */
283
0
    sc_path_t tpath;
284
0
    memset(&tpath, 0, sizeof tpath);
285
286
0
    r = asepcos_get_current_df_path(card, &tpath);
287
    /* workaround: as opensc can't handle paths with file id
288
     * and application names in it let's ignore the current
289
     * DF if the returned path contains a unsupported tag.
290
     */
291
0
    if (r != SC_ERROR_INVALID_ASN1_OBJECT && r != SC_SUCCESS)
292
0
      return r;
293
0
    if (r == SC_SUCCESS && sc_compare_path_prefix(&tpath, &npath) != 0) {
294
      /* remove the currently selected DF from the path */
295
0
      if (tpath.len == npath.len) {
296
        /* we are already in the requested DF */
297
0
        if (file == NULL)
298
          /* no file information requested =>
299
           * nothing to do */
300
0
          return SC_SUCCESS;
301
0
      } else {
302
        /* shorten path */
303
0
        r = sc_path_set(&npath, 0, &in_path->value[tpath.len],
304
0
            npath.len - tpath.len, 0, 0);
305
0
        if (r != SC_SUCCESS)
306
0
          return r;
307
0
        if (npath.len == 2)
308
0
          npath.type = SC_PATH_TYPE_FILE_ID;
309
0
        else
310
0
          npath.type = SC_PATH_TYPE_PATH;
311
0
      }
312
0
    }
313
0
  }
314
315
0
  r = iso_ops->select_file(card, &npath, file);
316
  /* XXX: this doesn't look right */
317
0
  if (file != NULL && *file != NULL)
318
0
    if ((*file)->ef_structure == SC_FILE_EF_UNKNOWN)
319
0
      (*file)->ef_structure = SC_FILE_EF_TRANSPARENT;
320
0
  if (r == SC_SUCCESS && file != NULL && *file != NULL) {
321
0
    r = asepcos_parse_sec_attr(card, *file, (*file)->sec_attr, (*file)->sec_attr_len);
322
0
    if (r != SC_SUCCESS)
323
0
      sc_log(card->ctx,  "error parsing security attributes");
324
0
  }
325
0
  LOG_FUNC_RETURN(card->ctx, r);
326
0
}
327
328
static int asepcos_set_security_env(sc_card_t *card,
329
  const sc_security_env_t *env, int se_num)
330
0
{
331
0
  return SC_SUCCESS;
332
0
}
333
334
335
static int asepcos_akn_to_fileid(sc_card_t *card, sc_cardctl_asepcos_akn2fileid_t *p)
336
0
{
337
0
  int r;
338
0
  u8  sbuf[32], rbuf[SC_MAX_APDU_BUFFER_SIZE];
339
0
  sc_apdu_t apdu = {0};
340
341
0
  sbuf[0] = p->akn & 0xff;
342
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x28, 0x02, 0x01);
343
0
  apdu.cla    |= 0x80;
344
0
  apdu.resp    = rbuf;
345
0
  apdu.resplen = sizeof(rbuf);
346
0
  apdu.le      = 256;
347
0
  apdu.lc      = 1;
348
0
  apdu.datalen = 1;
349
0
  apdu.data    = sbuf;
350
351
0
  r = sc_transmit_apdu(card, &apdu);
352
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
353
354
0
  if (apdu.resplen != 4)
355
0
    return SC_ERROR_INTERNAL;
356
357
0
  p->fileid = (apdu.resp[1] << 16) | (apdu.resp[2] << 8) | apdu.resp[3];
358
359
0
  return SC_SUCCESS;
360
0
}
361
362
/* sets the security attribute of a EF/DF
363
 */
364
static int asepcos_set_sec_attributes(sc_card_t *card, const u8 *data, size_t len,
365
  int is_ef)
366
0
{
367
0
  int r, type = is_ef != 0 ? 0x02 : 0x04;
368
0
  sc_apdu_t apdu = {0};
369
370
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x8a, type, 0xab);
371
0
  apdu.cla    |= 0x80;
372
0
  apdu.lc      = len;
373
0
  apdu.datalen = len;
374
0
  apdu.data    = data;
375
0
  r = sc_transmit_apdu(card, &apdu);
376
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
377
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
378
0
}
379
380
/* encodes the opensc file attributes into the card specific format
381
 */
382
static int asepcos_set_security_attributes(sc_card_t *card, sc_file_t *file)
383
0
{
384
0
  size_t i;
385
0
  const amode_entry_t *table;
386
0
  u8     buf[64], *p;
387
0
  int    r = SC_SUCCESS;
388
389
  /* first check whether the security attributes in encoded form
390
   * are already set. If present use these */
391
0
  if (file->sec_attr != NULL && file->sec_attr_len != 0)
392
0
    return asepcos_set_sec_attributes(card, file->sec_attr,
393
0
        file->sec_attr_len, file->type == SC_FILE_TYPE_DF ? 0:1);
394
  /* otherwise construct the ACL from the opensc ACLs */
395
0
  if (file->type == SC_FILE_TYPE_DF)
396
0
    table = df_amode_table;
397
0
  else if (file->type == SC_FILE_TYPE_WORKING_EF)
398
0
    table = wef_amode_table;
399
0
  else if (file->type == SC_FILE_TYPE_INTERNAL_EF)
400
0
    table = ief_amode_table;
401
0
  else
402
0
    return SC_ERROR_INVALID_ARGUMENTS;
403
404
0
  p = buf;
405
0
  for (i = 0; table[i].am != 0; i++) {
406
0
    const struct sc_acl_entry *ent = sc_file_get_acl_entry(file, table[i].sc);
407
0
    if (ent == NULL)
408
0
      continue;
409
0
    *p++ = 0x80;
410
0
    *p++ = 0x01;
411
0
    *p++ = table[i].am & 0xff;
412
0
    if (ent->method == SC_AC_NONE) {
413
0
      *p++ = 0x90;
414
0
      *p++ = 0x00;
415
0
    } else if (ent->method == SC_AC_NEVER) {
416
0
      *p++ = 0x97;
417
0
      *p++ = 0x00;
418
0
    } else if (ent->method == SC_AC_CHV) {
419
0
      sc_cardctl_asepcos_akn2fileid_t st;
420
0
      st.akn = ent->key_ref;
421
0
      r = asepcos_akn_to_fileid(card, &st);
422
0
      if (r != SC_SUCCESS)
423
0
        return r;
424
0
      *p++ = 0xa0;
425
0
      *p++ = 0x05;
426
0
      *p++ = 0x89;
427
0
      *p++ = 0x03;
428
0
      *p++ = (st.fileid >> 16) & 0xff;
429
0
      *p++ = (st.fileid >> 8 ) & 0xff;
430
0
      *p++ = st.fileid & 0xff;
431
0
    } else {
432
0
      sc_log(card->ctx,  "unknown auth method: '%d'", ent->method);
433
0
      return SC_ERROR_INTERNAL;
434
0
    }
435
0
  }
436
437
0
  if (p != buf)
438
0
    r = asepcos_set_sec_attributes(card, buf, p-buf, file->type == SC_FILE_TYPE_DF ? 0:1);
439
0
  return r;
440
0
}
441
442
static int asepcos_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len,
443
  u8 * out, size_t outlen)
444
0
{
445
0
  int       r;
446
0
  sc_apdu_t apdu;
447
448
0
  LOG_FUNC_CALLED(card->ctx);
449
450
  /* call RSA ENCRYPT DECRYPT for the decipher operation */
451
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x14, 0x01, 0x00);
452
0
  apdu.cla    |= 0x80;
453
0
  apdu.resp    = out;
454
0
  apdu.resplen = outlen;
455
  /* if less than 256 bytes are expected than set Le to 0x00
456
   * to tell the card the we want everything available (note: we
457
   * always have Le <= crgram_len) */
458
0
  apdu.le      = (outlen >= 256 && crgram_len < 256) ? 256 : outlen;
459
460
0
  apdu.data    = crgram;
461
0
  apdu.lc      = crgram_len;
462
0
  apdu.datalen = crgram_len;
463
0
  r = sc_transmit_apdu(card, &apdu);
464
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
465
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
466
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
467
0
  return (int)apdu.resplen;
468
0
}
469
470
/* compute the signature. Currently the RSA ENCRYPT DECRYPT command
471
 * is used here (TODO: use the key attributes to determine method
472
 * to use for signature generation).
473
 */
474
static int asepcos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen,
475
       u8 *out, size_t outlen)
476
0
{
477
0
  int r = SC_SUCCESS, atype;
478
0
  u8  rbuf[SC_MAX_APDU_BUFFER_SIZE];
479
0
  sc_apdu_t apdu;
480
481
0
  LOG_FUNC_CALLED(card->ctx);
482
483
0
  if (datalen >= 256)
484
0
    atype = SC_APDU_CASE_4_EXT;
485
0
  else
486
0
    atype = SC_APDU_CASE_4_SHORT;
487
0
  sc_format_apdu(card, &apdu, atype, 0x14, 0x01, 0x00);
488
0
  apdu.cla    |= 0x80;
489
0
  apdu.lc      = datalen;
490
0
  apdu.datalen = datalen;
491
0
  apdu.data    = data;
492
0
  apdu.resp    = rbuf;
493
0
  apdu.resplen = sizeof(rbuf);
494
0
  apdu.le      = 256;
495
496
0
  r = sc_transmit_apdu(card, &apdu);
497
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
498
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) {
499
0
    sc_log(card->ctx,  "error creating signature");
500
0
    return sc_check_sw(card, apdu.sw1, apdu.sw2);
501
0
  }
502
503
0
  if (apdu.resplen > outlen)
504
0
    return SC_ERROR_BUFFER_TOO_SMALL;
505
0
  memcpy(out, apdu.resp, apdu.resplen);
506
507
0
  return (int)apdu.resplen;
508
0
}
509
510
/* activates the EF/DF specified in the file id.
511
 */
512
static int asepcos_activate_file(sc_card_t *card, int fileid, int is_ef)
513
0
{
514
0
  int r, type = is_ef != 0 ? 2 : 1;
515
0
  sc_apdu_t apdu;
516
0
  u8 sbuf[2];
517
518
0
  sbuf[0] = (fileid >> 8) & 0xff;
519
0
  sbuf[1] = fileid & 0xff;
520
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x44, type, 0x00);
521
0
  apdu.lc      = 2;
522
0
  apdu.datalen = 2;
523
0
  apdu.data    = sbuf;
524
0
  r = sc_transmit_apdu(card, &apdu);
525
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
526
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
527
0
}
528
529
/* CREATE FILE: creates wEF, iEF and DFs. Note: although the ISO
530
 * command is used for wEF and iEF so format of the data send to
531
 * the card is asepcos specific.
532
 * @param  card  the sc_card_t object to use
533
 * @param  file  sc_file_t object describing the file to create
534
 * @return SC_SUCCESS on success and an error code otherwise.
535
 */
536
static int asepcos_create_file(sc_card_t *card, sc_file_t *file)
537
0
{
538
0
  if (file->type == SC_FILE_TYPE_DF) {
539
0
    int r, type;
540
0
    sc_apdu_t apdu = {0};
541
0
    u8  sbuf[SC_MAX_APDU_BUFFER_SIZE], *p = &sbuf[0];
542
543
0
    *p++ = (file->id >> 8) & 0xff;
544
0
    *p++ = file->id & 0xff;
545
0
    if (file->size > 0xffff) {
546
0
      *p++ = (file->size >> 24) & 0xff;
547
0
      *p++ = (file->size >> 16) & 0xff;
548
0
      *p++ = (file->size >> 8 ) & 0xff;
549
0
      *p++ = file->size & 0xff;
550
0
      type = 1;
551
0
    } else {
552
0
      *p++ = (file->size >> 8) & 0xff;
553
0
      *p++ = file->size & 0xff;
554
0
      type = 0;
555
0
    }
556
0
    if (file->namelen != 0 && file->namelen <= 16) {
557
0
      memcpy(p, file->name, file->namelen);
558
0
      p += file->namelen;
559
0
    }
560
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xe0, 0x38, type);
561
0
    apdu.cla    |= 0x80;
562
0
    apdu.lc      = p - sbuf;
563
0
    apdu.datalen = p - sbuf;
564
0
    apdu.data    = sbuf;
565
566
0
    r = sc_transmit_apdu(card, &apdu);
567
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
568
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
569
0
      return sc_check_sw(card, apdu.sw1, apdu.sw2);
570
571
0
    r = sc_select_file(card, &file->path, NULL);
572
0
    if (r != SC_SUCCESS)
573
0
      return r;
574
    /* set security attributes */
575
0
    r = asepcos_set_security_attributes(card, file);
576
0
    if (r != SC_SUCCESS) {
577
0
      sc_log(card->ctx,  "unable to set security attributes");
578
0
      return r;
579
0
    }
580
0
    return SC_SUCCESS;
581
0
  } else if (file->type == SC_FILE_TYPE_WORKING_EF) {
582
0
    int r;
583
0
    sc_apdu_t apdu;
584
0
    u8  descr_byte = file->ef_structure & 7;
585
0
    u8  sbuf[SC_MAX_APDU_BUFFER_SIZE], *p = &sbuf[0];
586
587
0
    *p++ = 0x85;
588
0
    p++;
589
    /* file id  */
590
0
    *p++ = (file->id >> 8) & 0xff;
591
0
    *p++ = file->id & 0xff;
592
    /* record size */
593
0
    if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
594
0
      *p++ = 0x00;
595
0
      *p++ = 0x00;
596
0
    } else {
597
0
      *p++ = (file->record_length >> 8) & 0xff;
598
0
      *p++ = file->record_length & 0xff;
599
0
    }
600
    /* number of records or file size */
601
0
    if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
602
0
      *p++ = (file->size >> 8) & 0xff;
603
0
      *p++ = file->size & 0xff;
604
0
    } else {
605
0
      *p++ = (file->record_count >> 8) & 0xff;
606
0
      *p++ = file->record_count & 0xff;
607
0
    }
608
    /* set the length of the inner TLV object */
609
0
    sbuf[1] = p - sbuf - 2;   /* FIXME */
610
611
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xe0, descr_byte, 0x00);
612
0
    apdu.lc      = p - sbuf;
613
0
    apdu.datalen = p - sbuf;
614
0
    apdu.data    = sbuf;
615
0
    r = sc_transmit_apdu(card, &apdu);
616
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
617
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
618
0
      return sc_check_sw(card, apdu.sw1, apdu.sw2);
619
620
    /* set security attributes */
621
0
    r = asepcos_set_security_attributes(card, file);
622
0
    if (r != SC_SUCCESS) {
623
0
      sc_log(card->ctx,  "unable to set security attributes");
624
0
      return r;
625
0
    }
626
0
    return asepcos_activate_file(card, file->id, 1);
627
0
  } else if (file->type == SC_FILE_TYPE_INTERNAL_EF) {
628
    /* for internal EF we 'misuse' the prop_attr field of the
629
     * sc_file_t object to store the data send to the card in
630
     * the CREATE EF call.
631
     */
632
0
    int r, atype = SC_APDU_CASE_3_SHORT;
633
0
    sc_apdu_t apdu;
634
635
0
    if (file->prop_attr_len > 255)
636
0
      atype = SC_APDU_CASE_3_EXT;
637
638
0
    sc_format_apdu(card, &apdu, atype, 0xe0, 0x08, 0x00);
639
0
    apdu.lc      = file->prop_attr_len;
640
0
    apdu.datalen = file->prop_attr_len;
641
0
    apdu.data    = file->prop_attr;
642
643
0
    r = sc_transmit_apdu(card, &apdu);
644
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
645
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
646
0
      return sc_check_sw(card, apdu.sw1, apdu.sw2);
647
    /* set security attributes */
648
0
    r = asepcos_set_security_attributes(card, file);
649
0
    if (r != SC_SUCCESS) {
650
0
      sc_log(card->ctx,  "unable to set security attributes");
651
0
      return r;
652
0
    }
653
0
    return asepcos_activate_file(card, file->id, 1);
654
0
  } else
655
0
    return SC_ERROR_INVALID_ARGUMENTS;
656
0
}
657
658
/* list files: the function first calls GET DATA to get the current
659
 * working DF. It then re-selects the DF to get proprietary FCI which
660
 * contain the FID of the first child DF EF.
661
 * The FID of the other EFs/DFs within the selected DF are then
662
 * obtained by selecting the know FIDs to get next child EF/DF.
663
 * @param  card  the sc_card_t object to use
664
 * @param  buff  the output buffer for the list of FIDs
665
 * @param  blen  the length of the buffer
666
 * @return the number of FIDs read on success and an error value otherwise.
667
 */
668
static int asepcos_list_files(sc_card_t *card, u8 *buf, size_t blen)
669
0
{
670
0
  int       r, rv = 0, dfFID, efFID;
671
0
  sc_path_t bpath, tpath;
672
0
  sc_file_t *tfile = NULL;
673
674
  /* 1. get currently selected DF */
675
0
  r = asepcos_get_current_df_path(card, &bpath);
676
0
  if (r != SC_SUCCESS)
677
0
    return r;
678
  /* 2. re-select DF to get the FID of the child EFs/DFs */
679
0
  r = sc_select_file(card, &bpath, &tfile);
680
0
  if (r != SC_SUCCESS)
681
0
    return r;
682
0
  if (tfile->prop_attr_len != 6 || tfile->prop_attr == NULL) {
683
0
    sc_file_free(tfile);
684
0
    sc_log(card->ctx,  "unable to parse proprietary FCI attributes");
685
0
    return SC_ERROR_INTERNAL;
686
0
  }
687
0
  dfFID = (tfile->prop_attr[2] << 8) | tfile->prop_attr[3];
688
0
  efFID = (tfile->prop_attr[4] << 8) | tfile->prop_attr[5];
689
0
  sc_file_free(tfile);
690
  /* 3. select every child DF to get the FID of the next child DF */
691
0
  while (dfFID != 0) {
692
    /* put DF FID on the list */
693
0
    if (blen < 2)
694
0
      return SC_ERROR_BUFFER_TOO_SMALL;
695
0
    *buf++ = (dfFID >> 8) & 0xff;
696
0
    *buf++ = dfFID & 0xff;
697
0
    rv   += 2;
698
0
    blen -= 2;
699
    /* select DF to get next DF FID */
700
0
    tpath = bpath;
701
0
    r = sc_append_file_id(&tpath, dfFID);
702
0
    if (r != SC_SUCCESS)
703
0
      return r;
704
0
    r = sc_select_file(card, &tpath, &tfile);
705
0
    if (r != SC_SUCCESS)
706
0
      return r;
707
0
    if (tfile->prop_attr_len != 6 || tfile->prop_attr == NULL)
708
0
      return SC_ERROR_INTERNAL;
709
0
    dfFID = (tfile->prop_attr[0] << 8) | tfile->prop_attr[1];
710
0
    sc_file_free(tfile);
711
0
  }
712
  /* 4. select every child EF ... */
713
0
  while (efFID != 0) {
714
    /* put DF FID on the list */
715
0
    if (blen < 2)
716
0
      return SC_ERROR_BUFFER_TOO_SMALL;
717
0
    *buf++ = (efFID >> 8) & 0xff;
718
0
    *buf++ = efFID & 0xff;
719
0
    rv   += 2;
720
0
    blen -= 2;
721
    /* select EF to get next EF FID */
722
0
    tpath = bpath;
723
0
    r = sc_append_file_id(&tpath, efFID);
724
0
    if (r != SC_SUCCESS)
725
0
      return r;
726
0
    r = sc_select_file(card, &tpath, &tfile);
727
0
    if (r != SC_SUCCESS)
728
0
      return r;
729
0
    if (tfile->prop_attr_len < 2 || tfile->prop_attr == NULL)
730
0
      return SC_ERROR_INTERNAL;
731
0
    efFID = (tfile->prop_attr[0] << 8) | tfile->prop_attr[1];
732
0
    sc_file_free(tfile);
733
0
  }
734
735
0
  return rv;
736
0
}
737
738
static int asepcos_delete_file(sc_card_t *card, const sc_path_t *path)
739
0
{
740
0
  int       r, ftype, atype;
741
0
  sc_apdu_t apdu;
742
0
  u8        buf[SC_MAX_APDU_BUFFER_SIZE];
743
744
  /* use GET DATA to determine whether it is a DF or EF */
745
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x84);
746
0
  apdu.le      = 256;
747
0
  apdu.resplen = sizeof(buf);
748
0
  apdu.resp    = buf;
749
0
  r = sc_transmit_apdu(card, &apdu);
750
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
751
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
752
    /* looks like a EF */
753
0
    atype = SC_APDU_CASE_3_SHORT;
754
0
    ftype = 0x02;
755
0
    buf[0] = path->value[path->len-2];
756
0
    buf[1] = path->value[path->len-1];
757
0
  } else {
758
    /* presumably a DF */
759
0
    atype = SC_APDU_CASE_1;
760
0
    ftype = 0x00;
761
0
  }
762
763
0
  sc_format_apdu(card, &apdu, atype, 0xe4, ftype, 0x00);
764
0
  if (atype == SC_APDU_CASE_3_SHORT) {
765
0
    apdu.lc      = 2;
766
0
    apdu.datalen = 2;
767
0
    apdu.data    = buf;
768
0
  }
769
770
0
  r = sc_transmit_apdu(card, &apdu);
771
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
772
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
773
0
}
774
775
/* returns the default transport key (note: this should be put in the
776
 * pkcs15 profile file).
777
 */
778
static int asepcos_get_default_key(sc_card_t *card,
779
  struct sc_cardctl_default_key *data)
780
0
{
781
0
  static const u8 asepcos_def_key[] = {0x41,0x53,0x45,0x43,0x41,0x52,0x44,0x2b};
782
0
  if (data->method != SC_AC_CHV && data->method != SC_AC_AUT)
783
0
    return SC_ERROR_NO_DEFAULT_KEY;
784
0
  if (data->key_data == NULL || data->len < sizeof(asepcos_def_key))
785
0
    return SC_ERROR_BUFFER_TOO_SMALL;
786
0
  memcpy(data->key_data, asepcos_def_key, sizeof(asepcos_def_key));
787
0
  data->len = sizeof(asepcos_def_key);
788
0
  return SC_SUCCESS;
789
0
}
790
791
static int asepcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
792
0
{
793
0
  int r;
794
0
  sc_apdu_t apdu;
795
0
  u8  rbuf[SC_MAX_APDU_BUFFER_SIZE];
796
797
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x14);
798
0
  apdu.resp = rbuf;
799
0
  apdu.resplen = sizeof(rbuf);
800
0
  apdu.le   = 256;
801
0
  r = sc_transmit_apdu(card, &apdu);
802
0
  LOG_TEST_RET(card->ctx, r,  "APDU transmit failed");
803
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
804
0
    return SC_ERROR_INTERNAL;
805
0
  if (apdu.resplen != 8) {
806
0
    sc_log(card->ctx,  "unexpected response to GET DATA serial number\n");
807
0
    return SC_ERROR_INTERNAL;
808
0
  }
809
  /* cache serial number */
810
0
  memcpy(card->serialnr.value, rbuf, 8);
811
0
  card->serialnr.len = 8;
812
  /* copy and return serial number */
813
0
  memcpy(serial, &card->serialnr, sizeof(*serial));
814
0
  return SC_SUCCESS;
815
0
}
816
817
static int asepcos_change_key(sc_card_t *card, sc_cardctl_asepcos_change_key_t *p)
818
0
{
819
0
  int       r, atype;
820
0
  sc_apdu_t apdu;
821
822
0
  if (p->datalen > 255)
823
0
    atype = SC_APDU_CASE_3_EXT;
824
0
  else
825
0
    atype = SC_APDU_CASE_3_SHORT;
826
827
0
  sc_format_apdu(card, &apdu, atype, 0x24, 0x01, 0x80);
828
0
  apdu.lc      = p->datalen;
829
0
  apdu.datalen = p->datalen;
830
0
  apdu.data    = p->data;
831
832
0
  r = sc_transmit_apdu(card, &apdu);
833
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
834
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
835
0
}
836
837
static int asepcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
838
0
{
839
0
  switch (cmd) {
840
0
  case SC_CARDCTL_GET_DEFAULT_KEY:
841
0
    return asepcos_get_default_key(card, (struct sc_cardctl_default_key *) ptr);
842
0
  case SC_CARDCTL_GET_SERIALNR:
843
0
    return asepcos_get_serialnr(card, (sc_serial_number_t *)ptr);
844
0
  case SC_CARDCTL_ASEPCOS_CHANGE_KEY:
845
0
    return asepcos_change_key(card, (sc_cardctl_asepcos_change_key_t*)ptr);
846
0
  case SC_CARDCTL_ASEPCOS_AKN2FILEID:
847
0
    return asepcos_akn_to_fileid(card, (sc_cardctl_asepcos_akn2fileid_t*)ptr);
848
0
  case SC_CARDCTL_ASEPCOS_SET_SATTR:
849
0
    return asepcos_set_security_attributes(card, (sc_file_t*)ptr);
850
0
  case SC_CARDCTL_ASEPCOS_ACTIVATE_FILE:
851
0
    return asepcos_activate_file(card, ((sc_cardctl_asepcos_activate_file_t*)ptr)->fileid,
852
0
                               ((sc_cardctl_asepcos_activate_file_t *)ptr)->is_ef);
853
0
  }
854
0
  return SC_ERROR_NOT_SUPPORTED;
855
0
}
856
857
/* build the different APDUs for the PIN handling commands
858
 */
859
static int asepcos_build_pin_apdu(sc_card_t *card, sc_apdu_t *apdu,
860
  struct sc_pin_cmd_data *data, u8 *buf, size_t buf_len,
861
  unsigned int cmd, int is_puk)
862
0
{
863
0
  int r, fileid;
864
0
  u8  *p = buf;
865
0
  sc_cardctl_asepcos_akn2fileid_t st;
866
867
0
  switch (cmd) {
868
0
  case SC_PIN_CMD_VERIFY:
869
0
    st.akn = data->pin_reference;
870
0
    r = asepcos_akn_to_fileid(card, &st);
871
0
    if (r != SC_SUCCESS)
872
0
      return r;
873
0
    fileid = st.fileid;
874
    /* the fileid of the puk is the fileid of the pin + 1 */
875
0
    if (is_puk != 0)
876
0
      fileid++;
877
0
    sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x02, 0x80);
878
0
    *p++ = (fileid >> 24) & 0xff;
879
0
    *p++ = (fileid >> 16) & 0xff;
880
0
    *p++ = (fileid >> 8 ) & 0xff;
881
0
    *p++ = fileid & 0xff;
882
0
    memcpy(p, data->pin1.data, data->pin1.len);
883
0
    p += data->pin1.len;
884
0
    apdu->lc       = p - buf;
885
0
    apdu->datalen  = p - buf;
886
0
    apdu->data     = buf;
887
0
    break;
888
0
  case SC_PIN_CMD_CHANGE:
889
    /* build the CHANGE KEY apdu. Note: the PIN file is implicitly
890
     * selected by its SFID */
891
0
    *p++ = 0x81;
892
0
    *p++ = data->pin2.len & 0xff;
893
0
    memcpy(p, data->pin2.data, data->pin2.len);
894
0
    p   += data->pin2.len;
895
0
    st.akn = data->pin_reference;
896
0
    r = asepcos_akn_to_fileid(card, &st);
897
0
    if (r != SC_SUCCESS)
898
0
      return r;
899
0
    fileid = 0x80 | (st.fileid & 0x1f);
900
0
    sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, fileid);
901
0
    apdu->lc       = p - buf;
902
0
    apdu->datalen  = p - buf;
903
0
    apdu->data     = buf;
904
0
    break;
905
0
  case SC_PIN_CMD_UNBLOCK:
906
    /* build the UNBLOCK KEY apdu. The PIN file is implicitly
907
     * selected by its SFID. The new PIN is provided in the
908
     * data field of the UNBLOCK KEY command. */
909
0
    *p++ = 0x81;
910
0
    *p++ = data->pin2.len & 0xff;
911
0
    memcpy(p, data->pin2.data, data->pin2.len);
912
0
    p   += data->pin2.len;
913
0
    st.akn = data->pin_reference;
914
0
    r = asepcos_akn_to_fileid(card, &st);
915
0
    if (r != SC_SUCCESS)
916
0
      return r;
917
0
    fileid = 0x80 | (st.fileid & 0x1f);
918
0
    sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, 0x2C, 0x02, fileid);
919
0
    apdu->lc       = p - buf;
920
0
    apdu->datalen  = p - buf;
921
0
    apdu->data     = buf;
922
0
    break;
923
0
  default:
924
0
    return SC_ERROR_NOT_SUPPORTED;
925
0
  }
926
0
  return SC_SUCCESS;
927
0
}
928
929
/* generic function to handle the different PIN operations, i.e verify
930
 * change and unblock.
931
 */
932
static int asepcos_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *pdata,
933
  int *tries_left)
934
0
{
935
0
  sc_apdu_t apdu;
936
0
  int r = SC_SUCCESS;
937
0
  u8  sbuf[SC_MAX_APDU_BUFFER_SIZE];
938
939
0
  if (tries_left)
940
0
    *tries_left = -1;
941
942
  /* only PIN verification is supported at the moment  */
943
944
  /* check PIN length */
945
0
  if (pdata->pin1.len < 4 || pdata->pin1.len > 16) {
946
0
    sc_log(card->ctx,  "invalid PIN1 length");
947
0
    return SC_ERROR_INVALID_PIN_LENGTH;
948
0
  }
949
950
0
  switch (pdata->cmd) {
951
0
  case SC_PIN_CMD_VERIFY:
952
0
    if (pdata->pin_type != SC_AC_CHV && pdata->pin_type != SC_AC_AUT)
953
0
      return SC_ERROR_INVALID_ARGUMENTS;
954
    /* 'AUT' key is the transport PIN and should have reference '0' */
955
0
    if (pdata->pin_type == SC_AC_AUT && pdata->pin_reference)
956
0
      return SC_ERROR_INVALID_ARGUMENTS;
957
    /* build verify APDU and send it to the card */
958
0
    r = asepcos_build_pin_apdu(card, &apdu, pdata, sbuf, sizeof(sbuf), SC_PIN_CMD_VERIFY, 0);
959
0
    if (r != SC_SUCCESS)
960
0
      break;
961
0
    r = sc_transmit_apdu(card, &apdu);
962
0
    if (r != SC_SUCCESS)
963
0
      sc_log(card->ctx,  "APDU transmit failed");
964
0
    break;
965
0
  case SC_PIN_CMD_CHANGE:
966
0
    if (pdata->pin_type != SC_AC_CHV)
967
0
      return SC_ERROR_INVALID_ARGUMENTS;
968
0
    if (pdata->pin2.len < 4 || pdata->pin2.len > 16) {
969
0
      sc_log(card->ctx,  "invalid PIN2 length");
970
0
      return SC_ERROR_INVALID_PIN_LENGTH;
971
0
    }
972
    /* 1. step: verify the old pin */
973
0
    r = asepcos_build_pin_apdu(card, &apdu, pdata, sbuf, sizeof(sbuf), SC_PIN_CMD_VERIFY, 0);
974
0
    if (r != SC_SUCCESS)
975
0
      break;
976
0
    r = sc_transmit_apdu(card, &apdu);
977
0
    if (r != SC_SUCCESS) {
978
0
      sc_log(card->ctx,  "APDU transmit failed");
979
0
      break;
980
0
    }
981
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) {
982
      /* unable to verify the old PIN */
983
0
      break;
984
0
    }
985
    /* 2, step: use CHANGE KEY to update the PIN */
986
0
    r = asepcos_build_pin_apdu(card, &apdu, pdata, sbuf, sizeof(sbuf), SC_PIN_CMD_CHANGE, 0);
987
0
    if (r != SC_SUCCESS)
988
0
      break;
989
0
    r = sc_transmit_apdu(card, &apdu);
990
0
    if (r != SC_SUCCESS)
991
0
      sc_log(card->ctx,  "APDU transmit failed");
992
0
    break;
993
0
  case SC_PIN_CMD_UNBLOCK:
994
0
    if (pdata->pin_type != SC_AC_CHV)
995
0
      return SC_ERROR_INVALID_ARGUMENTS;
996
0
    if (pdata->pin2.len < 4 || pdata->pin2.len > 16) {
997
0
      sc_log(card->ctx,  "invalid PIN2 length");
998
0
      return SC_ERROR_INVALID_PIN_LENGTH;
999
0
    }
1000
    /* 1. step: verify the puk */
1001
0
    r = asepcos_build_pin_apdu(card, &apdu, pdata, sbuf, sizeof(sbuf), SC_PIN_CMD_VERIFY, 1);
1002
0
    if (r != SC_SUCCESS)
1003
0
      break;
1004
0
    r = sc_transmit_apdu(card, &apdu);
1005
0
    if (r != SC_SUCCESS) {
1006
0
      sc_log(card->ctx,  "APDU transmit failed");
1007
0
      break;
1008
0
    }
1009
    /* 2, step: unblock and change the pin */
1010
0
    r = asepcos_build_pin_apdu(card, &apdu, pdata, sbuf, sizeof(sbuf), SC_PIN_CMD_UNBLOCK, 0);
1011
0
    if (r != SC_SUCCESS)
1012
0
      break;
1013
0
    r = sc_transmit_apdu(card, &apdu);
1014
0
    if (r != SC_SUCCESS) {
1015
0
      sc_log(card->ctx,  "APDU transmit failed");
1016
0
      break;
1017
0
    }
1018
0
    break;
1019
0
  default:
1020
0
    sc_log(card->ctx,  "error: unknown cmd type");
1021
0
    return SC_ERROR_INTERNAL;
1022
0
  }
1023
  /* Clear the buffer - it may contain pins */
1024
0
  sc_mem_clear(sbuf, sizeof(sbuf));
1025
  /* check for remaining tries if verification failed */
1026
0
  if (r == SC_SUCCESS) {
1027
0
    if (apdu.sw1 == 0x63) {
1028
0
      if ((apdu.sw2 & 0xF0) == 0xC0 && tries_left != NULL)
1029
0
        *tries_left = apdu.sw2 & 0x0F;
1030
0
      r = SC_ERROR_PIN_CODE_INCORRECT;
1031
0
      return r;
1032
0
    }
1033
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1034
0
  }
1035
1036
0
  return r;
1037
0
}
1038
1039
static int asepcos_card_reader_lock_obtained(sc_card_t *card, int was_reset)
1040
0
{
1041
0
  int r = SC_SUCCESS;
1042
1043
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1044
1045
0
  if (was_reset > 0 && card->type == SC_CARD_TYPE_ASEPCOS_JAVA) {
1046
    /* in case of a Java card try to select the ASEPCOS applet */
1047
0
    r = asepcos_select_asepcos_applet(card);
1048
0
  }
1049
1050
0
  LOG_FUNC_RETURN(card->ctx, r);
1051
0
}
1052
1053
static int asepcos_logout(sc_card_t *card)
1054
0
{
1055
0
  int r = SC_ERROR_NOT_SUPPORTED;
1056
1057
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
1058
1059
0
  if (card->type == SC_CARD_TYPE_ASEPCOS_JAVA) {
1060
    /* in case of a Java card try to select the ASEPCOS applet */
1061
0
    r = asepcos_select_asepcos_applet(card);
1062
0
  }
1063
1064
0
  LOG_FUNC_RETURN(card->ctx, r);
1065
0
}
1066
1067
static struct sc_card_driver * sc_get_driver(void)
1068
14.0k
{
1069
14.0k
  if (iso_ops == NULL)
1070
1
    iso_ops = sc_get_iso7816_driver()->ops;
1071
14.0k
  asepcos_ops = *iso_ops;
1072
14.0k
  asepcos_ops.match_card        = asepcos_match_card;
1073
14.0k
  asepcos_ops.init              = asepcos_init;
1074
14.0k
  asepcos_ops.select_file       = asepcos_select_file;
1075
14.0k
  asepcos_ops.set_security_env  = asepcos_set_security_env;
1076
14.0k
  asepcos_ops.decipher          = asepcos_decipher;
1077
14.0k
  asepcos_ops.compute_signature = asepcos_compute_signature;
1078
14.0k
  asepcos_ops.create_file       = asepcos_create_file;
1079
14.0k
  asepcos_ops.delete_file       = asepcos_delete_file;
1080
14.0k
  asepcos_ops.list_files        = asepcos_list_files;
1081
14.0k
  asepcos_ops.card_ctl          = asepcos_card_ctl;
1082
14.0k
  asepcos_ops.pin_cmd           = asepcos_pin_cmd;
1083
14.0k
  asepcos_ops.logout            = asepcos_logout;
1084
14.0k
  asepcos_ops.card_reader_lock_obtained = asepcos_card_reader_lock_obtained;
1085
1086
14.0k
  return &asepcos_drv;
1087
14.0k
}
1088
1089
struct sc_card_driver * sc_get_asepcos_driver(void)
1090
14.0k
{
1091
14.0k
  return sc_get_driver();
1092
14.0k
}