Coverage Report

Created: 2025-07-12 06:53

/src/opensc/src/libopensc/card-mcrd.c
Line
Count
Source (jump to first uncovered line)
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
0
#define MFID 0x3F00
68
0
#define EF_KeyD 0x0013    /* File with extra key information. */
69
0
#define EF_Rule 0x0030    /* Default ACL file. */
70
71
0
#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
0
#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
0
{
112
0
  sc_context_t *ctx = card->ctx;
113
0
  struct mcrd_priv_data *priv = DRVDATA(card);
114
0
  struct df_info_s *dfi;
115
116
0
  if(!(!priv->is_ef))
117
0
    return NULL;
118
119
0
  if (!priv->curpathlen) {
120
0
    sc_log(ctx, "no current path to find the df_info\n");
121
0
    return NULL;
122
0
  }
123
124
0
  for (dfi = priv->df_infos; dfi; dfi = dfi->next) {
125
0
    if (dfi->pathlen == priv->curpathlen
126
0
      && !memcmp(dfi->path, priv->curpath,
127
0
          dfi->pathlen * sizeof *dfi->path))
128
0
      return dfi;
129
0
  }
130
  /* Not found, create it. */
131
0
  dfi = calloc(1, sizeof *dfi);
132
0
  if (!dfi) {
133
0
    sc_log(ctx, "out of memory while allocating df_info\n");
134
0
    return NULL;
135
0
  }
136
0
  dfi->pathlen = priv->curpathlen;
137
0
  memcpy(dfi->path, priv->curpath, dfi->pathlen * sizeof *dfi->path);
138
0
  dfi->next = priv->df_infos;
139
0
  priv->df_infos = dfi;
140
0
  return dfi;
141
0
}
142
143
static void clear_special_files(struct df_info_s *dfi)
144
0
{
145
0
  if (dfi) {
146
0
    while (dfi->rule_file) {
147
0
      struct rule_record_s *tmp = dfi->rule_file->next;
148
0
      free(dfi->rule_file);
149
0
      dfi->rule_file = tmp;
150
0
    }
151
0
    while (dfi->keyd_file) {
152
0
      struct keyd_record_s *tmp = dfi->keyd_file->next;
153
0
      free(dfi->keyd_file);
154
0
      dfi->keyd_file = tmp;
155
0
    }
156
0
  }
157
0
}
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
0
{
192
0
  int i = 0;
193
194
0
  i = _sc_match_atr(card, mcrd_atrs, &card->type);
195
0
  if (i >= 0) {
196
0
    card->name = mcrd_atrs[i].name;
197
0
    return 1;
198
0
  }
199
200
0
  return 0;
201
0
}
202
203
static int mcrd_init(sc_card_t * card)
204
0
{
205
0
  unsigned long flags;
206
0
  struct mcrd_priv_data *priv = calloc(1, sizeof *priv);
207
0
  if (!priv)
208
0
    return SC_ERROR_OUT_OF_MEMORY;
209
0
  priv->curpath[0] = MFID;
210
0
  priv->curpathlen = 1;
211
0
  card->drv_data = priv;
212
0
  card->cla = 0x00;
213
0
  card->caps = SC_CARD_CAP_RNG;
214
215
0
  flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE;
216
0
  _sc_card_add_rsa_alg(card, 512, flags, 0);
217
0
  _sc_card_add_rsa_alg(card, 768, flags, 0);
218
0
  _sc_card_add_rsa_alg(card, 1024, flags, 0);
219
220
0
  if (SC_SUCCESS != sc_select_file (card, sc_get_mf_path(), NULL))
221
0
    sc_log(card->ctx, "Warning: select MF failed");
222
223
0
  load_special_files(card);
224
225
0
  return SC_SUCCESS;
226
0
}
227
228
static int mcrd_finish(sc_card_t * card)
229
0
{
230
0
  struct mcrd_priv_data *priv;
231
232
0
  if (card == NULL)
233
0
    return 0;
234
0
  priv = DRVDATA(card);
235
0
  while (priv->df_infos) {
236
0
    struct df_info_s *tmp = priv->df_infos->next;
237
0
    clear_special_files(priv->df_infos);
238
0
    free(priv->df_infos);
239
0
    priv->df_infos = tmp;
240
0
  }
241
0
  free(priv);
242
0
  return 0;
243
0
}
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
0
{
249
0
  sc_context_t *ctx = card->ctx;
250
0
  int r;
251
0
  unsigned int recno;
252
0
  struct df_info_s *dfi;
253
0
  struct rule_record_s *rule;
254
0
  struct keyd_record_s *keyd;
255
256
  /* First check whether we already cached it. */
257
0
  dfi = get_df_info(card);
258
0
  if (dfi && dfi->rule_file)
259
0
    return 0; /* yes. */
260
0
  clear_special_files(dfi);
261
0
  if (!dfi)
262
0
    LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
263
264
  /* Read rule file. Note that we bypass our cache here. */
265
0
  r = select_part(card, MCRD_SEL_EF, EF_Rule, NULL);
266
0
  LOG_TEST_RET(ctx, r, "selecting EF_Rule failed");
267
268
0
  for (recno = 1;; recno++) {
269
0
    u8 recbuf[256];
270
0
    r = sc_read_record(card, recno, 0, recbuf, sizeof(recbuf),
271
0
          SC_RECORD_BY_REC_NR);
272
273
0
    if (r == SC_ERROR_RECORD_NOT_FOUND)
274
0
      break;
275
0
    if (r < 0) {
276
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
277
0
    } else {
278
0
      rule = malloc(sizeof *rule + (size_t)r);
279
0
      if (!rule)
280
0
        LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
281
0
      rule->recno = recno;
282
0
      rule->datalen = (size_t)r;
283
0
      memcpy(rule->data, recbuf, r);
284
0
      rule->next = dfi->rule_file;
285
0
      dfi->rule_file = rule;
286
0
    }
287
0
  }
288
289
0
  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
0
  r = select_part(card, MCRD_SEL_EF, EF_KeyD, NULL);
293
0
  if (r == SC_ERROR_FILE_NOT_FOUND) {
294
0
    sc_log(ctx, "no EF_KeyD file available\n");
295
0
    return 0; /* That is okay. */
296
0
  }
297
0
  LOG_TEST_RET(ctx, r, "selecting EF_KeyD failed");
298
299
0
  for (recno = 1;; recno++) {
300
0
    u8 recbuf[256];
301
0
    r = sc_read_record(card, recno, 0, recbuf, sizeof(recbuf),
302
0
          SC_RECORD_BY_REC_NR);
303
304
0
    if (r == SC_ERROR_RECORD_NOT_FOUND)
305
0
      break;
306
0
    if (r < 0) {
307
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
308
0
    } else {
309
0
      keyd = malloc(sizeof *keyd + (size_t)r);
310
0
      if (!keyd)
311
0
        LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
312
0
      keyd->recno = recno;
313
0
      keyd->datalen = (size_t) r;
314
0
      memcpy(keyd->data, recbuf, r);
315
0
      keyd->next = dfi->keyd_file;
316
0
      dfi->keyd_file = keyd;
317
0
    }
318
0
  }
319
320
0
  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
0
  return 0;
324
0
}
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
0
{
329
0
  sc_context_t *ctx = card->ctx;
330
0
  struct df_info_s *dfi;
331
0
  struct rule_record_s *rule;
332
0
  size_t left, taglen;
333
0
  unsigned int cla, tag;
334
0
  const u8 *p;
335
0
  int skip;
336
0
  char dbgbuf[2048];
337
338
  /* Currently we support only the short for. */
339
0
  if (buflen != 1) {
340
0
    sc_log(ctx, "can't handle long ARRs\n");
341
0
    return;
342
0
  }
343
344
0
  dfi = get_df_info(card);
345
0
  for (rule = dfi ? dfi->rule_file : NULL; rule && rule->recno != *buf;
346
0
    rule = rule->next) ;
347
0
  if (!rule) {
348
0
    sc_log(ctx, "referenced EF_rule record %d not found\n", *buf);
349
0
    return;
350
0
  }
351
352
0
  sc_hex_dump(rule->data, rule->datalen, dbgbuf, sizeof dbgbuf);
353
0
  sc_log(ctx,
354
0
    "rule for record %d:\n%s", *buf, dbgbuf);
355
356
0
  p = rule->data;
357
0
  left = rule->datalen;
358
0
  skip = 1;   /* Skip over initial unknown SC DOs. */
359
0
  for (;;) {
360
0
    buf = p;
361
0
    if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS
362
0
        || p == NULL)
363
0
      break;
364
0
    left -= (size_t)(p - buf);
365
0
    tag |= cla;
366
367
0
    if (tag == 0x80 && taglen != 1) {
368
0
      skip = 1;
369
0
    } else if (tag == 0x80) { /* AM byte. */
370
0
      sc_log(ctx, "  AM_DO: %02x\n", *p);
371
0
      skip = 0;
372
0
    } else if (tag >= 0x81 && tag <= 0x8f) { /* Cmd description */
373
0
      sc_hex_dump(p, taglen, dbgbuf, sizeof dbgbuf);
374
0
      sc_log(ctx, "  AM_DO: cmd[%s%s%s%s] %s",
375
0
         (tag & 8) ? "C" : "",
376
0
         (tag & 4) ? "I" : "",
377
0
         (tag & 2) ? "1" : "",
378
0
         (tag & 1) ? "2" : "", dbgbuf);
379
0
      skip = 0;
380
0
    } else if (tag == 0x9C) { /* Proprietary state machine descrip. */
381
0
      skip = 1;
382
0
    } else if (!skip) {
383
0
      switch (tag) {
384
0
      case 0x90:  /* Always */
385
0
        sc_log(ctx, "     SC: always\n");
386
0
        break;
387
0
      case 0x97:  /* Never */
388
0
        sc_log(ctx, "     SC: never\n");
389
0
        break;
390
0
      case 0xA4:  /* Authentication, value is a CRT. */
391
0
        sc_log_hex(ctx, "     SC: auth", p, taglen);
392
0
        break;
393
394
0
      case 0xB4:
395
0
      case 0xB6:
396
0
      case 0xB8:  /* Cmd or resp with SM, value is a CRT. */
397
0
        sc_log_hex(ctx, "     SC: cmd/resp", p, taglen);
398
0
        break;
399
400
0
      case 0x9E:  /* Security Condition byte. */
401
0
        sc_log_hex(ctx, "     SC: condition", p, taglen);
402
0
        break;
403
404
0
      case 0xA0:  /* OR template. */
405
0
        sc_log(ctx, "     SC: OR\n");
406
0
        break;
407
0
      case 0xAF:  /* AND template. */
408
0
        sc_log(ctx, "     SC: AND\n");
409
0
        break;
410
0
      }
411
0
    }
412
0
    left -= taglen;
413
0
    p += taglen;
414
0
  }
