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-mcrd.c
Line
Count
Source
1
/*
2
 * card-mcrd.c: Support for MICARDO cards
3
 *
4
 * Copyright (C) 2004  Martin Paljak <martin@martinpaljak.net>
5
 * Copyright (C) 2004  Priit Randla <priit.randla@eyp.ee>
6
 * Copyright (C) 2003  Marie Fischer <marie@vtl.ee>
7
 * Copyright (C) 2001  Juha Yrjölä <juha.yrjola@iki.fi>
8
 * Copyright (C) 2002  g10 Code GmbH
9
 *
10
 * This library is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU Lesser General Public
12
 * License as published by the Free Software Foundation; either
13
 * version 2.1 of the License, or (at your option) any later version.
14
 *
15
 * This library is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 * Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with this library; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
 */
24
25
#ifdef HAVE_CONFIG_H
26
#include "config.h"
27
#endif
28
29
#include <stdlib.h>
30
#include <string.h>
31
#include <ctype.h>
32
33
#include "internal.h"
34
#include "asn1.h"
35
#include "cardctl.h"
36
#include "gp.h"
37
38
static const struct sc_atr_table mcrd_atrs[] = {
39
  {"3B:FF:94:00:FF:80:B1:FE:45:1F:03:00:68:D2:76:00:00:28:FF:05:1E:31:80:00:90:00:23", NULL,
40
    "Micardo 2.1/German BMI/D-Trust", SC_CARD_TYPE_MCRD_GENERIC, 0, NULL},
41
  {"3b:6f:00:ff:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00", NULL,
42
    "D-Trust", SC_CARD_TYPE_MCRD_GENERIC, 0, NULL},
43
  {"3b:ff:11:00:ff:80:b1:fe:45:1f:03:00:68:d2:76:00:00:28:ff:05:1e:31:80:00:90:00:a6", NULL,
44
    "D-Trust", SC_CARD_TYPE_MCRD_GENERIC, 0, NULL},
45
  {NULL, NULL, NULL, 0, 0, NULL}
46
};
47
48
49
static struct sc_card_operations mcrd_ops;
50
static struct sc_card_driver mcrd_drv = {
51
  "MICARDO 2.1",
52
  "mcrd",
53
  &mcrd_ops,
54
  NULL, 0, NULL
55
};
56
57
static const struct sc_card_operations *iso_ops = NULL;
58
59
enum {
60
  MCRD_SEL_MF = 0x00,
61
  MCRD_SEL_DF = 0x01,
62
  MCRD_SEL_EF = 0x02,
63
  MCRD_SEL_PARENT = 0x03,
64
  MCRD_SEL_AID = 0x04
65
};
66
67
4.26k
#define MFID 0x3F00
68
21
#define EF_KeyD 0x0013    /* File with extra key information. */
69
193
#define EF_Rule 0x0030    /* Default ACL file. */
70
71
2.40k
#define MAX_CURPATH 10
72
73
struct rule_record_s {
74
  struct rule_record_s *next;
75
  unsigned int recno;
76
  size_t datalen;
77
  u8 data[1];
78
};
79
80
struct keyd_record_s {
81
  struct keyd_record_s *next;
82
  unsigned int recno;
83
  size_t datalen;
84
  u8 data[1];
85
};
86
87
struct df_info_s {
88
  struct df_info_s *next;
89
  unsigned short path[MAX_CURPATH];
90
  size_t pathlen;
91
  struct rule_record_s *rule_file;  /* keeps records of EF_Rule. */
92
  struct keyd_record_s *keyd_file;  /* keeps records of EF_KeyD. */
93
};
94
95
struct mcrd_priv_data {
96
  unsigned short curpath[MAX_CURPATH];  /* The currently selected path. */
97
  int is_ef;    /* True if the path points to an EF. */
98
  size_t curpathlen;  /* Length of this path or 0 if unknown. */
99
  struct df_info_s *df_infos;
100
  sc_security_env_t sec_env;  /* current security environment */
101
};
102
103
4.64k
#define DRVDATA(card) ((struct mcrd_priv_data *) ((card)->drv_data))
104
105
static int load_special_files(sc_card_t * card);
106
static int select_part(sc_card_t * card, u8 kind, unsigned short int fid, sc_file_t ** file);
107
108
/* Return the DF_info for the current path.  If does not yet exist,
109
   create it.  Returns NULL on error. */
110
static struct df_info_s *get_df_info(sc_card_t * card)
111
513
{
112
513
  sc_context_t *ctx = card->ctx;
113
513
  struct mcrd_priv_data *priv = DRVDATA(card);
114
513
  struct df_info_s *dfi;
115
116
513
  if(!(!priv->is_ef))
117
2
    return NULL;
118
119
511
  if (!priv->curpathlen) {
120
231
    sc_log(ctx, "no current path to find the df_info\n");
121
231
    return NULL;
122
231
  }
123
124
319
  for (dfi = priv->df_infos; dfi; dfi = dfi->next) {
125
122
    if (dfi->pathlen == priv->curpathlen
126
90
      && !memcmp(dfi->path, priv->curpath,
127
90
          dfi->pathlen * sizeof *dfi->path))
128
83
      return dfi;
129
122
  }
130
  /* Not found, create it. */
131
197
  dfi = calloc(1, sizeof *dfi);
132
197
  if (!dfi) {
133
0
    sc_log(ctx, "out of memory while allocating df_info\n");
134
0
    return NULL;
135
0
  }
136
197
  dfi->pathlen = priv->curpathlen;
137
197
  memcpy(dfi->path, priv->curpath, dfi->pathlen * sizeof *dfi->path);
138
197
  dfi->next = priv->df_infos;
139
197
  priv->df_infos = dfi;
140
197
  return dfi;
141
197
}
142
143
static void clear_special_files(struct df_info_s *dfi)
144
619
{
145
619
  if (dfi) {
146
1.27k
    while (dfi->rule_file) {
147
880
      struct rule_record_s *tmp = dfi->rule_file->next;
148
880
      free(dfi->rule_file);
149
880
      dfi->rule_file = tmp;
150
880
    }
151
464
    while (dfi->keyd_file) {
152
74
      struct keyd_record_s *tmp = dfi->keyd_file->next;
153
74
      free(dfi->keyd_file);
154
74
      dfi->keyd_file = tmp;
155
74
    }
156
390
  }
157
619
}
158
159
/*
160
 * Official notice: Refer to the Micardo 2.1 Public manual.
161
 * Sad side: not available without a NDA.
162
 */
