Coverage Report

Created: 2025-08-24 06:59

/src/opensc/src/libopensc/card-atrust-acos.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * atrust-acos.c: Support for A-Trust ACOS based cards
3
 *
4
 * Copyright (C) 2005  Franz Brandl <brandl@a-trust.at> based on work from
5
 *                     Jörn Zukowski <zukowski@trustcenter.de> and
6
 *                     Nils Larsch   <larsch@trustcenter.de>, TrustCenter AG
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 <stdlib.h>
28
#include <string.h>
29
30
#include "internal.h"
31
#include "asn1.h"
32
#include "cardctl.h"
33
34
/*****************************************************************************/
35
36
#define ACOS_EMV_A03    "A-TRUST ACOS"
37
0
#define ACOS_EMV_A05    "A-TRUST ACOS A05"
38
39
static const char *atrust_acos_atrs[] = {
40
  "3B:BF:11:00:81:31:fe:45:45:50:41",
41
  "3B:BF:11:00:81:31:fe:45:4d:43:41",
42
  "3B:BF:13:00:81:31:fe:45:45:50:41",
43
  "3B:BF:13:00:81:31:fe:45:4d:43:41",
44
  NULL
45
};
46
47
/* sequence and number has to match atr table ! */
48
static const char *atrust_acos_names[] = {
49
  ACOS_EMV_A03,
50
  ACOS_EMV_A03,
51
  ACOS_EMV_A05,
52
  ACOS_EMV_A05,
53
  NULL
54
};
55
56
static struct sc_card_operations atrust_acos_ops;
57
static struct sc_card_operations *iso_ops = NULL;
58
59
static struct sc_card_driver atrust_acos_drv = {
60
  "A-Trust ACOS cards",
61
  "atrust-acos",
62
  &atrust_acos_ops,
63
  NULL, 0, NULL
64
};
65
66
/* internal structure to save the current security environment */
67
typedef struct atrust_acos_ex_data_st {
68
  int    sec_ops; /* the currently selected security operation,
69
       * i.e. SC_SEC_OPERATION_AUTHENTICATE etc. */
70
  unsigned long    fix_digestInfo;
71
} atrust_acos_ex_data;
72
73
/*****************************************************************************/
74
75
static int atrust_acos_match_card(struct sc_card *card)
76
0
{
77
0
  int   i, match = 0;
78
79
80
0
  for (i = 0; atrust_acos_atrs[i] != NULL; i++)
81
0
  {
82
0
    u8 defatr[SC_MAX_ATR_SIZE];
83
0
    size_t len = sizeof(defatr);
84
0
    const char *atrp = atrust_acos_atrs[i];
85
86
0
    if (sc_hex_to_bin(atrp, defatr, &len))
87
0
      continue;
88
    /* we may only verify part of ATR since */
89
    /* part of the hist chars is variable */
90
0
    if (len > card->atr.len)
91
0
      continue;
92
0
    if (memcmp(card->atr.value, defatr, len) != 0)
93
0
      continue;
94
95
0
    match = 1;
96
0
    card->name = atrust_acos_names[i];
97
98
0
    break;
99
0
    }
100
0
  return match;
101
0
}
102
103
/*****************************************************************************/
104
105
static int atrust_acos_init(struct sc_card *card)
106
0
{
107
0
  unsigned int flags;
108
0
  atrust_acos_ex_data *ex_data;
109
110
0
  ex_data = calloc(1, sizeof(atrust_acos_ex_data));
111
0
  if (ex_data == NULL)
112
0
    return SC_ERROR_OUT_OF_MEMORY;
113
114
0
  card->cla  = 0x00;
115
0
  card->drv_data = (void *)ex_data;
116
117
  /* set the supported algorithm */
118
119
0
  flags = SC_ALGORITHM_RSA_PAD_PKCS1
120
0
    | SC_ALGORITHM_RSA_HASH_NONE
121
0
    | SC_ALGORITHM_RSA_HASH_SHA1
122
0
    | SC_ALGORITHM_RSA_HASH_MD5
123
0
    | SC_ALGORITHM_RSA_HASH_RIPEMD160
124
0
    | SC_ALGORITHM_RSA_HASH_MD5_SHA1;
125
126
0
  if (card->name != NULL && !strcmp(card->name, ACOS_EMV_A05))
127
0
    flags |= SC_ALGORITHM_RSA_HASH_SHA256;
128
129
0
  _sc_card_add_rsa_alg(card, 1536, flags, 0x10001);
130
131
  /* we need read_binary&friends with max 128 bytes per read */
132
0
  card->max_send_size = 128;
133
0
  card->max_recv_size = 128;
134
135
0
  return 0;
136
0
}
137
138
/*****************************************************************************/
139
140
static int atrust_acos_finish(struct sc_card *card)
141
0
{
142
0
  if (card->drv_data)
143
0
    free((atrust_acos_ex_data *)card->drv_data);
144
0
  return 0;
145
0
}
146
147
/*****************************************************************************/
148
149
static int process_fci(struct sc_context *ctx, struct sc_file *file,
150
           const u8 *buf, size_t buflen)