415
416
0
}
417
418
static void process_fcp(sc_card_t * card, sc_file_t * file,
419
      const u8 * buf, size_t buflen)
420
0
{
421
0
  sc_context_t *ctx = card->ctx;
422
0
  size_t taglen, len = buflen;
423
0
  const u8 *tag = NULL, *p = buf;
424
0
  int bad_fde = 0;
425
426
0
  sc_log(ctx, "processing FCI bytes\n");
427
428
  /* File identifier. */
429
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
430
0
  if (tag != NULL && taglen == 2) {
431
0
    file->id = (tag[0] << 8) | tag[1];
432
0
    sc_log(ctx,
433
0
      "  file identifier: 0x%02X%02X\n", tag[0], tag[1]);
434
0
  }
435
  /* Number of data bytes in the file including structural information. */
436
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen);
437
0
  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
0
    tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
443
0
    bad_fde = !!tag;
444
0
  }
445
0
  if (tag != NULL && taglen >= 2) {
446
0
    int bytes = (tag[0] << 8) + tag[1];
447
0
    sc_log(ctx,
448
0
      "  bytes in file: %d\n", bytes);
449
0
    file->size = (size_t)bytes;
450
0
  }
451
0
  if (tag == NULL) {
452
0
    tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
453
0
    if (tag != NULL && taglen >= 2) {
454
0
      int bytes = (tag[0] << 8) + tag[1];
455
0
      sc_log(ctx,
456
0
        "  bytes in file: %d\n", bytes);
457
0
      file->size = (size_t)bytes;
458
0
    }
459
0
  }