163
164
static int mcrd_delete_ref_to_authkey(sc_card_t * card)
165
0
{
166
0
  sc_apdu_t apdu;
167
0
  int r;
168
0
  u8 sbuf[2] = { 0x83, 0x00 };
169
0
  if(card == NULL)
170
0
    return SC_ERROR_INTERNAL;
171
0
  sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x41, 0xA4, sbuf, 2, NULL, 0);
172
0
  r = sc_transmit_apdu(card, &apdu);
173
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
174
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
175
0
}
176
177
static int mcrd_delete_ref_to_signkey(sc_card_t * card)
178
0
{
179
0
  sc_apdu_t apdu;
180
0
  int r;
181
0
  u8 sbuf[2] = { 0x83, 0x00 };
182
0
  if(card == NULL)
183
0
    return SC_ERROR_INTERNAL;
184
0
  sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x41, 0xB6, sbuf, 2, NULL, 0);
185
0
  r = sc_transmit_apdu(card, &apdu);
186
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
187
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
188
0
}
189
190
static int mcrd_match_card(sc_card_t * card)
191
13.6k
{
192
13.6k
  int i = 0;
193
194
13.6k
  i = _sc_match_atr(card, mcrd_atrs, &card->type);
195
13.6k
  if (i >= 0) {
196
300
    card->name = mcrd_atrs[i].name;
197
300
    return 1;
198
300
  }
199
200
13.3k
  return 0;
201
13.6k
}
202
203
static int mcrd_init(sc_card_t * card)
204
300
{
205
300
  unsigned long flags;
206
300
  struct mcrd_priv_data *priv = calloc(1, sizeof *priv);
207
300
  if (!priv)
208
0
    return SC_ERROR_OUT_OF_MEMORY;
209
300
  priv->curpath[0] = MFID;
210
300
  priv->curpathlen = 1;
211
300
  card->drv_data = priv;
212
300
  card->cla = 0x00;
213
300
  card->caps = SC_CARD_CAP_RNG;
214
215
300
  flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE;
216
300
  _sc_card_add_rsa_alg(card, 512, flags, 0);
217
300
  _sc_card_add_rsa_alg(card, 768, flags, 0);
218
300
  _sc_card_add_rsa_alg(card, 1024, flags, 0);
219
220
300
  if (SC_SUCCESS != sc_select_file (card, sc_get_mf_path(), NULL))
221
229
    sc_log(card->ctx, "Warning: select MF failed");
222
223
300
  load_special_files(card);
224
225
300
  return SC_SUCCESS;
226
300
}
227
228
static int mcrd_finish(sc_card_t * card)
229
300
{
230
300
  struct mcrd_priv_data *priv;
231
232
300
  if (card == NULL)
233
0
    return 0;
234
300
  priv = DRVDATA(card);
235
497
  while (priv->df_infos) {
236
197
    struct df_info_s *tmp = priv->df_infos->next;
237
197
    clear_special_files(priv->df_infos);
238
197
    free(priv->df_infos);
239
197
    priv->df_infos = tmp;
240
197
  }
241
300
  free(priv);
242
300
  return 0;
243
300
}
244
245
/* Load the rule and keyd file into our private data.
246
   Return 0 on success */