151
0
{
152
153
0
  size_t taglen, len = buflen;
154
0
  const u8 *tag = NULL, *p;
155
156
0
  sc_log(ctx,  "processing FCI bytes\n");
157
158
0
  if (buflen < 2)
159
0
    return SC_ERROR_INTERNAL;
160
0
  if (buf[0] != 0x6f)         /* FCI template */
161
0
    return SC_ERROR_INVALID_DATA;
162
0
  len = (size_t)buf[1];
163
0
  if (buflen - 2 < len)
164
0
    return SC_ERROR_INVALID_DATA;
165
0
  p = buf + 2;
166
167
  /* defaults */
168
0
  file->type = SC_FILE_TYPE_WORKING_EF;
169
0
  file->ef_structure = SC_FILE_EF_UNKNOWN;
170
0
  file->shareable = 0;
171
0
  file->record_length = 0;
172
0
  file->size = 0;
173
174
  /* get file size */
175
0
  tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
176
0
  if (tag != NULL && taglen >= 2) {
177
0
    int bytes = (tag[0] << 8) + tag[1];
178
0
    sc_log(ctx,  "  bytes in file: %d\n", bytes);
179
0
    file->size = bytes;
180
0
  }
181
182
  /* get file type */
183
0
    tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
184
0
  if (tag != NULL) {
185
0
    const char *type = "unknown";
186
0
    const char *structure = "unknown";
187
188
0
    if (taglen == 1 && tag[0] == 0x01) {
189
      /* transparent EF */
190
0
      type = "working EF";
191
0
      structure = "transparent";
192
0
      file->type = SC_FILE_TYPE_WORKING_EF;
193
0
      file->ef_structure = SC_FILE_EF_TRANSPARENT;
194
0
    } else if (taglen == 1 && tag[0] == 0x11) {
195
      /* object EF */
196
0
      type = "working EF";
197
0
      structure = "object";
198
0
      file->type = SC_FILE_TYPE_WORKING_EF;
199
0
      file->ef_structure = SC_FILE_EF_TRANSPARENT; /* TODO */
200
0
    } else if (taglen == 3 && tag[1] == 0x21) {
201
0
      type = "working EF";
202
0
      file->record_length = tag[2];
203
0
      file->type = SC_FILE_TYPE_WORKING_EF;
204
      /* linear fixed, cyclic or compute */
205
0
      switch ( tag[0] )
206
0
      {
207
0
        case 0x02:
208
0
          structure = "linear fixed";
209
0
          file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
210
0
          break;
211
0
        case 0x07:
212
0
          structure = "cyclic";
213
0
          file->ef_structure = SC_FILE_EF_CYCLIC;
214
0
          break;
215
0
        case 0x17:
216
0
          structure = "compute";
217
0
          file->ef_structure = SC_FILE_EF_UNKNOWN;
218
0
          break;
219
0
        default:
220
0
          structure = "unknown";
221
0
          file->ef_structure = SC_FILE_EF_UNKNOWN;
222
0
          file->record_length = 0;
223
0
          break;
224
0
      }
225
0
    }
226
227
0
    sc_log(ctx,  "  type: %s\n", type);
228
0
    sc_log(ctx,  "  EF structure: %s\n", structure);
229
0
  }
230
0
  file->magic = SC_FILE_MAGIC;
231
232
0
  return SC_SUCCESS;
233
0
}
234
235
/*****************************************************************************/
236
237
static int atrust_acos_select_aid(struct sc_card *card,
238
            u8 aid[16], size_t len,
239
            struct sc_file **file_out)
