Coverage Report

Created: 2025-08-24 06:59

/src/opensc/src/libopensc/card-tcos.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * card-tcos.c: Support for TCOS cards
3
 *
4
 * Copyright (C) 2011  Peter Koch <pk@opensc-project.org>
5
 * Copyright (C) 2002  g10 Code GmbH
6
 * Copyright (C) 2001  Juha Yrjölä <juha.yrjola@iki.fi>
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
27
#include <string.h>
28
#include <ctype.h>
29
#include <time.h>
30
#include <stdlib.h>
31
32
#include "internal.h"
33
#include "asn1.h"
34
#include "cardctl.h"
35
36
static const struct sc_atr_table tcos_atrs[] = {
37
  /* Infineon SLE44 */
38
  { "3B:BA:13:00:81:31:86:5D:00:64:05:0A:02:01:31:80:90:00:8B", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
39
  /* Infineon SLE66S */
40
  { "3B:BA:14:00:81:31:86:5D:00:64:05:14:02:02:31:80:90:00:91", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
41
  /* Infineon SLE66CX320P */
42
  { "3B:BA:96:00:81:31:86:5D:00:64:05:60:02:03:31:80:90:00:66", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
43
  /* Infineon SLE66CX322P */
44
  { "3B:BA:96:00:81:31:86:5D:00:64:05:7B:02:03:31:80:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
45
  /* Philips P5CT072 */
46
  { "3B:BF:96:00:81:31:FE:5D:00:64:04:11:03:01:31:C0:73:F7:01:D0:00:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL },
47
  { "3B:BF:96:00:81:31:FE:5D:00:64:04:11:04:0F:31:C0:73:F7:01:D0:00:90:00:74", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL },
48
  /* Philips P5CT080 */
49
  { "3B:BF:B6:00:81:31:FE:5D:00:64:04:28:03:02:31:C0:73:F7:01:D0:00:90:00:67", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL },
50
  { NULL, NULL, NULL, 0, 0, NULL }
51
};
52
53
static struct sc_card_operations tcos_ops;
54
static struct sc_card_driver tcos_drv = {
55
  "TCOS 3.0",
56
  "tcos",
57
  &tcos_ops,
58
  NULL, 0, NULL
59
};
60
61
static const struct sc_card_operations *iso_ops = NULL;
62
63
typedef struct tcos_data_st {
64
  unsigned long pad_flags;
65
  unsigned int next_sign;
66
} tcos_data;
67
68
69
static int tcos_finish(sc_card_t *card)
70
0
{
71
0
  free(card->drv_data);
72
0
  return 0;
73
0
}
74
75
76
static int tcos_match_card(sc_card_t *card)
77
17.4k
{
78
17.4k
  int i;
79
80
17.4k
  i = _sc_match_atr(card, tcos_atrs, &card->type);
81
17.4k
  if (i < 0)
82
17.4k
    return 0;
83
0
  return 1;
84
17.4k
}
85
86
87
static int tcos_init(sc_card_t *card)
88
0
{
89
0
  unsigned long flags;
90
91
0
  tcos_data *data = malloc(sizeof(tcos_data));
92
0
  if (!data) return SC_ERROR_OUT_OF_MEMORY;
93
94
0
  card->name = "TCOS";
95
0
  card->drv_data = (void *)data;
96
0
  card->cla = 0x00;
97
98
0
  flags = SC_ALGORITHM_RSA_RAW;
99
0
  flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
100
0
  flags |= SC_ALGORITHM_RSA_HASH_NONE;
101
102
0
  _sc_card_add_rsa_alg(card, 512, flags, 0);
103
0
  _sc_card_add_rsa_alg(card, 768, flags, 0);
104
0
  _sc_card_add_rsa_alg(card, 1024, flags, 0);
105
106
0
  if (card->type == SC_CARD_TYPE_TCOS_V3) {
107
0
    card->caps |= SC_CARD_CAP_APDU_EXT;
108
0
    _sc_card_add_rsa_alg(card, 1280, flags, 0);
109
0
    _sc_card_add_rsa_alg(card, 1536, flags, 0);
110
0
    _sc_card_add_rsa_alg(card, 1792, flags, 0);
111
0
    _sc_card_add_rsa_alg(card, 2048, flags, 0);
112
0
  }
113
114
0
  return 0;
115
0
}
116
117
118
/* Hmmm, I don't know what to do.  It seems that the ACL design of
119
   OpenSC should be enhanced to allow for the command based security
120
   attributes of TCOS.  FIXME: This just allows to create a very basic
121
   file. */
122
static int tcos_construct_fci(const sc_file_t *file,
123
                              u8 *out, size_t *outlen)
124
0
{
125
0
  u8 *p = out;
126
0
  u8 buf[64];
127
0
  size_t n;
128
129
  /* FIXME: possible buffer overflow */
130
131
0
  *p++ = 0x6F; /* FCI */
132
0
  p++;
133
134
  /* File size */
135
0
  buf[0] = (file->size >> 8) & 0xFF;
136
0
  buf[1] = file->size & 0xFF;
137
0
  sc_asn1_put_tag(0x81, buf, 2, p, 16, &p);
138
139
  /* File descriptor */
140
0
  n = 0;
141
0
  buf[n] = file->shareable ? 0x40 : 0;
142
0
  switch (file->type) {
143
0
  case SC_FILE_TYPE_WORKING_EF:
144
0
    break;
145
0
  case SC_FILE_TYPE_DF:
146
0
    buf[0] |= 0x38;
147
0
    break;
148
0
  default:
149
0
    return SC_ERROR_NOT_SUPPORTED;
150
0
  }
151
0
  buf[n++] |= file->ef_structure & 7;
152
0
  if ( (file->ef_structure & 7) > 1) {
153
    /* record structured file */
154
0
    buf[n++] = 0x41; /* indicate 3rd byte */
155
0
    buf[n++] = file->record_length;
156
0
  }
157
0
  sc_asn1_put_tag(0x82, buf, n, p, 8, &p);
158
159
  /* File identifier */
160
0
  buf[0] = (file->id >> 8) & 0xFF;
161
0
  buf[1] = file->id & 0xFF;
162
0
  sc_asn1_put_tag(0x83, buf, 2, p, 16, &p);
163
164
  /* Directory name */
165
0
  if (file->type == SC_FILE_TYPE_DF) {
166
0
    if (file->namelen) {
167
0
      sc_asn1_put_tag(0x84, file->name, file->namelen,
168
0
                                        p, 16, &p);
169
0
    } else {
170
      /* TCOS needs one, so we use a faked one */
171
0
      snprintf ((char *) buf, sizeof(buf)-1, "foo-%lu",
172
0
                                  (unsigned long) time (NULL));
173
0
      sc_asn1_put_tag(0x84, buf, strlen ((char *) buf), p, 16, &p);
174
0
    }
175
0
  }
176
177
  /* File descriptor extension */
178
0
  if (file->prop_attr_len && file->prop_attr) {
179
0
    n = file->prop_attr_len;
180
0
    memcpy(buf, file->prop_attr, n);
181
0
  } else {
182
0
    n = 0;
183
0
    buf[n++] = 0x01; /* not invalidated, permanent */
184
0
    if (file->type == SC_FILE_TYPE_WORKING_EF)
185
0
      buf[n++] = 0x00; /* generic data file */
186
0
  }
187
0
  sc_asn1_put_tag(0x85, buf, n, p, 16, &p);
188
189
  /* Security attributes */
190
0
  if (file->sec_attr_len && file->sec_attr) {
191
0
    memcpy(buf, file->sec_attr, file->sec_attr_len);
192
0
    n = file->sec_attr_len;
193
0
  } else {
194
    /* no attributes given - fall back to default one */
195
0
    memcpy (buf+ 0, "\xa4\x00\x00\x00\xff\xff", 6); /* select */
196
0
    memcpy (buf+ 6, "\xb0\x00\x00\x00\xff\xff", 6); /* read bin */
197
0
    memcpy (buf+12, "\xd6\x00\x00\x00\xff\xff", 6); /* upd bin */
198
0
    memcpy (buf+18, "\x60\x00\x00\x00\xff\xff", 6); /* admin grp*/
199
0
    n = 24;
200
0
  }
201
0
  sc_asn1_put_tag(0x86, buf, n, p, sizeof (buf), &p);
202
203
204
  /* fixup length of FCI */
205
0
  out[1] = p - out - 2;
206
207
0
  *outlen = p - out;
208
0
  return 0;
209
0
}
210
211
212
static int tcos_create_file(sc_card_t *card, sc_file_t *file)
213
0
{
214
0
  int r;
215
0
  size_t len;
216
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
217
0
  sc_apdu_t apdu;
218
219
0
  len = SC_MAX_APDU_BUFFER_SIZE;
220
0
  r = tcos_construct_fci(file, sbuf, &len);
221
0
  LOG_TEST_RET(card->ctx, r, "tcos_construct_fci() failed");
222
223
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
224
0
  apdu.cla |= 0x80;  /* this is an proprietary extension */
225
0
  apdu.lc = len;
226
0
  apdu.datalen = len;
227
0
  apdu.data = sbuf;
228
229
0
  r = sc_transmit_apdu(card, &apdu);
230
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
231
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
232
0
}
233
234
235
static unsigned int map_operations (int commandbyte)
236
0
{
237
0
  unsigned int op = (unsigned int)-1;
238
239
0
  switch ( (commandbyte & 0xfe) ) {
240
0
    case 0xe2: /* append record */   op = SC_AC_OP_UPDATE; break;
241
0
    case 0x24: /* change password */ op = SC_AC_OP_UPDATE; break;
242
0
    case 0xe0: /* create */          op = SC_AC_OP_CREATE; break;
243
0
    case 0xe4: /* delete */          op = SC_AC_OP_DELETE; break;
244
0
    case 0xe8: /* exclude sfi */     op = SC_AC_OP_WRITE; break;
245
0
    case 0x82: /* external auth */   op = SC_AC_OP_READ; break;
246
0
    case 0xe6: /* include sfi */     op = SC_AC_OP_WRITE; break;
247
0
    case 0x88: /* internal auth */   op = SC_AC_OP_READ; break;
248
0
    case 0x04: /* invalidate */      op = SC_AC_OP_INVALIDATE; break;
249
0
    case 0x2a: /* perform sec. op */ op = SC_AC_OP_SELECT; break;
250
0
    case 0xb0: /* read binary */     op = SC_AC_OP_READ; break;
251
0
    case 0xb2: /* read record */     op = SC_AC_OP_READ; break;
252
0
    case 0x44: /* rehabilitate */    op = SC_AC_OP_REHABILITATE; break;
253
0
    case 0xa4: /* select */          op = SC_AC_OP_SELECT; break;
254
0
    case 0xee: /* set permanent */   op = SC_AC_OP_CREATE; break;
255
0
    case 0x2c: /* unblock password */op = SC_AC_OP_WRITE; break;
256
0
    case 0xd6: /* update binary */   op = SC_AC_OP_WRITE; break;
257
0
    case 0xdc: /* update record */   op = SC_AC_OP_WRITE; break;
258
0
    case 0x20: /* verify password */ op = SC_AC_OP_SELECT; break;
259
0
    case 0x60: /* admin group */     op = SC_AC_OP_CREATE; break;
260
0
  }
261
0
  return op;
262
0
}
263
264
265
/* Hmmm, I don't know what to do.  It seems that the ACL design of
266
   OpenSC should be enhanced to allow for the command based security
267
   attributes of TCOS.  FIXME: This just allows to create a very basic
268
   file. */
269
static void parse_sec_attr(sc_card_t *card,
270
                           sc_file_t *file, const u8 *buf, size_t len)
271
0
{
272
0
  unsigned int op;
273
274
  /* list directory is not covered by ACLs - so always add an entry */
275
0
  sc_file_add_acl_entry (file, SC_AC_OP_LIST_FILES,
276
0
                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
277
  /* FIXME: check for what LOCK is used */
278
0
  sc_file_add_acl_entry (file, SC_AC_OP_LOCK,
279
0
                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
280
0
  for (; len >= 6; len -= 6, buf += 6) {
281
    /* FIXME: temporary hacks */
282
0
    if (!memcmp(buf, "\xa4\x00\x00\x00\xff\xff", 6)) {/* select */
283
0
      sc_file_add_acl_entry (file, SC_AC_OP_SELECT,
284
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
285
0
    } else if (!memcmp(buf, "\xb0\x00\x00\x00\xff\xff", 6)) {/*read*/
286
0
      sc_file_add_acl_entry (file, SC_AC_OP_READ,
287
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
288
0
    } else if (!memcmp(buf, "\xd6\x00\x00\x00\xff\xff", 6)) {/*upd*/
289
0
      sc_file_add_acl_entry (file, SC_AC_OP_UPDATE,
290
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
291
0
    } else if (!memcmp(buf, "\x60\x00\x00\x00\xff\xff", 6)) {/*adm */
292
0
      sc_file_add_acl_entry (file, SC_AC_OP_WRITE,
293
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
294
0
      sc_file_add_acl_entry (file, SC_AC_OP_CREATE,
295
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
296
0
      sc_file_add_acl_entry (file, SC_AC_OP_INVALIDATE,
297
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
298
0
      sc_file_add_acl_entry (file, SC_AC_OP_REHABILITATE,
299
0
                                               SC_AC_NONE, SC_AC_KEY_REF_NONE);
300
0
    } else {
301
      /* the first byte tells use the command or the
302
         command group.  We have to mask bit 0
303
         because this one distinguish between AND/OR
304
         combination of PINs*/
305
0
      op = map_operations (buf[0]);
306
0
      if (op == (unsigned int)-1) {
307
0
        sc_log(card->ctx,
308
0
          "Unknown security command byte %02x\n",
309
0
          buf[0]);
310
0
        continue;
311
0
      }
312
0
      if (!buf[1])
313
0
        sc_file_add_acl_entry (file, op,
314
0
                                                       SC_AC_NONE,
315
0
                                                       SC_AC_KEY_REF_NONE);
316
0
      else
317
0
        sc_file_add_acl_entry (file, op,
318
0
                                                       SC_AC_CHV, buf[1]);
319
320
0
      if (!buf[2] && !buf[3])
321
0
        sc_file_add_acl_entry (file, op,
322
0
                                                       SC_AC_NONE,
323
0
                                                       SC_AC_KEY_REF_NONE);
324
0
      else
325
0
        sc_file_add_acl_entry (file, op,
326
0
                                                       SC_AC_TERM,
327
0
                                                       (buf[2]<<8)|buf[3]);
328
0
    }
329
0
  }
330
0
}
331
332
333
static int tcos_select_file(sc_card_t *card,
334
                            const sc_path_t *in_path,
335
                            sc_file_t **file_out)
336
0
{
337
0
  sc_context_t *ctx;
338
0
  sc_apdu_t apdu;
339
0
  sc_file_t *file=NULL;
340
0
  u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
341
0
  int r;
342
0
  size_t pathlen;
343
344
0
  assert(card != NULL && in_path != NULL);
345
0
  ctx=card->ctx;
346
0
  memcpy(path, in_path->value, in_path->len);
347
0
  pathlen = in_path->len;
348
349
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x04);
350
351
0
  switch (in_path->type) {
352
0
  case SC_PATH_TYPE_FILE_ID:
353
0
    if (pathlen != 2) return SC_ERROR_INVALID_ARGUMENTS;
354
    /* fall through */
355
0
  case SC_PATH_TYPE_FROM_CURRENT:
356
0
    apdu.p1 = 9;
357
0
    break;
358
0
  case SC_PATH_TYPE_DF_NAME:
359
0
    apdu.p1 = 4;
360
0
    break;
361
0
  case SC_PATH_TYPE_PATH:
362
0
    apdu.p1 = 8;
363
0
    if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) path += 2, pathlen -= 2;
364
0
    if (pathlen == 0) apdu.p1 = 0;
365
0
    break;
366
0
  case SC_PATH_TYPE_PARENT:
367
0
    apdu.p1 = 3;
368
0
    pathlen = 0;
369
0
    break;
370
0
  default:
371
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
372
0
  }
373
0
  if( pathlen == 0 ) apdu.cse = SC_APDU_CASE_2_SHORT;
374
375
0
  apdu.lc = pathlen;
376
0
  apdu.data = path;
377
0
  apdu.datalen = pathlen;
378
379
0
  if (file_out != NULL) {
380
0
    apdu.resp = buf;
381
0
    apdu.resplen = sizeof(buf);
382
0
    apdu.le = 256;
383
0
  } else {
384
0
    apdu.resplen = 0;
385
0
    apdu.le = 0;
386
0
    apdu.p2 = 0x0C;
387
0
    apdu.cse = (pathlen == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT;
388
0
  }
389
390
0
  r = sc_transmit_apdu(card, &apdu);
391
0
  LOG_TEST_RET(ctx, r, "APDU transmit failed");
392
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
393
0
  if (r || file_out == NULL) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
394
395
0
  if (apdu.resplen < 1 || apdu.resp[0] != 0x62) {
396
0
    sc_log(ctx, "received invalid template %02X\n", apdu.resp[0]);
397
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
398
0
  }
399
400
0
  file = sc_file_new();
401
0
  if (file == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
402
0
  *file_out = file;
403
0
  file->path = *in_path;
404
405
0
  iso_ops->process_fci(card, file, apdu.resp, apdu.resplen);
406
407
0
  parse_sec_attr(card, file, file->sec_attr, file->sec_attr_len);
408
409
0
  return 0;
410
0
}
411
412
413
static int tcos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
414
0
{
415
0
  sc_context_t *ctx;
416
0
  sc_apdu_t apdu;
417
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], p1;
418
0
  int r, count = 0;
419
420
0
  assert(card != NULL);
421
0
  ctx = card->ctx;
422
423
0
  for (p1=1; p1<=2; p1++) {
424
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, p1, 0);
425
0
    apdu.cla = 0x80;
426
0
    apdu.resp = rbuf;
427
0
    apdu.resplen = sizeof(rbuf);
428
0
    apdu.le = 256;
429
0
    r = sc_transmit_apdu(card, &apdu);
430
0
    LOG_TEST_RET(ctx, r, "APDU transmit failed");
431
0
    if (apdu.sw1==0x6A && (apdu.sw2==0x82 || apdu.sw2==0x88)) continue;
432
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
433
0
    LOG_TEST_RET(ctx, r, "List Dir failed");
434
0
    if (apdu.resplen > buflen) return SC_ERROR_BUFFER_TOO_SMALL;
435
0
    sc_log(ctx,
436
0
      "got %"SC_FORMAT_LEN_SIZE_T"u %s-FileIDs\n",
437
0
      apdu.resplen / 2, p1 == 1 ? "DF" : "EF");
438
439
0
    memcpy(buf, apdu.resp, apdu.resplen);
440
0
    buf += apdu.resplen;
441
0
    buflen -= apdu.resplen;
442
0
    count += apdu.resplen;
443
0
  }
444
0
  return count;
445
0
}
446
447
448
static int tcos_delete_file(sc_card_t *card, const sc_path_t *path)
449
0
{
450
0
  int r;
451
0
  u8 sbuf[2];
452
0
  sc_apdu_t apdu;
453
454
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
455
0
  if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
456
0
    sc_log(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
457
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
458
0
  }
459
0
  sbuf[0] = path->value[0];
460
0
  sbuf[1] = path->value[1];
461
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
462
0
  apdu.cla |= 0x80;
463
0
  apdu.lc = 2;
464
0
  apdu.datalen = 2;
465
0
  apdu.data = sbuf;
466
467
0
  r = sc_transmit_apdu(card, &apdu);
468
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
469
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
470
0
}
471
472
473
static int tcos_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num)
474
0
{
475
0
  sc_context_t *ctx;
476
0
  sc_apdu_t apdu;
477
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
478
0
  int r, default_key, tcos3;
479
0
  tcos_data *data;
480
481
0
  assert(card != NULL && env != NULL);
482
0
  ctx = card->ctx;
483
0
  tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
484
0
  data=(tcos_data *)card->drv_data;
485
486
0
  if (se_num || (env->operation!=SC_SEC_OPERATION_DECIPHER && env->operation!=SC_SEC_OPERATION_SIGN)) {
487
0
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
488
0
  }
489
0
  if(!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT))
490
0
    sc_log(ctx,
491
0
      "No Key-Reference in SecEnvironment\n");
492
0
  else
493
0
    sc_log(ctx,
494
0
      "Key-Reference %02X (len=%"SC_FORMAT_LEN_SIZE_T"u)\n",
495
0
      env->key_ref[0], env->key_ref_len);
496
  /* Key-Reference 0x80 ?? */
497
0
  default_key= !(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || (env->key_ref_len==1 && env->key_ref[0]==0x80);
498
0
  sc_log(ctx, "TCOS3:%d PKCS1 type 01:%d PKCS1 type 02: %d\n", tcos3,
499
0
      !!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01),
500
0
      !!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02));
501
502
0
  data->pad_flags = env->algorithm_flags;
503
0
  data->next_sign = default_key;
504
505
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, tcos3 ? 0x41 : 0xC1, 0xB8);
506
0
  p = sbuf;
507
0
  if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
508
0
    *p++ = (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) ? 0x83 : 0x84;
509
0
    *p++ = env->key_ref_len;
510
0
    memcpy(p, env->key_ref, env->key_ref_len);
511
0
    p += env->key_ref_len;
512
0
  }
513
0
  apdu.data = sbuf;
514
0
  apdu.lc = apdu.datalen = (p - sbuf);
515
516
0
  r=sc_transmit_apdu(card, &apdu);
517
0
  if (r) {
518
0
    sc_log(ctx,
519
0
      "%s: APDU transmit failed", sc_strerror(r));
520
0
    return r;
521
0
  }
522
0
  if (apdu.sw1==0x6A && (apdu.sw2==0x81 || apdu.sw2==0x88)) {
523
0
    sc_log(ctx,
524
0
      "Detected Signature-Only key\n");
525
0
    if (env->operation==SC_SEC_OPERATION_SIGN && default_key) return SC_SUCCESS;
526
0
  }
527
0
  SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
528
0
}
529
530
531
static int tcos_restore_security_env(sc_card_t *card, int se_num)
532
0
{
533
0
  return 0;
534
0
}
535
536
537
static int tcos_compute_signature(sc_card_t *card, const u8 * data, size_t datalen, u8 * out, size_t outlen)
538
0
{
539
0
  size_t dlen = datalen;
540
0
  sc_apdu_t apdu;
541
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
542
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
543
0
  int tcos3, r;
544
545
0
  if (card == NULL || data == NULL || out == NULL) {
546
0
    return SC_ERROR_INVALID_ARGUMENTS;
547
0
  }
548
549
0
  tcos3 = (card->type == SC_CARD_TYPE_TCOS_V3);
550
551
  // We can sign (key length / 8) bytes
552
0
  if (datalen > 256) {
553
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
554
0
  }
555
556
0
  if (((tcos_data *)card->drv_data)->next_sign) {
557
0
    if (datalen > 48) {
558
0
      sc_log(card->ctx, "Data to be signed is too long (TCOS supports max. 48 bytes)\n");
559
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
560
0
    }
561
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
562
0
    memcpy(sbuf, data, datalen);
563
0
    dlen = datalen;
564
0
  } else {
565
0
    size_t keylen = tcos3 ? 256 : 128;
566
567
0
    if (datalen > keylen) {
568
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
569
0
    }
570
571
0
    sc_format_apdu(card, &apdu, keylen > 255 ? SC_APDU_CASE_4_EXT : SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
572
0
    memset(sbuf, 0xff, sizeof(sbuf));
573
0
    sbuf[0] = 0x02;
574
0
    sbuf[1] = 0x00;
575
0
    sbuf[2] = 0x01;
576
0
    sbuf[keylen - datalen] = 0x00;
577
0
    memcpy(sbuf + keylen - datalen + 1, data, datalen);
578
0
    dlen = keylen + 1;
579
0
  }
580
0
  apdu.resp = rbuf;
581
0
  apdu.resplen = sizeof(rbuf);
582
0
  apdu.le = tcos3 ? 256 : 128;
583
0
  apdu.data = sbuf;
584
0
  apdu.lc = apdu.datalen = dlen;
585
586
0
  r = sc_transmit_apdu(card, &apdu);
587
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
588
0
  if (tcos3 && apdu.p1 == 0x80 && apdu.sw1 == 0x6A && apdu.sw2 == 0x87) {
589
0
    size_t keylen = 128;
590
591
0
    if (datalen > keylen) {
592
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
593
0
    }
594
595
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
596
0
    memset(sbuf, 0xff, sizeof(sbuf));
597
0
    sbuf[0] = 0x02;
598
0
    sbuf[1] = 0x00;
599
0
    sbuf[2] = 0x01;
600
0
    sbuf[keylen - datalen] = 0x00;
601
0
    memcpy(sbuf + keylen - datalen + 1, data, datalen);
602
0
    dlen = keylen + 1;
603
604
0
    apdu.resp = rbuf;
605
0
    apdu.resplen = sizeof(rbuf);
606
0
    apdu.le = 128;
607
0
    apdu.data = sbuf;
608
0
    apdu.lc = apdu.datalen = dlen;
609
0
    r = sc_transmit_apdu(card, &apdu);
610
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
611
0
  }
612
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
613
0
    size_t len = apdu.resplen>outlen ? outlen : apdu.resplen;
614
0
    memcpy(out, apdu.resp, len);
615
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
616
0
  }
617
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
618
0
}
619
620
621
static int tcos_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
622
0
{
623
0
  sc_context_t *ctx;
624
0
  sc_apdu_t apdu;
625
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
626
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
627
0
  tcos_data *data;
628
0
  int tcos3, r;
629
630
0
  if (card == NULL || crgram == NULL || out == NULL) {
631
0
    return SC_ERROR_INVALID_ARGUMENTS;
632
0
  }
633
0
  ctx = card->ctx;
634
0
  tcos3 = (card->type == SC_CARD_TYPE_TCOS_V3);
635
0
  data = (tcos_data *)card->drv_data;
636
637
0
  LOG_FUNC_CALLED(ctx);
638
0
  sc_log(ctx, "TCOS3:%d PKCS1 type 02:%d\n", tcos3,
639
0
      !!(data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02));
640
641
0
  sc_format_apdu(card, &apdu, crgram_len > 255 ? SC_APDU_CASE_4_EXT : SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
642
0
  apdu.resp = rbuf;
643
0
  apdu.resplen = sizeof(rbuf);
644
0
  apdu.le = crgram_len;
645
646
0
  apdu.data = sbuf;
647
0
  apdu.lc = apdu.datalen = crgram_len + 1;
648
0
  sbuf[0] = tcos3 ? 0x00 : ((data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02) ? 0x81 : 0x02);
649
0
  if (sizeof sbuf - 1 < crgram_len)
650
0
    return SC_ERROR_INVALID_ARGUMENTS;
651
0
  memcpy(sbuf + 1, crgram, crgram_len);
652
653
0
  r = sc_transmit_apdu(card, &apdu);
654
0
  LOG_TEST_RET(ctx, r, "APDU transmit failed");
655
656
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
657
0
    size_t len = (apdu.resplen > outlen) ? outlen : apdu.resplen;
658
0
    unsigned int offset = 0;
659
660
0
    if (tcos3 && (data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02)
661
0
        && len > 2 && apdu.resp[0] == 0 && apdu.resp[1] == 2) {
662
0
      offset = 2;
663
0
      while (offset < len && apdu.resp[offset] != 0)
664
0
        ++offset;
665
0
      offset = (offset < len - 1) ? offset + 1 : 0;
666
0
    }
667
0
    if (offset < len)
668
0
        memcpy(out, apdu.resp + offset, len - offset);
669
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, (int)(len - offset));
670
0
  }
671
0
  SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
672
0
}
673
674
675
/* Issue the SET PERMANENT command.  With ENABLE_NULLPIN set the
676
   NullPIN method will be activated, otherwise the permanent operation
677
   will be done on the active file. */
678
static int tcos_setperm(sc_card_t *card, int enable_nullpin)
679
0
{
680
0
  int r;
681
0
  sc_apdu_t apdu;
682
683
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
684
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xEE, 0x00, 0x00);
685
0
  apdu.cla |= 0x80;
686
0
  apdu.lc = 0;
687
0
  apdu.datalen = 0;
688
0
  apdu.data = NULL;
689
690
0
  r = sc_transmit_apdu(card, &apdu);
691
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
692
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
693
0
}
694
695
696
static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
697
0
{
698
0
  int r;
699
700
0
  if (!serial)
701
0
    return SC_ERROR_INVALID_ARGUMENTS;
702
703
  /* see if we have cached serial number */
704
0
  if (card->serialnr.len) {
705
0
    memcpy(serial, &card->serialnr, sizeof(*serial));
706
0
    return SC_SUCCESS;
707
0
  }
708
709
0
  card->serialnr.len = sizeof card->serialnr.value;
710
0
  r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0);
711
0
  if (r < 0) {
712
0
    card->serialnr.len = 0;
713
0
    return r;
714
0
  }
715
716
  /* copy and return serial number */
717
0
  memcpy(serial, &card->serialnr, sizeof(*serial));
718
719
0
  return SC_SUCCESS;
720
0
}
721
722
723
static int tcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
724
0
{
725
0
  switch (cmd) {
726
0
  case SC_CARDCTL_TCOS_SETPERM:
727
0
    return tcos_setperm(card, !!ptr);
728
0
  case SC_CARDCTL_GET_SERIALNR:
729
0
    return tcos_get_serialnr(card, (sc_serial_number_t *)ptr);
730
0
  }
731
0
  return SC_ERROR_NOT_SUPPORTED;
732
0
}
733
734
735
struct sc_card_driver * sc_get_tcos_driver(void)
736
19.4k
{
737
19.4k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
738
739
19.4k
  if (iso_ops == NULL) iso_ops = iso_drv->ops;
740
19.4k
  tcos_ops = *iso_drv->ops;
741
742
19.4k
  tcos_ops.match_card           = tcos_match_card;
743
19.4k
  tcos_ops.init                 = tcos_init;
744
19.4k
  tcos_ops.finish               = tcos_finish;
745
19.4k
  tcos_ops.create_file          = tcos_create_file;
746
19.4k
  tcos_ops.set_security_env     = tcos_set_security_env;
747
19.4k
  tcos_ops.select_file          = tcos_select_file;
748
19.4k
  tcos_ops.list_files           = tcos_list_files;
749
19.4k
  tcos_ops.delete_file          = tcos_delete_file;
750
19.4k
  tcos_ops.compute_signature    = tcos_compute_signature;
751
19.4k
  tcos_ops.decipher             = tcos_decipher;
752
19.4k
  tcos_ops.restore_security_env = tcos_restore_security_env;
753
19.4k
  tcos_ops.card_ctl             = tcos_card_ctl;
754
755
19.4k
  return &tcos_drv;
756
19.4k
}