247
static int load_special_files(sc_card_t * card)
248
422
{
249
422
  sc_context_t *ctx = card->ctx;
250
422
  int r;
251
422
  unsigned int recno;
252
422
  struct df_info_s *dfi;
253
422
  struct rule_record_s *rule;
254
422
  struct keyd_record_s *keyd;
255
256
  /* First check whether we already cached it. */
257
422
  dfi = get_df_info(card);
258
422
  if (dfi && dfi->rule_file)
259
0
    return 0; /* yes. */
260
422
  clear_special_files(dfi);
261
422
  if (!dfi)
262
422
    LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
263
264
  /* Read rule file. Note that we bypass our cache here. */
265
193
  r = select_part(card, MCRD_SEL_EF, EF_Rule, NULL);
266
193
  LOG_TEST_RET(ctx, r, "selecting EF_Rule failed");
267
268
1.01k
  for (recno = 1;; recno++) {
269
1.01k
    u8 recbuf[256];
270
1.01k
    r = sc_read_record(card, recno, 0, recbuf, sizeof(recbuf),
271
1.01k
          SC_RECORD_BY_REC_NR);
272
273
1.01k
    if (r == SC_ERROR_RECORD_NOT_FOUND)
274
21
      break;
275
996
    if (r < 0) {
276
116
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
277
880
    } else {
278
880
      rule = malloc(sizeof *rule + (size_t)r);
279
880
      if (!rule)
280
880
        LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
281
880
      rule->recno = recno;
282
880
      rule->datalen = (size_t)r;
283
880
      memcpy(rule->data, recbuf, r);
284
880
      rule->next = dfi->rule_file;
285
880
      dfi->rule_file = rule;
286
880
    }
287
996
  }
288
289
21
  sc_log(ctx, "new EF_Rule file loaded (%d records)\n", recno - 1);
290
291
  /* Read the KeyD file. Note that we bypass our cache here. */
292
21
  r = select_part(card, MCRD_SEL_EF, EF_KeyD, NULL);
293
21
  if (r == SC_ERROR_FILE_NOT_FOUND) {
294
1
    sc_log(ctx, "no EF_KeyD file available\n");
295
1
    return 0; /* That is okay. */
296
1
  }
297
20
  LOG_TEST_RET(ctx, r, "selecting EF_KeyD failed");
298
299
89
  for (recno = 1;; recno++) {
300
89
    u8 recbuf[256];
301
89
    r = sc_read_record(card, recno, 0, recbuf, sizeof(recbuf),
302
89
          SC_RECORD_BY_REC_NR);
303
304
89
    if (r == SC_ERROR_RECORD_NOT_FOUND)
305
3
      break;
306
86
    if (r < 0) {
307
12
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
308
74
    } else {
309
74
      keyd = malloc(sizeof *keyd + (size_t)r);
310
74
      if (!keyd)
311
74
        LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
312
74
      keyd->recno = recno;
313
74
      keyd->datalen = (size_t) r;
314
74
      memcpy(keyd->data, recbuf, r);
315
74
      keyd->next = dfi->keyd_file;
316
74
      dfi->keyd_file = keyd;
317
74
    }
318
86
  }
319
320
3
  sc_log(ctx, "new EF_KeyD file loaded (%d records)\n", recno - 1);
321
  /* FIXME: Do we need to restore the current DF?  I guess it is
322
     not required, but we could try to do so by selecting 3fff?  */
323
3
  return 0;
324
15
}
325
326
/* Process an ARR (7816-9/8.5.4) and setup the ACL. */
327
static void process_arr(sc_card_t * card, const u8 * buf, size_t buflen)
328
92
{
329
92
  sc_context_t *ctx = card->ctx;
330
92
  struct df_info_s *dfi;
331
92
  struct rule_record_s *rule;
332
92
  size_t left, taglen;
333
92
  unsigned int cla, tag;
334
92
  const u8 *p;
335
92
  int skip;
336
92
  char dbgbuf[2048];
337
338
  /* Currently we support only the short for. */
339
92
  if (buflen != 1) {
340
1
    sc_log(ctx, "can't handle long ARRs\n");
341
1
    return;
342
1
  }
343
344
91
  dfi = get_df_info(card);
345
385
  for (rule = dfi ? dfi->rule_file : NULL; rule && rule->recno != *buf;
346
294
    rule = rule->next) ;
347
91
  if (!rule) {
348
21
    sc_log(ctx, "referenced EF_rule record %d not found\n", *buf);
349
21
    return;
350
21
  }
351
352
70
  sc_hex_dump(rule->data, rule->datalen, dbgbuf, sizeof dbgbuf);
353
70
  sc_log(ctx,
354
70
    "rule for record %d:\n%s", *buf, dbgbuf);
355
356
70
  p = rule->data;
357
70
  left = rule->datalen;
358
70
  skip = 1;   /* Skip over initial unknown SC DOs. */
359
385
  for (;;) {
360
385
    buf = p;
361
385
    if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS
362
333
        || p == NULL)
363
70
      break;
364
315
    left -= (size_t)(p - buf);
365
315
    tag |= cla;
366
367
315
    if (tag == 0x80 && taglen != 1) {
368
16
      skip = 1;
369
299
    } else if (tag == 0x80) { /* AM byte. */
370
9
      sc_log(ctx, "  AM_DO: %02x\n", *p);
371
9
      skip = 0;
372
290
    } else if (tag >= 0x81 && tag <= 0x8f) { /* Cmd description */
373
90
      sc_hex_dump(p, taglen, dbgbuf, sizeof dbgbuf);
374
90
      sc_log(ctx, "  AM_DO: cmd[%s%s%s%s] %s",
375
90
         (tag & 8) ? "C" : "",
376
90
         (tag & 4) ? "I" : "",
377
90
         (tag & 2) ? "1" : "",
378
90
         (tag & 1) ? "2" : "", dbgbuf);
379
90
      skip = 0;
380
200
    } else if (tag == 0x9C) { /* Proprietary state machine descrip. */
381
8
      skip = 1;
382
192
    } else if (!skip) {
383
157
      switch (tag) {
384
6
      case 0x90:  /* Always */
385
6
        sc_log(ctx, "     SC: always\n");
386
6
        break;
387
10
      case 0x97:  /* Never */
388
10
        sc_log(ctx, "     SC: never\n");
389
10
        break;
390
15
      case 0xA4:  /* Authentication, value is a CRT. */
391
15
        sc_log_hex(ctx, "     SC: auth", p, taglen);
392
15
        break;
393
394
11
      case 0xB4:
395
21
      case 0xB6:
396
35
      case 0xB8:  /* Cmd or resp with SM, value is a CRT. */
397
35
        sc_log_hex(ctx, "     SC: cmd/resp", p, taglen);
398
35
        break;
399
400
11
      case 0x9E:  /* Security Condition byte. */
401
11
        sc_log_hex(ctx, "     SC: condition", p, taglen);
402
11
        break;
403
404
10
      case 0xA0:  /* OR template. */
405
10
        sc_log(ctx, "     SC: OR\n");
406
10
        break;
407
10
      case 0xAF:  /* AND template. */
408
10
        sc_log(ctx, "     SC: AND\n");
409
10
        break;
410
157
      }
411
157
    }
412
315
    left -= taglen;
413
315
    p += taglen;
414
315
  }