240
0
{
241
0
  sc_apdu_t apdu;
242
0
  int r;
243
0
  size_t i = 0;
244
245
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
246
0
  apdu.lc = len;
247
0
  apdu.data = (u8*)aid;
248
0
  apdu.datalen = len;
249
0
  apdu.resplen = 0;
250
0
  apdu.le = 0;
251
0
  r = sc_transmit_apdu(card, &apdu);
252
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
253
254
  /* check return value */
255
0
  if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61)
256
0
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
257
258
0
  if (file_out) {
259
0
    sc_file_t *file = sc_file_new();
260
0
    if (!file)
261
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
262
0
    file->type = SC_FILE_TYPE_DF;
263
0
    file->ef_structure = SC_FILE_EF_UNKNOWN;
264
0
    file->path.len = 0;
265
0
    file->size = 0;
266
    /* AID */
267
0
    for (i = 0; i < len; i++)
268
0
      file->name[i] = aid[i];
269
0
    file->namelen = len;
270
0
    file->id = 0x0000;
271
0
    file->magic = SC_FILE_MAGIC;
272
0
    *file_out = file;
273
0
  }
274
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
275
0
}
276
277
/*****************************************************************************/
278
279
static int atrust_acos_select_fid(struct sc_card *card,
280
            unsigned int id_hi, unsigned int id_lo,
281
            struct sc_file **file_out)
282
0
{
283
0
  sc_apdu_t apdu;
284
0
  u8 data[] = {id_hi & 0xff, id_lo & 0xff};
285
0
  u8 resp[SC_MAX_APDU_BUFFER_SIZE];
286
0
  int bIsDF = 0, r;
287
288
  /* request FCI to distinguish between EFs and DFs */
289
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00);
290
0
  apdu.resp = (u8*)resp;
291
0
  apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
292
0
  apdu.le = 256;
293
0
  apdu.lc = 2;
294
0
  apdu.data = (u8*)data;
295
0
  apdu.datalen = 2;
296
297
0
  r = sc_transmit_apdu(card, &apdu);
298
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
299
300
0
  if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) {
301
    /* no FCI => we have a DF (see comment in process_fci()) */
302
0
    bIsDF = 1;
303
0
    apdu.p2 = 0x0C;
304
0
    apdu.cse = SC_APDU_CASE_3_SHORT;
305
0
    apdu.resplen = 0;
306
0
    apdu.le = 0;
307
0
    r = sc_transmit_apdu(card, &apdu);
308
0
    LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
309
0
      } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)) {
310
    /* SELECT returned some data (possible FCI) =>
311
     * try a READ BINARY to see if a EF is selected */
312
0
    sc_apdu_t apdu2;
313
0
    u8 resp2[2];
314
0
    sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0);
315
0
    apdu2.resp = (u8*)resp2;
316
0
    apdu2.resplen = 2;
317
0
    apdu2.le = 1;
318
0
    apdu2.lc = 0;
319
0
    r = sc_transmit_apdu(card, &apdu2);
320
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
321
0
    if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86)
322
      /* no current EF is selected => we have a DF */
323
0
      bIsDF = 1;
324
0
  }
325
326
0
  if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00))
327
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
328
329
0
  if (file_out) {
330
0
    sc_file_t *file = sc_file_new();
331
0
    if (!file)
332
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
333
0
    file->id = (id_hi << 8) + id_lo;
334
335
0
    if (bIsDF) {
336
      /* we have a DF */
337
0
      file->type = SC_FILE_TYPE_DF;
338
0
      file->ef_structure = SC_FILE_EF_UNKNOWN;
339
0
      file->size = 0;
340
0
      file->namelen = 0;
341
0
      file->magic = SC_FILE_MAGIC;
342
0
      *file_out = file;
343
0
    } else {
344
      /* ok, assume we have a EF */
345
0
      r = process_fci(card->ctx, file, apdu.resp,
346
0
          apdu.resplen);
347
0
      if (r != SC_SUCCESS) {
348
0
        sc_file_free(file);
349
0
        return r;
350
0
      }
351
352
0
      *file_out = file;
353
0
    }
354
0
  }
355
356
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
357
0
}
358
359
/*****************************************************************************/
360
361
static int atrust_acos_select_file(struct sc_card *card,
362
             const struct sc_path *in_path,
363
             struct sc_file **file_out)