460
461
  /* File descriptor byte(s). */
462
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
463
0
  if (tag != NULL) {
464
    /* Fixme, this might actual be up to 6 bytes. */
465
0
    if (taglen > 0) {
466
0
      unsigned char byte = tag[0];
467
0
      const char *type;
468
469
0
      file->shareable = byte & 0x40 ? 1 : 0;
470
0
      sc_log(ctx,
471
0
        "  shareable: %s\n",
472
0
         (byte & 0x40) ? "yes" : "no");
473
0
      file->ef_structure = byte & 0x07;
474
0
      switch ((byte >> 3) & 7) {
475
0
      case 0:
476
0
        type = "working EF";
477
0
        file->type = SC_FILE_TYPE_WORKING_EF;
478
0
        break;
479
0
      case 1:
480
0
        type = "internal EF";
481
0
        file->type = SC_FILE_TYPE_INTERNAL_EF;
482
0
        break;
483
0
      case 7:
484
0
        type = "DF";
485
0
        file->type = SC_FILE_TYPE_DF;
486
0
        break;
487
0
      default:
488
0
        type = "unknown";
489
0
        break;
490
0
      }
491
0
      sc_log(ctx,
492
0
        "  type: %s\n", type);
493
0
      sc_log(ctx,
494
0
        "  EF structure: %d\n", byte & 0x07);
495
0
    }
496
0
  }