415
416
70
}
417
418
static void process_fcp(sc_card_t * card, sc_file_t * file,
419
      const u8 * buf, size_t buflen)
420
218
{
421
218
  sc_context_t *ctx = card->ctx;
422
218
  size_t taglen, len = buflen;
423
218
  const u8 *tag = NULL, *p = buf;
424
218
  int bad_fde = 0;
425
426
218
  sc_log(ctx, "processing FCI bytes\n");
427
428
  /* File identifier. */
429
218
  tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
430
218
  if (tag != NULL && taglen == 2) {
431
9
    file->id = (tag[0] << 8) | tag[1];
432
9
    sc_log(ctx,
433
9
      "  file identifier: 0x%02X%02X\n", tag[0], tag[1]);
434
9
  }
435
  /* Number of data bytes in the file including structural information. */
436
218
  tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen);
437
218
  if (!tag) {
438
    /* My card does not encode the filelength in 0x81 but
439
       in 0x85 which is the file descriptor extension in TCOS.
440
       Assume that this is the case when the regular file
441
       size tag is not encoded. */
442
177
    tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
443
177
    bad_fde = !!tag;
444
177
  }
445
218
  if (tag != NULL && taglen >= 2) {
446
30
    int bytes = (tag[0] << 8) + tag[1];
447
30
    sc_log(ctx,
448
30
      "  bytes in file: %d\n", bytes);
449
30
    file->size = (size_t)bytes;
450
30
  }
451
218
  if (tag == NULL) {
452
172
    tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
453
172
    if (tag != NULL && taglen >= 2) {
454
68
      int bytes = (tag[0] << 8) + tag[1];
455
68
      sc_log(ctx,
456
68
        "  bytes in file: %d\n", bytes);
457
68
      file->size = (size_t)bytes;
458
68
    }
459
172
  }
460
461
  /* File descriptor byte(s). */
462
218
  tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
463
218
  if (tag != NULL) {
464
    /* Fixme, this might actual be up to 6 bytes. */
465
41
    if (taglen > 0) {
466
35
      unsigned char byte = tag[0];
467
35
      const char *type;
468
469
35
      file->shareable = byte & 0x40 ? 1 : 0;
470
35
      sc_log(ctx,
471
35
        "  shareable: %s\n",
472
35
         (byte & 0x40) ? "yes" : "no");
473
35
      file->ef_structure = byte & 0x07;
474
35
      switch ((byte >> 3) & 7) {
475
22
      case 0:
476
22
        type = "working EF";
477
22
        file->type = SC_FILE_TYPE_WORKING_EF;
478
22
        break;
479
3
      case 1:
480
3
        type = "internal EF";
481
3
        file->type = SC_FILE_TYPE_INTERNAL_EF;
482
3
        break;
483
6
      case 7:
484
6
        type = "DF";
485
6
        file->type = SC_FILE_TYPE_DF;
486
6
        break;
487
4
      default:
488
4
        type = "unknown";
489
4
        break;
490
35
      }
491
35
      sc_log(ctx,
492
35
        "  type: %s\n", type);
493
35
      sc_log(ctx,
494
35
        "  EF structure: %d\n", byte & 0x07);
495
35
    }
496
41
  }
497
498
  /* DF name. */
499
218
  tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
500
218
  if (tag != NULL && taglen > 0 && taglen <= 16) {
501
33
    char name[17];
502
33
    size_t i;
503
504
33
    memcpy(file->name, tag, taglen);
505
33
    file->namelen = taglen;
506
507
255
    for (i = 0; i < taglen; i++) {
508
222
      if (isalnum(tag[i]) || ispunct(tag[i]) || isspace(tag[i]))
509
134
        name[i] = (const char)tag[i];
510
88
      else
511
88
        name[i] = '?';
512
222
    }
513
33
    name[taglen] = 0;
514
33
    sc_log(ctx, "  file name: %s\n", name);
515
33
  }
516
517
  /* Proprietary information. */
518
218
  tag = bad_fde ? NULL : sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
519
218
  if (tag != NULL && taglen) {
520
3
    sc_file_set_prop_attr(file, tag, taglen);
521
3
  } else
522
215
    file->prop_attr_len = 0;
523
524
  /* Proprietary information, constructed. */
525
218
  tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen);
526
218
  if (tag != NULL && taglen) {
527
3
    sc_file_set_prop_attr(file, tag, taglen);
528
3
  }
529
530
  /* Security attributes, proprietary format. */
531
218
  tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen);
532
218
  if (tag != NULL && taglen) {
533
8
    sc_file_set_sec_attr(file, tag, taglen);
534
8
  }
535
536
  /* Security attributes, reference to expanded format. */
537
218
  tag = sc_asn1_find_tag(ctx, p, len, 0x8B, &taglen);
538
218
  if (tag && taglen) {
539
92
    process_arr(card, tag, taglen);
540
126
  } else if ((tag = sc_asn1_find_tag(ctx, p, len, 0xA1, &taglen))
541
5
      && taglen) {
542
    /* Not found, but there is a Security Attribute
543
       Template for interface mode. */
544
4
    tag = sc_asn1_find_tag(ctx, tag, taglen, 0x8B, &taglen);
545
4
    if (tag && taglen)
546
0
      process_arr(card, tag, taglen);
547
4
  }
548
549
218
  file->magic = SC_FILE_MAGIC;
550
218
}
551
552
/* Send a select command and parse the response. */
553
static int
554
do_select(sc_card_t * card, u8 kind,
555
    const u8 * buf, size_t buflen, sc_file_t ** file)