364
0
{
365
0
  u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
366
0
  int    r;
367
0
  size_t i, pathlen;
368
369
0
  memcpy(path, in_path->value, in_path->len);
370
0
  pathlen = in_path->len;
371
372
0
  if (in_path->type == SC_PATH_TYPE_FILE_ID) {
373
    /* SELECT EF/DF with ID */
374
    /* Select with 2byte File-ID */
375
0
    if (pathlen != 2)
376
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
377
0
    return atrust_acos_select_fid(card, path[0], path[1], file_out);
378
0
  } else if (in_path->type == SC_PATH_TYPE_DF_NAME) {
379
    /* SELECT DF with AID */
380
    /* Select with 1-16byte Application-ID */
381
0
    return atrust_acos_select_aid(card, pathbuf, pathlen, file_out);
382
0
  } else if (in_path->type == SC_PATH_TYPE_PATH) {
383
0
    u8 n_pathbuf[SC_MAX_PATH_SIZE];
384
385
    /* Select with path (sequence of File-IDs) */
386
    /* ACOS only supports one
387
     * level of subdirectories, therefore a path is
388
     * at most 3 FID long (the last one being the FID
389
     * of a EF) => pathlen must be even and less than 6
390
     */
391
0
    if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
392
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
393
    /* if pathlen == 6 then the first FID must be MF (== 3F00) */
394
0
    if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
395
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
396
397
    /* unify path (the first FID should be MF) */
398
0
    if (path[0] != 0x3f || path[1] != 0x00)
399
0
    {
400
0
      n_pathbuf[0] = 0x3f;
401
0
      n_pathbuf[1] = 0x00;
402
0
      memcpy(n_pathbuf+2, path, pathlen);
403
0
      path = n_pathbuf;
404
0
      pathlen += 2;
405
0
    }
406
407
0
    for (i = 0; i < pathlen - 2; i += 2) {
408
0
      r = atrust_acos_select_fid(card, path[i], path[i + 1], NULL);
409
0
      LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
410
0
    }
411
0
    return atrust_acos_select_fid(card, path[pathlen - 2], path[pathlen - 1], file_out);
412
0
  } else
413
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
414
0
}
415
416
/** atrust_acos_set_security_env
417
 * sets the security environment
418
 * \param card pointer to the sc_card object
419
 * \param env pointer to a sc_security_env object
420
 * \param se_num not used here
421
 * \return SC_SUCCESS on success or an error code
422
 *
423
 * This function sets the security environment (using the
424
 * command MANAGE SECURITY ENVIRONMENT). In case a COMPUTE SIGNATURE
425
 * operation is requested , this function tries to detect whether
426
 * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE must be used for signature
427
 * calculation.
428
 */
429
static int atrust_acos_set_security_env(struct sc_card *card,
430
            const struct sc_security_env *env,
431
            int se_num)
432
0
{
433
0
  u8              *p, *pp;
434
0
  int              r, operation = env->operation;
435
0
  struct sc_apdu   apdu;
436
0
  u8               sbuf[SC_MAX_APDU_BUFFER_SIZE];
437
0
  atrust_acos_ex_data *ex_data = (atrust_acos_ex_data *)card->drv_data;
438
439
0
  p     = sbuf;
440
441
  /* copy key reference, if present */
442
0
  if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
443
0
    if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC)
444
0
      *p++ = 0x83;
445
0
    else
446
0
      *p++ = 0x84;
447
0
    *p++ = env->key_ref_len;
448
0
    memcpy(p, env->key_ref, env->key_ref_len);
449
0
    p += env->key_ref_len;
450
0
  }
451
0
  pp = p;
452
0
  if (operation == SC_SEC_OPERATION_DECIPHER){
453
0
    if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02) {
454
0
      *p++ = 0x80;
455
0
      *p++ = 0x01;
456
0
      *p++ = 0x02;
457
0
    } else
458
0
      return SC_ERROR_INVALID_ARGUMENTS;
459
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81,
460
0
                   0xb8);
461
0
    apdu.data    = sbuf;
462
0
    apdu.datalen = p - sbuf;
463
0
    apdu.lc      = p - sbuf;
464
0
    apdu.le      = 0;
465
0
    r = sc_transmit_apdu(card, &apdu);
466
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
467
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
468
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
469
0
    return SC_SUCCESS;