497
498
  /* DF name. */
499
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
500
0
  if (tag != NULL && taglen > 0 && taglen <= 16) {
501
0
    char name[17];
502
0
    size_t i;
503
504
0
    memcpy(file->name, tag, taglen);
505
0
    file->namelen = taglen;
506
507
0
    for (i = 0; i < taglen; i++) {
508
0
      if (isalnum(tag[i]) || ispunct(tag[i]) || isspace(tag[i]))
509
0
        name[i] = (const char)tag[i];
510
0
      else
511
0
        name[i] = '?';
512
0
    }
513
0
    name[taglen] = 0;
514
0
    sc_log(ctx, "  file name: %s\n", name);
515
0
  }
516
517
  /* Proprietary information. */
518
0
  tag = bad_fde ? NULL : sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
519
0
  if (tag != NULL && taglen) {
520
0
    sc_file_set_prop_attr(file, tag, taglen);
521
0
  } else
522
0
    file->prop_attr_len = 0;
523
524
  /* Proprietary information, constructed. */
525
0
  tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen);
526
0
  if (tag != NULL && taglen) {
527
0
    sc_file_set_prop_attr(file, tag, taglen);
528
0
  }
529
530
  /* Security attributes, proprietary format. */
531
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen);
532
0
  if (tag != NULL && taglen) {
533
0
    sc_file_set_sec_attr(file, tag, taglen);
534
0
  }
535
536
  /* Security attributes, reference to expanded format. */
537
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x8B, &taglen);
538
0
  if (tag && taglen) {
539
0
    process_arr(card, tag, taglen);
540
0
  } else if ((tag = sc_asn1_find_tag(ctx, p, len, 0xA1, &taglen))
541
0
      && taglen) {
542
    /* Not found, but there is a Security Attribute
543
       Template for interface mode. */
544
0
    tag = sc_asn1_find_tag(ctx, tag, taglen, 0x8B, &taglen);
545
0
    if (tag && taglen)
546
0
      process_arr(card, tag, taglen);
547
0
  }
548
549
0
  file->magic = SC_FILE_MAGIC;