556
2.42k
{
557
2.42k
  sc_apdu_t apdu;
558
2.42k
  u8 resbuf[SC_MAX_APDU_BUFFER_SIZE];
559
2.42k
  int r;
560
561
2.42k
  u8 p2 = 0x00;
562
2.42k
  if (kind == MCRD_SEL_EF) p2 = 0x04;
563
2.42k
  if (kind == MCRD_SEL_DF) p2 = 0x0C;
564
565
2.42k
  sc_format_apdu_ex(&apdu, 0x00, 0xA4, kind, p2, buf, buflen, resbuf, 256);
566
2.42k
  r = sc_transmit_apdu(card, &apdu);
567
2.42k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
568
2.39k
  if (!file) {
569
1.82k
    if (apdu.sw1 == 0x61)
570
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
571
1.82k
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
572
1.82k
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
573
1.82k
  }
574
570
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
575
570
  if (r)
576
258
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
577
578
312
  if (p2 == 0x0C) {
579
23
    if (file) {
580
23
      *file = sc_file_new();
581
23
      if (!*file)
582
23
        LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
583
23
      (*file)->type = SC_FILE_TYPE_DF;
584
23
      return SC_SUCCESS;
585
23
    }
586
23
  }
587
588
289
  if (p2 == 0x04 && apdu.resplen > 2 && apdu.resp[0] == 0x62) {
589
18
    *file = sc_file_new();
590
18
    if (!*file)
591
18
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
592
18
    if (apdu.resp[1] > apdu.resplen - 2)
593
18
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
594
11
    process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
595
11
    return SC_SUCCESS;
596
18
  }
597
598
271
  if (p2 != 0x0C && apdu.resplen > 2 && apdu.resp[0] == 0x6F) {
599
214
    if (apdu.resp[1] > apdu.resplen - 2)
600
214
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
601
207
    *file = sc_file_new();
602
207
    if (!*file)
603
207
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
604
207
    process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
605
207
    return SC_SUCCESS;
606
207
  }
607
57
  return SC_SUCCESS;
608
271
}
609
610
/* Wrapper around do_select to be used when multiple selects are
611
   required. */
612
static int
613
select_part(sc_card_t * card, u8 kind, unsigned short int fid,
614
    sc_file_t ** file)
615
2.02k
{
616
2.02k
  u8 fbuf[2];
617
2.02k
  unsigned int len;
618
2.02k
  int r;
619
620
2.02k
  sc_log(card->ctx,
621
2.02k
    "select_part (0x%04X, kind=%u)\n", fid, kind);
622
623
2.02k
  if (fid == MFID) {
624
897
    kind = MCRD_SEL_MF; /* force this kind. */
625
897
    len = 0;
626
1.12k
  } else {
627
1.12k
    fbuf[0] = fid >> 8;
628
1.12k
    fbuf[1] = fid & 0xff;
629
1.12k
    len = 2;
630
1.12k
  }
631
2.02k
  r = do_select(card, kind, fbuf, len, file);
632
633
2.02k
  return r;
634
2.02k
}
635
636
/* Select a file by iterating over the FID in the PATHPTR array while
637
   updating the curpath kept in the private data cache.  With DF_ONLY
638
   passed as true only DF are selected, otherwise the function tries
639
   to figure out whether the last path item is a DF or EF. */
640
static int
641
select_down(sc_card_t * card,
642
    unsigned short *pathptr, size_t pathlen,
643
    int df_only, sc_file_t ** file)
644
937
{
645
937
  struct mcrd_priv_data *priv = DRVDATA(card);
646
937
  int r;
647
937
  int found_ef = 0;
648
649
937
  if (!pathlen)
650
0
    return SC_ERROR_INVALID_ARGUMENTS;
651
652
1.54k
  for (; pathlen; pathlen--, pathptr++) {
653
1.16k
    if (priv->curpathlen == MAX_CURPATH)
654
1.16k
      LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL,
655
1.16k
          "path too long for cache");
656
1.16k
    r = -1;   /* force DF select. */
657
1.16k
    if (pathlen == 1 && !df_only) {
658
      /* first try to select an EF and retry an DF
659
         on error. */
660
562
      r = select_part(card, MCRD_SEL_EF, *pathptr, file);
661
562
      if (!r)
662
263
        found_ef = 1;
663
562
    }
664
1.16k
    if (r)
665
899
      r = select_part(card, MCRD_SEL_DF, *pathptr,
666
899
          pathlen == 1 ? file : NULL);
667
1.16k
    LOG_TEST_RET(card->ctx, r, "unable to select DF");
668
610
    priv->curpath[priv->curpathlen] = *pathptr;
669
610
    priv->curpathlen++;
670
610
  }
671
385
  priv->is_ef = found_ef;
672
385
  if (!found_ef)
673
122
    load_special_files(card);
674
675
385
  return 0;
676
937
}
677
678
/* Handle the selection case when a PATH is requested.  Our card does
679
   not support this addressing so we have to emulate it.  To keep the
680
   security status we should not unnecessary change the directory;
681
   this is accomplished be keeping track of the currently selected
682
   file.  Note that PATH is an array of PATHLEN file ids and not the
683
   usual sc_path structure. */
684
685
static int
686
select_file_by_path(sc_card_t * card, unsigned short *pathptr,
687
      size_t pathlen, sc_file_t ** file)