470
0
  }
471
  /* try COMPUTE SIGNATURE */
472
0
  if (operation == SC_SEC_OPERATION_SIGN && (
473
0
      env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01 ||
474
0
      env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796)) {
475
0
    if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
476
0
      *p++ = 0x80;
477
0
      *p++ = 0x01;
478
0
      *p++ = env->algorithm_ref & 0xFF;
479
0
    } else if (env->flags & SC_SEC_ENV_ALG_PRESENT &&
480
0
                env->algorithm == SC_ALGORITHM_RSA) {
481
      /* set the method to use based on the algorithm_flags */
482
0
      *p++ = 0x80;
483
0
      *p++ = 0x01;
484
0
      if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01) {
485
0
        if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
486
0
          *p++ = 0x12;
487
0
        else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160)
488
0
          *p++ = 0x22;
489
0
        else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
490
0
          *p++ = 0x32;
491
0
        else {
492
          /* can't use COMPUTE SIGNATURE =>
493
           * try INTERNAL AUTHENTICATE */
494
0
          p = pp;
495
0
          operation = SC_SEC_OPERATION_AUTHENTICATE;
496
0
          goto try_authenticate;
497
0
        }
498
0
      } else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796) {
499
0
        if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
500
0
          *p++ = 0x11;
501
0
        else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160)
502
0
          *p++ = 0x21;
503
0
        else
504
0
          return SC_ERROR_INVALID_ARGUMENTS;
505
0
      } else
506
0
        return SC_ERROR_INVALID_ARGUMENTS;
507
0
    }
508
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xb6);
509
0
    apdu.data    = sbuf;
510
0
    apdu.datalen = p - sbuf;
511
0
    apdu.lc      = p - sbuf;
512
0
    apdu.le      = 0;
513
    /* we don't know whether to use
514
     * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE */
515
0
    r = sc_transmit_apdu(card, &apdu);
516
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
517
0
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
518
0
      ex_data->fix_digestInfo = 0;
519
0
      ex_data->sec_ops        = SC_SEC_OPERATION_SIGN;
520
0
      return SC_SUCCESS;
521
0
    }
522
    /* reset pointer */
523
0
    p = pp;
524
    /* doesn't work => try next op */
525
0
    operation = SC_SEC_OPERATION_AUTHENTICATE;
526
0
  }
527
0
try_authenticate:
528
  /* try INTERNAL AUTHENTICATE */
529
0
  if (operation == SC_SEC_OPERATION_AUTHENTICATE &&
530
0
      env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
531
0
    *p++ = 0x80;
532
0
    *p++ = 0x01;
533
0
    *p++ = 0x01;
534
535
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xa4);
536
0
    apdu.data    = sbuf;
537
0
    apdu.datalen = p - sbuf;
538
0
    apdu.lc      = p - sbuf;
539
0
    apdu.le      = 0;
540
0
    r = sc_transmit_apdu(card, &apdu);
541
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
542
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
543
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
544
0
    ex_data->fix_digestInfo = env->algorithm_flags;
545
0
    ex_data->sec_ops        = SC_SEC_OPERATION_AUTHENTICATE;
546
0
    return SC_SUCCESS;
547
0
  }
548
549
0
  return SC_ERROR_INVALID_ARGUMENTS;
550
0
}
551
552
/*****************************************************************************/
553
554
static int atrust_acos_compute_signature(struct sc_card *card,
555
             const u8 * data, size_t datalen,
556
             u8 * out, size_t outlen)
557
0
{
558
0
  int r;
559
0
  struct sc_apdu apdu;
560
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
561
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
562
0
  atrust_acos_ex_data *ex_data = (atrust_acos_ex_data *)card->drv_data;
563
564
0
  if (datalen > SC_MAX_APDU_BUFFER_SIZE)
565
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
566
567
0
  if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) {
568
    /* compute signature with the COMPUTE SIGNATURE command */
569
570
    /* set the hash value     */
571
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A,
572
0
             0x90, 0x81);
573
0
    apdu.resp = rbuf;
574
0
    apdu.resplen = sizeof(rbuf);
575
0
    apdu.le = 0;
576
0
    memcpy(sbuf, data, datalen);
577
0
    apdu.data = sbuf;
578
0
    apdu.lc = datalen;
579
0
    apdu.datalen = datalen;