550
0
}
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
0
{
557
0
  sc_apdu_t apdu;
558
0
  u8 resbuf[SC_MAX_APDU_BUFFER_SIZE];
559
0
  int r;
560
561
0
  u8 p2 = 0x00;
562
0
  if (kind == MCRD_SEL_EF) p2 = 0x04;
563
0
  if (kind == MCRD_SEL_DF) p2 = 0x0C;
564
565
0
  sc_format_apdu_ex(&apdu, 0x00, 0xA4, kind, p2, buf, buflen, resbuf, 256);
566
0
  r = sc_transmit_apdu(card, &apdu);
567
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
568
0
  if (!file) {
569
0
    if (apdu.sw1 == 0x61)
570
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
571
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
572
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
573
0
  }
574
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
575
0
  if (r)
576
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
577
578
0
  if (p2 == 0x0C) {
579
0
    if (file) {
580
0
      *file = sc_file_new();
581
0
      if (!*file)
582
0
        LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
583
0
      (*file)->type = SC_FILE_TYPE_DF;
584
0
      return SC_SUCCESS;
585
0
    }
586
0
  }
587
588
0
  if (p2 == 0x04 && apdu.resplen > 2 && apdu.resp[0] == 0x62) {
589
0
    *file = sc_file_new();
590
0
    if (!*file)
591
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
592
0
    if (apdu.resp[1] > apdu.resplen - 2)
593
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
594
0
    process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
595
0
    return SC_SUCCESS;
596
0
  }
597
598
0
  if (p2 != 0x0C && apdu.resplen > 2 && apdu.resp[0] == 0x6F) {
599
0
    *file = sc_file_new();
600
0
    if (!*file)
601
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
602
0
    if (apdu.resp[1] > apdu.resplen - 2)
603
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
604
0
    process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
605
0
    return SC_SUCCESS;
606
0
  }
607
0
  return SC_SUCCESS;
608
0
}
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
0
{
616
0
  u8 fbuf[2];
617
0
  unsigned int len;
618
0
  int r;
619
620
0
  sc_log(card->ctx,
621
0
    "select_part (0x%04X, kind=%u)\n", fid, kind);
622
623
0
  if (fid == MFID) {
624
0
    kind = MCRD_SEL_MF; /* force this kind. */
625
0
    len = 0;
626
0
  } else {
627
0
    fbuf[0] = fid >> 8;
628
0
    fbuf[1] = fid & 0xff;
629
0
    len = 2;
630
0
  }
631
0
  r = do_select(card, kind, fbuf, len, file);
632
633
0
  return r;
634
0
}
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
0
{
645
0
  struct mcrd_priv_data *priv = DRVDATA(card);
646
0
  int r;
647
0
  int found_ef = 0;
648
649
0
  if (!pathlen)
650
0
    return SC_ERROR_INVALID_ARGUMENTS;
651
652
0
  for (; pathlen; pathlen--, pathptr++) {
653
0
    if (priv->curpathlen == MAX_CURPATH)
654
0
      LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL,
655
0
          "path too long for cache");
656
0
    r = -1;   /* force DF select. */
657
0
    if (pathlen == 1 && !df_only) {
658
      /* first try to select an EF and retry an DF
659
         on error. */
660
0
      r = select_part(card, MCRD_SEL_EF, *pathptr, file);
661
0
      if (!r)
662
0
        found_ef = 1;
663
0
    }
664
0
    if (r)
665
0
      r = select_part(card, MCRD_SEL_DF, *pathptr,
666
0
          pathlen == 1 ? file : NULL);
667
0
    LOG_TEST_RET(card->ctx, r, "unable to select DF");
668
0
    priv->curpath[priv->curpathlen] = *pathptr;
669
0
    priv->curpathlen++;
670
0
  }
671
0
  priv->is_ef = found_ef;
672
0
  if (!found_ef)
673
0
    load_special_files(card);
674
675
0
  return 0;
676
0
}
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
0
{
689
0
  struct mcrd_priv_data *priv = DRVDATA(card);
690
0
  int r;
691
0
  size_t i;
692
693
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
694
695
0
  if (!(!priv->curpathlen || priv->curpath[0] == MFID))
696
0
    return SC_ERROR_INTERNAL;
697
698
0
  if (pathlen && *pathptr == 0x3FFF) {
699
0
    pathlen--;
700
0
    pathptr++;
701
0
  }
702
703
0
  if (!pathlen || pathlen >= MAX_CURPATH)
704
0
    r = SC_ERROR_INVALID_ARGUMENTS;
705
0
  else if (pathlen == 1 && pathptr[0] == MFID) {
706
    /* MF requested: clear the cache and select it. */
707
0
    priv->curpathlen = 0;
708
0
    r = select_part(card, MCRD_SEL_MF, pathptr[0], file);
709
0
    LOG_TEST_RET(card->ctx, r, "unable to select MF");
710
0
    priv->curpath[0] = pathptr[0];
711
0
    priv->curpathlen = 1;
712
0
    priv->is_ef = 0;
713
0
  } else if (pathlen > 1 && pathptr[0] == MFID) {
714
    /* Absolute addressing, check cache to avoid
715
       unnecessary selects. */
716
0
    for (i = 0; (i < pathlen && i < priv->curpathlen
717
0
        && pathptr[i] == priv->curpath[i]); i++) ;
718
0
    if (!priv->curpathlen) {
719
      /* Need to do all selects starting at the root. */
720
0
      priv->curpathlen = 0;
721
0
      priv->is_ef = 0;
722
0
      r = select_down(card, pathptr, pathlen, 0, file);
723
0
    } 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
0
    } 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
0
    } else {
745
      /* We have to append something.  For now we
746
         simply start at the root. (fixme) */
747
0
      priv->curpathlen = 0;
748
0
      priv->is_ef = 0;
749
0
      r = select_down(card, pathptr, pathlen, 0, file);
750
0
    }