688
1.24k
{
689
1.24k
  struct mcrd_priv_data *priv = DRVDATA(card);
690
1.24k
  int r;
691
1.24k
  size_t i;
692
693
1.24k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
694
695
1.24k
  if (!(!priv->curpathlen || priv->curpath[0] == MFID))
696
0
    return SC_ERROR_INTERNAL;
697
698
1.24k
  if (pathlen && *pathptr == 0x3FFF) {
699
0
    pathlen--;
700
0
    pathptr++;
701
0
  }
702
703
1.24k
  if (!pathlen || pathlen >= MAX_CURPATH)
704
0
    r = SC_ERROR_INVALID_ARGUMENTS;
705
1.24k
  else if (pathlen == 1 && pathptr[0] == MFID) {
706
    /* MF requested: clear the cache and select it. */
707
300
    priv->curpathlen = 0;
708
300
    r = select_part(card, MCRD_SEL_MF, pathptr[0], file);
709
300
    LOG_TEST_RET(card->ctx, r, "unable to select MF");
710
71
    priv->curpath[0] = pathptr[0];
711
71
    priv->curpathlen = 1;
712
71
    priv->is_ef = 0;
713
944
  } else if (pathlen > 1 && pathptr[0] == MFID) {
714
    /* Absolute addressing, check cache to avoid
715
       unnecessary selects. */
716
697
    for (i = 0; (i < pathlen && i < priv->curpathlen
717
197
        && pathptr[i] == priv->curpath[i]); i++) ;
718
597
    if (!priv->curpathlen) {
719
      /* Need to do all selects starting at the root. */
720
500
      priv->curpathlen = 0;
721
500
      priv->is_ef = 0;
722
500
      r = select_down(card, pathptr, pathlen, 0, file);
723
500
    } else if (i == pathlen && i < priv->curpathlen) {
724
      /* Go upwards; we do it the easy way and start
725
         at the root.  However we know that the target is a DF. */
726
0
      priv->curpathlen = 0;
727
0
      priv->is_ef = 0;
728
0
      r = select_down(card, pathptr, pathlen, 1, file);
729
97
    } else if (i == pathlen && i == priv->curpathlen) {
730
      /* Already selected. */
731
0
      if (!file)
732
0
        r = 0; /* The caller did not request the fci. */
733
0
      else {
734
        /* This EF or DF was already selected, but
735
           we need to get the FCI, so we have
736
           to select again. */
737
0
        if (!(priv->curpathlen > 1))
738
0
          return SC_ERROR_INTERNAL;
739
0
        priv->curpathlen--;
740
0
        priv->is_ef = 0;
741
0
        r = select_down(card, pathptr + pathlen - 1, 1,
742
0
            0, file);
743
0
      }
744
97
    } else {
745
      /* We have to append something.  For now we
746
         simply start at the root. (fixme) */
747
97
      priv->curpathlen = 0;
748
97
      priv->is_ef = 0;
749
97
      r = select_down(card, pathptr, pathlen, 0, file);
750
97
    }
751
597
  } else {
752
    /* Relative addressing. */
753
347
    if (!priv->curpathlen) {
754
      /* Relative addressing without a current path. So we
755
         select the MF first. */
756
48
      r = select_part(card, MCRD_SEL_MF, pathptr[0], file);
757
48
      LOG_TEST_RET(card->ctx, r, "unable to select MF");
758
41
      priv->curpath[0] = pathptr[0];
759
41
      priv->curpathlen = 1;
760
41
      priv->is_ef = 0;
761
41
    }
762
340
    if (priv->is_ef) {
763
35
      if(!(priv->curpathlen > 1))
764
0
        return SC_ERROR_INTERNAL;
765
35
      priv->curpathlen--;
766
35
      priv->is_ef = 0;
767
35
    }
768
    /* Free the previously allocated file so we do not leak memory here */
769
340
    if (file) {
770
291
      sc_file_free(*file);
771
291
      *file = NULL;
772
291
    }
773
340
    r = select_down(card, pathptr, pathlen, 0, file);
774
340
  }
775
1.00k
  return r;
776
1.24k
}
777
778
static int
779
select_file_by_fid(sc_card_t * card, unsigned short *pathptr,
780
      size_t pathlen, sc_file_t ** file)