580
0
    r = sc_transmit_apdu(card, &apdu);
581
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
582
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
583
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,
584
0
               sc_check_sw(card, apdu.sw1, apdu.sw2));
585
586
    /* call COMPUTE SIGNATURE */
587
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A,
588
0
             0x9E, 0x9A);
589
0
    apdu.resp = rbuf;
590
0
    apdu.resplen = sizeof(rbuf);
591
0
    apdu.le = 256;
592
593
0
    apdu.lc = 0;
594
0
    apdu.datalen = 0;
595
0
    r = sc_transmit_apdu(card, &apdu);
596
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
597
0
    if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
598
0
      size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
599
0
      memcpy(out, apdu.resp, len);
600
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
601
0
    }
602
0
  } else if (ex_data->sec_ops == SC_SEC_OPERATION_AUTHENTICATE) {
603
0
    size_t tmp_len;
604
    /* call INTERNAL AUTHENTICATE */
605
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x10, 0x00);
606
    /* fix/create DigestInfo structure (if necessary) */
607
0
    if (ex_data->fix_digestInfo) {
608
0
      unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES;
609
0
      if (flags == 0x0)
610
        /* XXX: assume no hash is wanted */
611
0
        flags = SC_ALGORITHM_RSA_HASH_NONE;
612
0
      tmp_len = sizeof(sbuf);
613
0
      r = sc_pkcs1_encode(card->ctx, flags, data, datalen,
614
0
          sbuf, &tmp_len, sizeof(sbuf)*8, NULL);
615
0
      if (r < 0)
616
0
        return r;
617
0
    } else {
618
0
      memcpy(sbuf, data, datalen);
619
0
      tmp_len = datalen;
620
0
    }
621
0
    apdu.lc = tmp_len;
622
0
    apdu.data = sbuf;
623
0
    apdu.datalen = tmp_len;
624
0
    apdu.resp = rbuf;
625
0
    apdu.resplen = sizeof(rbuf);
626
0
    apdu.le = 256;
627
0
    r = sc_transmit_apdu(card, &apdu);
628
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
629
0
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
630
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
631
0
    {
632
0
      size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
633
634
0
      memcpy(out, apdu.resp, len);
635
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
636
0
    }
637
0
  } else
638
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
639
640
  /* clear old state */
641
0
  ex_data->sec_ops = 0;
642
0
  ex_data->fix_digestInfo = 0;
643
644
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
645
0
}
646
647
/*****************************************************************************/
648
649
static int atrust_acos_decipher(struct sc_card *card,
650
          const u8 * crgram, size_t crgram_len,
651
          u8 * out, size_t outlen)
652
0
{
653
0
  int r;
654
0
  struct sc_apdu apdu;
655
0
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
656
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
657
658
0
  assert(card != NULL && crgram != NULL && out != NULL);
659
0
  LOG_FUNC_CALLED(card->ctx);
660
0
  if (crgram_len > 255)
661
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
662
663
  /* INS: 0x2A  PERFORM SECURITY OPERATION
664
   * P1:  0x80  Resp: Plain value
665
   * P2:  0x86  Cmd: Padding indicator byte followed by cryptogram */
666
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
667
0
  apdu.resp = rbuf;
668
0
  apdu.resplen = sizeof(rbuf);
669
670
0
  sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
671
0
  memcpy(sbuf + 1, crgram, crgram_len);
672
0
  apdu.data = sbuf;
673
0
  apdu.lc = crgram_len + 1;
674
0
  apdu.datalen = crgram_len + 1;
675
0
  apdu.le = 256;
676
0
  r = sc_transmit_apdu(card, &apdu);
677
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
678
0
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
679
0
    size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
680
681
0
    memcpy(out, apdu.resp, len);
682
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, (int)len);
683
0
  }
684
685
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
686
0
}
687
688
/*****************************************************************************/
689
690
static int atrust_acos_check_sw(struct sc_card *card, unsigned int sw1,
691
  unsigned int sw2)