751
0
  } else {
752
    /* Relative addressing. */
753
0
    if (!priv->curpathlen) {
754
      /* Relative addressing without a current path. So we
755
         select the MF first. */
756
0
      r = select_part(card, MCRD_SEL_MF, pathptr[0], file);
757
0
      LOG_TEST_RET(card->ctx, r, "unable to select MF");
758
0
      priv->curpath[0] = pathptr[0];
759
0
      priv->curpathlen = 1;
760
0
      priv->is_ef = 0;
761
0
    }
762
0
    if (priv->is_ef) {
763
0
      if(!(priv->curpathlen > 1))
764
0
        return SC_ERROR_INTERNAL;
765
0
      priv->curpathlen--;
766
0
      priv->is_ef = 0;
767
0
    }
768
    /* Free the previously allocated file so we do not leak memory here */
769
0
    if (file) {
770
0
      sc_file_free(*file);
771
0
      *file = NULL;
772
0
    }
773
0
    r = select_down(card, pathptr, pathlen, 0, file);
774
0
  }
775
0
  return r;
776
0
}
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
0
{
850
0
  struct mcrd_priv_data *priv = DRVDATA(card);
851
0
  int r = 0;
852
853
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
854
855
0
  if (path->type == SC_PATH_TYPE_DF_NAME) {
856
0
    if (path->len > 16)
857
0
      return SC_ERROR_INVALID_ARGUMENTS;
858
0
    r = do_select(card, MCRD_SEL_AID, path->value, path->len, file);
859
0
    priv->curpathlen = 0;
860
0
  } else {
861
0
    unsigned short int pathtmp[SC_MAX_PATH_SIZE / 2];
862
0
    unsigned short int *pathptr;
863
0
    int samepath = 1;
864
0
    size_t pathlen, n;
865
866
0
    if ((path->len & 1) || path->len > sizeof(pathtmp))
867
0
      return SC_ERROR_INVALID_ARGUMENTS;
868
869
0
    memset(pathtmp, 0, sizeof pathtmp);
870
0
    pathptr = pathtmp;
871
0
    for (n = 0; n < path->len; n += 2)
872
0
      pathptr[n >> 1] =
873
0
        (unsigned short)((path->value[n] << 8) | path->value[n + 1]);
874
0
    pathlen = path->len >> 1;
875
876
0
    if (pathlen == priv->curpathlen && priv->is_ef != 2) {
877
0
      for (n = 0; n < pathlen; n++) {
878
0
        if (priv->curpath[n] != pathptr[n]) {
879
0
          samepath = 0;
880
0
          break;
881
0
        }
882
0
      }
883
0
    } else if (priv->curpathlen < pathlen && priv->is_ef != 2) {
884
0
      for (n = 0; n < priv->curpathlen; n++) {
885
0
        if (priv->curpath[n] != pathptr[n]) {
886
0
          samepath = 0;
887
0
          break;
888
0
        }
889
0
      }
890
0
      pathptr = pathptr + n;
891
0
      pathlen = pathlen - n;
892
0
    }
893
894
0
    if (samepath != 1 || priv->is_ef == 0 || priv->is_ef == 1) {
895
0
      if (path->type == SC_PATH_TYPE_PATH)
896
0
        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
0
    }
901
0
  }
902
903
0
  return r;
904
0
}
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
0
{
1031
0
  LOG_FUNC_CALLED(card->ctx);
1032
0
  data->pin1.offset = 5;
1033
0
  data->pin2.offset = 5;
1034
1035
0
  if (card->type == SC_CARD_TYPE_MCRD_GENERIC) {
1036
0
    sc_log(card->ctx, "modify pin reference for D-Trust\n");
1037
0
    if (data->pin_reference == 0x02)
1038
0
      data->pin_reference = data->pin_reference | 0x80;
1039
0
  }
1040
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, iso_ops->pin_cmd(card, data, tries_left));
1041
0
}
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
0
{
1051
0
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
1052
0
  if (iso_ops == NULL)
1053
0
    iso_ops = iso_drv->ops;
1054
1055
0
  mcrd_ops = *iso_drv->ops;
1056
0
  mcrd_ops.match_card = mcrd_match_card;
1057
0
  mcrd_ops.init = mcrd_init;
1058
0
  mcrd_ops.finish = mcrd_finish;
1059
0
  mcrd_ops.select_file = mcrd_select_file;
1060
0
  mcrd_ops.set_security_env = mcrd_set_security_env;
1061
0
  mcrd_ops.compute_signature = mcrd_compute_signature;
1062
0
  mcrd_ops.pin_cmd = mcrd_pin_cmd;
1063
0
  mcrd_ops.logout = mcrd_logout;
1064
1065
0
  return &mcrd_drv;
1066
0
}
1067
1068
struct sc_card_driver *sc_get_mcrd_driver(void)
1069
0
{
1070
0
  return sc_get_driver();
1071
0
}