781
0
{
782
0
  struct mcrd_priv_data *priv = DRVDATA(card);
783
0
  int r;
784
785
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
786
787
0
  if (!(!priv->curpathlen || priv->curpath[0] == MFID))
788
0
    return SC_ERROR_INTERNAL;
789
790
0
  if (pathlen > 1)
791
0
    return SC_ERROR_INVALID_ARGUMENTS;
792
793
0
  if (pathlen && *pathptr == 0x3FFF)
794
0
    return 0;
795
796
0
  if (!pathlen) {
797
    /* re-select the current one if needed. */
798
0
    if (!file)
799
0
      r = 0; /* The caller did not request the fci. */
800
0
    else if (!priv->curpathlen) {
801
      /* There is no current file. */
802
0
      r = SC_ERROR_INTERNAL;
803
0
    } else {
804
0
      if (!(priv->curpathlen > 1))
805
0
        return SC_ERROR_INTERNAL;
806
0
      priv->curpathlen--;
807
0
      priv->is_ef = 0;
808
0
      r = select_down(card, pathptr, 1, 0, file);
809
0
    }
810
0
  } else if (pathptr[0] == MFID) {
811
    /* MF requested: clear the cache and select it. */
812
0
    priv->curpathlen = 0;
813
0
    r = select_part(card, MCRD_SEL_MF, MFID, file);
814
0
    LOG_TEST_RET(card->ctx, r, "unable to select MF");
815
0
    priv->curpath[0] = MFID;
816
0
    priv->curpathlen = 1;
817
0
    priv->is_ef = 0;
818
0
  } else {
819
    /* Relative addressing. */
820
0
    if (!priv->curpathlen) {
821
      /* Relative addressing without a current path. So we
822
         select the MF first. */
823
0
      r = select_part(card, MCRD_SEL_MF, pathptr[0], file);
824
0
      LOG_TEST_RET(card->ctx, r, "unable to select MF");
825
0
      priv->curpath[0] = pathptr[0];
826
0
      priv->curpathlen = 1;
827
0
      priv->is_ef = 0;
828
0
    }
829
0
    if (priv->is_ef) {
830
0
      if (!(priv->curpathlen > 1))
831
0
        return SC_ERROR_INTERNAL;
832
0
      priv->curpathlen--;
833
0
      priv->is_ef = 0;
834
0
    }
835
    /* Free the previously allocated file so we do not leak memory here */
836
0
    if (file) {
837
0
      sc_file_free(*file);
838
0
      *file = NULL;
839
0
    }
840
0
    r = select_down(card, pathptr, 1, 0, file);
841
0
  }
842
843
0
  return r;
844
0
}
845
846
/* This drivers select command handler. */
847
static int
848
mcrd_select_file(sc_card_t * card, const sc_path_t * path, sc_file_t ** file)
849
1.64k
{
850
1.64k
  struct mcrd_priv_data *priv = DRVDATA(card);
851
1.64k
  int r = 0;
852
853
1.64k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
854
855
1.64k
  if (path->type == SC_PATH_TYPE_DF_NAME) {
856
405
    if (path->len > 16)
857
0
      return SC_ERROR_INVALID_ARGUMENTS;
858
405
    r = do_select(card, MCRD_SEL_AID, path->value, path->len, file);
859
405
    priv->curpathlen = 0;
860
1.24k
  } else {
861
1.24k
    unsigned short int pathtmp[SC_MAX_PATH_SIZE / 2];
862
1.24k
    unsigned short int *pathptr;
863
1.24k
    int samepath = 1;
864
1.24k
    size_t pathlen, n;
865
866
1.24k
    if ((path->len & 1) || path->len > sizeof(pathtmp))
867
0
      return SC_ERROR_INVALID_ARGUMENTS;
868
869
1.24k
    memset(pathtmp, 0, sizeof pathtmp);
870
1.24k
    pathptr = pathtmp;
871
3.51k
    for (n = 0; n < path->len; n += 2)
872
2.26k
      pathptr[n >> 1] =
873
2.26k
        (unsigned short)((path->value[n] << 8) | path->value[n + 1]);
874
1.24k
    pathlen = path->len >> 1;
875
876
1.24k
    if (pathlen == priv->curpathlen && priv->is_ef != 2) {
877
797
      for (n = 0; n < pathlen; n++) {
878
497
        if (priv->curpath[n] != pathptr[n]) {
879
97
          samepath = 0;
880
97
          break;
881
97
        }
882
497
      }
883
847
    } else if (priv->curpathlen < pathlen && priv->is_ef != 2) {
884
1.26k
      for (n = 0; n < priv->curpathlen; n++) {
885
425
        if (priv->curpath[n] != pathptr[n]) {
886
2
          samepath = 0;
887
2
          break;
888
2
        }
889
425
      }
890
843
      pathptr = pathptr + n;
891
843
      pathlen = pathlen - n;
892
843
    }
893
894
1.24k
    if (samepath != 1 || priv->is_ef == 0 || priv->is_ef == 1) {
895
1.24k
      if (path->type == SC_PATH_TYPE_PATH)
896
1.24k
        r = select_file_by_path(card, pathptr, pathlen, file);
897
0
      else { /* SC_PATH_TYPE_FILEID */
898
0
        r = select_file_by_fid(card, pathptr, pathlen, file);
899
0
      }
900
1.24k
    }
901
1.24k
  }
902
903
1.64k
  return r;
904
1.64k
}
905
906
/* It seems that MICARDO does not fully comply with ISO, so I use
907
   values gathered from peeking actual signing operations using a
908
   different system.
909
   It has been generalized [?] and modified by information coming from
910
   openpgp card implementation and some other sources. -mp
911
   */
912
static int mcrd_set_security_env(sc_card_t * card,
913
         const sc_security_env_t * env, int se_num)
914
0
{
915
0
  struct mcrd_priv_data *priv;
916
0
  sc_apdu_t apdu;
917
0
  u8 sbuf[5] = {0x83, 0x03, 0x80, 0, 0};
918
0
  int r = 0, locked = 0;
919
920
0
  if (card == NULL || env == NULL)
921
0
    return SC_ERROR_INTERNAL;
922
0
  LOG_FUNC_CALLED(card->ctx);
923
0
  priv = DRVDATA(card);
924
925
  /* some sanity checks */
926
0
  if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
927
0
    if (env->algorithm != SC_ALGORITHM_RSA)
928
0
      return SC_ERROR_INVALID_ARGUMENTS;
929
0
  }
930
0
  if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)
931
0
    || env->key_ref_len != 1)
932
0
    return SC_ERROR_INVALID_ARGUMENTS;
933
934
0
  switch (env->operation) {
935
0
  case SC_SEC_OPERATION_DECIPHER:
936
0
    sc_log(card->ctx, "Using keyref %d to decipher\n", env->key_ref[0]);
937
0
    mcrd_delete_ref_to_authkey(card);
938
0
    mcrd_delete_ref_to_signkey(card);
939
0
    break;
940
0
  case SC_SEC_OPERATION_SIGN:
941
0
    sc_log(card->ctx, "Using keyref %d to sign\n", env->key_ref[0]);
942
0
    break;
943
0
  default:
944
0
    return SC_ERROR_INVALID_ARGUMENTS;
945
0
  }