692
0
{
693
694
0
  sc_log(card->ctx,  "sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
695
696
0
  if (sw1 == 0x90 && sw2 == 0x00)
697
0
    return SC_SUCCESS;
698
0
  if (sw1 == 0x63 && (sw2 & ~0x0fU) == 0xc0 )
699
0
  {
700
0
    sc_log(card->ctx,  "Verification failed (remaining tries: %d)\n",
701
0
    (sw2 & 0x0f));
702
0
    return SC_ERROR_PIN_CODE_INCORRECT;
703
0
  }
704
705
  /* iso error */
706
0
  return iso_ops->check_sw(card, sw1, sw2);
707
0
}
708
709
/*****************************************************************************/
710
711
static int acos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
712
0
{
713
0
  int r;
714
0
  u8  rbuf[SC_MAX_APDU_BUFFER_SIZE];
715
0
  sc_apdu_t apdu;
716
717
0
  if (!serial)
718
0
    return SC_ERROR_INVALID_ARGUMENTS;
719
  /* see if we have cached serial number */
720
0
  if (card->serialnr.len) {
721
0
    memcpy(serial, &card->serialnr, sizeof(*serial));
722
0
    return SC_SUCCESS;
723
0
  }
724
  /* get serial number via GET CARD DATA */
725
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00);
726
0
  apdu.cla |= 0x80;
727
0
  apdu.resp = rbuf;
728
0
  apdu.resplen = sizeof(rbuf);
729
0
  apdu.le   = 256;
730
0
  apdu.lc   = 0;
731
0
  apdu.datalen = 0;
732
0
        r = sc_transmit_apdu(card, &apdu);
733
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
734
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
735
0
    return SC_ERROR_INTERNAL;
736
  /* cache serial number */
737
0
  memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR));
738
0
  card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR);
739
  /* copy and return serial number */
740
0
  memcpy(serial, &card->serialnr, sizeof(*serial));
741
0
  return SC_SUCCESS;
742
0
}
743
744
/*****************************************************************************/
745
746
static int atrust_acos_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
747
0
{
748
749
0
  switch (cmd)
750
0
  {
751
0
  case SC_CARDCTL_GET_SERIALNR:
752
0
    return acos_get_serialnr(card, (sc_serial_number_t *)ptr);
753
0
  default:
754
0
    return SC_ERROR_NOT_SUPPORTED;
755
0
  }
756
0
}
757
758
/*****************************************************************************/
759
760
static int atrust_acos_logout(struct sc_card *card)
761
0
{
762
0
  int r;
763
0
  struct sc_apdu apdu;
764
0
  const u8 mf_buf[2] = {0x3f, 0x00};
765
766
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
767
0
  apdu.le = 0;
768
0
  apdu.lc = 2;
769
0
  apdu.data    = mf_buf;
770
0
  apdu.datalen = 2;
771
0
  apdu.resplen = 0;
772
773
0
  r = sc_transmit_apdu(card, &apdu);
774
0
  LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
775
776
0
  if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85)
777
    /* the only possible reason for this error here is, afaik,
778
     * that no MF exists, but then there's no need to logout
779
     * => return SC_SUCCESS
780
     */
781
0
    return SC_SUCCESS;
782
0
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
783
0
}
784
785
/*****************************************************************************/
786
787
static struct sc_card_driver * sc_get_driver(void)
788
0
{
789
0
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
790
0
  if (iso_ops == NULL)
791
0
    iso_ops = iso_drv->ops;
792
793
0
  atrust_acos_ops = *iso_drv->ops;
794
0
  atrust_acos_ops.match_card = atrust_acos_match_card;
795
0
  atrust_acos_ops.init   = atrust_acos_init;
796
0
  atrust_acos_ops.finish = atrust_acos_finish;
797
0
  atrust_acos_ops.select_file = atrust_acos_select_file;
798
0
  atrust_acos_ops.check_sw    = atrust_acos_check_sw;
799
0
  atrust_acos_ops.create_file = NULL;
800
0
  atrust_acos_ops.delete_file = NULL;
801
0
  atrust_acos_ops.set_security_env  = atrust_acos_set_security_env;
802
0
  atrust_acos_ops.compute_signature = atrust_acos_compute_signature;
803
0
  atrust_acos_ops.decipher    = atrust_acos_decipher;
804
0
  atrust_acos_ops.card_ctl    = atrust_acos_card_ctl;
805
0
  atrust_acos_ops.logout      = atrust_acos_logout;
806
807
0
  return &atrust_acos_drv;
808
0
}
809
810
/*****************************************************************************/
811
812
struct sc_card_driver * sc_get_atrust_acos_driver(void)
813
0
{
814
0
  return sc_get_driver();
815
0
}