946
0
  priv->sec_env = *env;
947
948
0
  sbuf[3] = env->key_ref[0];
949
0
  switch (env->operation) {
950
0
  case SC_SEC_OPERATION_DECIPHER:
951
0
    sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x41, 0xB8, sbuf, 5, NULL, 0);
952
0
    break;
953
0
  case SC_SEC_OPERATION_SIGN:
954
0
    sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x41, 0xB6, sbuf, 5, NULL, 0);
955
0
    break;
956
0
  default:
957
0
    return SC_ERROR_INVALID_ARGUMENTS;
958
0
  }
959
960
0
  if (se_num > 0) {
961
0
    r = sc_lock(card);
962
0
    LOG_TEST_RET(card->ctx, r, "sc_lock() failed");
963
0
    locked = 1;
964
0
  }
965
0
  if (apdu.datalen != 0) {
966
0
    r = sc_transmit_apdu(card, &apdu);
967
0
    if (r) {
968
0
      sc_log(card->ctx,
969
0
        "%s: APDU transmit failed", sc_strerror(r));
970
0
      goto err;
971
0
    }
972
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
973
0
    if (r) {
974
0
      sc_log(card->ctx,
975
0
        "%s: Card returned error", sc_strerror(r));
976
0
      goto err;
977
0
    }
978
0
  }
979
0
  if (se_num <= 0)
980
0
    return 0;
981
0
  sc_unlock(card);
982
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
983
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
984
0
err:
985
0
  if (locked)
986
0
    sc_unlock(card);
987
0
  return r;
988
0
}
989
990
/* heavily modified by -mp */
991
static int mcrd_compute_signature(sc_card_t * card,
992
          const u8 * data, size_t datalen,
993
          u8 * out, size_t outlen)
994
0
{
995
0
  struct mcrd_priv_data *priv = DRVDATA(card);
996
0
  sc_security_env_t *env = NULL;
997
0
  int r;
998
0
  sc_apdu_t apdu;
999
1000
0
  if (data == NULL || out == NULL)
1001
0
    return SC_ERROR_INVALID_ARGUMENTS;
1002
0
  env = &priv->sec_env;
1003
1004
0
  LOG_FUNC_CALLED(card->ctx);
1005
0
  if (env->operation != SC_SEC_OPERATION_SIGN)
1006
0
    return SC_ERROR_INVALID_ARGUMENTS;
1007
0
  if (datalen > 255)
1008
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
1009
1010
0
  sc_log(card->ctx,
1011
0
     "Will compute signature (%d) for %"SC_FORMAT_LEN_SIZE_T"u (0x%02"SC_FORMAT_LEN_SIZE_T"x) bytes using key %d algorithm %lu flags %lu\n",
1012
0
     env->operation, datalen, datalen, env->key_ref[0],
1013
0
     env->algorithm, env->algorithm_flags);
1014
1015
0
  if (env->key_ref[0] == 1) /* authentication key */
1016
0
    sc_format_apdu_ex(&apdu, 0x00, 0x88, 0, 0, data, datalen, out, MIN(0x80U, outlen));
1017
0
  else
1018
0
    sc_format_apdu_ex(&apdu, 0x00, 0x2A, 0x9E, 0x9A, data, datalen, out, MIN(0x80U, outlen));
1019
0
  r = sc_transmit_apdu(card, &apdu);
1020
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1021
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1022
0
  LOG_TEST_RET(card->ctx, r, "Card returned error");
1023
1024
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)apdu.resplen);
1025
0
}
1026
1027
/* added by -mp, to give pin information in the card driver (pkcs15emu->driver needed) */
1028
static int mcrd_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data,
1029
      int *tries_left)
1030
1
{
1031
1
  LOG_FUNC_CALLED(card->ctx);
1032
1
  data->pin1.offset = 5;
1033
1
  data->pin2.offset = 5;
1034
1035
1
  if (card->type == SC_CARD_TYPE_MCRD_GENERIC) {
1036
1
    sc_log(card->ctx, "modify pin reference for D-Trust\n");
1037
1
    if (data->pin_reference == 0x02)
1038
1
      data->pin_reference = data->pin_reference | 0x80;
1039
1
  }
1040
1
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, iso_ops->pin_cmd(card, data, tries_left));
1041
1
}
1042
1043
static int mcrd_logout(sc_card_t * card)
1044
0
{
1045
0
  return SC_ERROR_NOT_SUPPORTED;
1046
0
}
1047
1048
/* Driver binding */
1049
static struct sc_card_driver *sc_get_driver(void)
1050
14.0k
{
1051
14.0k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
1052
14.0k
  if (iso_ops == NULL)
1053
1
    iso_ops = iso_drv->ops;
1054
1055
14.0k
  mcrd_ops = *iso_drv->ops;
1056
14.0k
  mcrd_ops.match_card = mcrd_match_card;
1057
14.0k
  mcrd_ops.init = mcrd_init;
1058
14.0k
  mcrd_ops.finish = mcrd_finish;
1059
14.0k
  mcrd_ops.select_file = mcrd_select_file;
1060
14.0k
  mcrd_ops.set_security_env = mcrd_set_security_env;
1061
14.0k
  mcrd_ops.compute_signature = mcrd_compute_signature;
1062
14.0k
  mcrd_ops.pin_cmd = mcrd_pin_cmd;
1063
14.0k
  mcrd_ops.logout = mcrd_logout;
1064
1065
14.0k
  return &mcrd_drv;
1066
14.0k
}
1067
1068
struct sc_card_driver *sc_get_mcrd_driver(void)
1069
14.0k
{
1070
14.0k
  return sc_get_driver();
1071
14.0k
}